kchan.go 3.9 KB

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