kchan.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. // package kchan -- умный потокобезопасный канал
  2. package kchan
  3. import (
  4. "sync"
  5. "gitp78su.ipnodns.ru/svi/kern/v4/lev0"
  6. "gitp78su.ipnodns.ru/svi/kern/v4/lev0/defs"
  7. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/comp_spec"
  8. "gitp78su.ipnodns.ru/svi/kern/v4/lev1/safe_bool"
  9. )
  10. var (
  11. If = lev0.If
  12. )
  13. // KChanParam -- параметры умного канала.
  14. type KChanParam[T any] struct {
  15. Limit_ lev0.Int // лимит на размер канала, не может быть пустым
  16. OnWrite_ func(T) // Обратный вызов при записи в канал
  17. OnRead_ func(T) // Обратный вызов при чтении из канала
  18. OnClose_ func() // Обратный вызов при закрытии канала
  19. OnLimit_ func() // Обратный вызов при достижении лимита
  20. Ctx_ comp_spec.ILocalCtx // Локальный контекст для контроля создателя
  21. }
  22. var msg1 = lev0.ATxt("KChanParam[T]: ctx==nil")
  23. // SelfCheck -- проверка корректности правильности параметров умного канала.
  24. func (sf *KChanParam[T]) SelfCheck() {
  25. If(sf.Limit_ <= 0).Hassert("KChanParam[T].SelfCheck(): limit=%v, канал должен иметь положительный лимит",
  26. sf.Limit_)
  27. If(sf.Ctx_ == nil).Hassert(msg1)
  28. }
  29. // KChan -- умный потокобезопасный канал
  30. //
  31. // Канал является резиновым, но лимит можно поставить сверху.
  32. // При необходимости лимит ёмкости можно поднять, но не снизить.
  33. // Умный канал можно безопасно закрывать многократно.
  34. // Умный канал можно использовать неблокирующим способом.
  35. // Умный канал точно знает своё состояние (длина, закрыт и т.п.)
  36. // При передаче инстанса канала -- из него можно только читать.
  37. // Умный канал строго типизирован и его тип видно из сигнатуры.
  38. // Кроме того, можно повесить хуки на события записи, чтения и закрытия
  39. // (например, для целей валидации).
  40. type KChan[T any] struct {
  41. *KChanParam[T]
  42. block sync.RWMutex
  43. isClosed lev0.ISafeBool
  44. lstMsg []T
  45. }
  46. var msg2 = lev0.ATxt("NewKChan: param==nil")
  47. // NewKChan -- создаёт новый безопасный умный канал.
  48. func NewKChan[T any](param *KChanParam[T]) lev0.IChan[T] {
  49. If(param == nil).Hassert(msg2)
  50. param.SelfCheck()
  51. sf := &KChan[T]{
  52. KChanParam: param,
  53. isClosed: safe_bool.NewSafeBool(true),
  54. }
  55. go sf.close()
  56. return sf
  57. }
  58. // Read -- возвращает первый элемент очереди (если есть).
  59. func (sf *KChan[T]) Read() *lev0.Result[T] {
  60. sf.block.Lock()
  61. defer sf.block.Unlock()
  62. if len(sf.lstMsg) == 0 {
  63. err := lev0.LetErr("KChan[T].Read(): empty list msg")
  64. return lev0.ResErr[T](err)
  65. }
  66. msg := sf.lstMsg[0]
  67. sf.lstMsg = sf.lstMsg[1:]
  68. return lev0.ResOk(msg)
  69. }
  70. // Limit -- ограничение размера канала.
  71. func (sf *KChan[T]) Limit() defs.Int {
  72. sf.block.RLock()
  73. defer sf.block.RUnlock()
  74. return defs.Int(len(sf.lstMsg))
  75. }
  76. // Len -- возвращает количество элементов в канале.
  77. func (sf *KChan[T]) Len() defs.Int {
  78. sf.block.RLock()
  79. defer sf.block.RUnlock()
  80. return defs.Int(len(sf.lstMsg))
  81. }
  82. // IsClosed -- возвращает признак закрытия канала.
  83. func (sf *KChan[T]) IsClosed() defs.Bool {
  84. return sf.isClosed.Get()
  85. }
  86. // Close -- закрывает канал.
  87. func (sf *KChan[T]) Close() {
  88. sf.block.Lock()
  89. defer sf.block.Unlock()
  90. sf.isClosed.Set()
  91. }
  92. // Ожидает закрытия канала по контексту.
  93. func (sf *KChan[T]) close() {
  94. sf.Ctx_.Wait()
  95. sf.isClosed.Set()
  96. }