kchan.go 4.0 KB

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