safe_chan.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. // package safe_chan -- умный безопасный канал
  2. package safe_chan
  3. import (
  4. "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/def_err"
  5. "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/def_spec_base"
  6. "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/safe_bool"
  7. "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/safe_mutex"
  8. "gitp78su.ipnodns.ru/svi/kern/v4/d0/defs/table/owner"
  9. "gitp78su.ipnodns.ru/svi/kern/v4/d0/helpers"
  10. "gitp78su.ipnodns.ru/svi/kern/v4/d0/result"
  11. )
  12. // SafeChanParam -- параметры умного безопасного канала.
  13. type SafeChanParam[T any] struct {
  14. Limit_ def_spec_base.Num // лимит на размер канала, не может быть пустым
  15. OnWrite_ func(T) // Обратный вызов при записи в канал
  16. OnRead_ func(T) // Обратный вызов при чтении из канала
  17. OnClose_ func() // Обратный вызов при закрытии канала
  18. OnLimit_ func() // Обратный вызов при достижении лимита
  19. Owner_ *owner.LOwner // Владелец канала
  20. }
  21. // SelfCheck -- проверка корректности правильности параметров умного канала.
  22. func (sf *SafeChanParam[T]) SelfCheck() {
  23. helpers.If(sf.Limit_ <= 0).
  24. Hassert("SafeChanParam[T].SelfCheck(): limit=%v, канал должен иметь положительный лимит",
  25. sf.Limit_)
  26. helpers.If(sf.Owner_ == nil).Hassert("SafeChanParam[T].SelfCheck(): Owner_==nil")
  27. }
  28. // SafeChan -- умный безопасный канал
  29. //
  30. // Канал является резиновым, но лимит можно поставить сверху.
  31. // При необходимости лимит ёмкости можно поднять, но не снизить.
  32. // Умный канал можно безопасно закрывать многократно.
  33. // Умный канал можно использовать неблокирующим способом.
  34. // Умный канал точно знает своё состояние (длина, закрыт и т.п.)
  35. // При передаче инстанса канала -- из него можно только читать.
  36. // Умный канал строго типизирован и его тип видно из сигнатуры.
  37. // Кроме того, можно повесить хуки на события записи, чтения и закрытия
  38. // (например, для целей валидации).
  39. type SafeChan[T any] struct {
  40. *SafeChanParam[T]
  41. block *safe_mutex.MSafeMutex
  42. isClosed *safe_bool.MSafeBool
  43. lstMsg []T
  44. }
  45. var msg2 = def_spec_base.Txt("NewKChan: param==nil")
  46. // MutSafeChan -- создаёт новый безопасный умный канал.
  47. func MutSafeChan[T any](param *SafeChanParam[T]) *SafeChan[T] {
  48. helpers.If(param == nil).Hassert(msg2)
  49. param.SelfCheck()
  50. sf := &SafeChan[T]{
  51. SafeChanParam: param,
  52. block: safe_mutex.MutSafeMutex(),
  53. isClosed: safe_bool.MutSafeBool(param.Owner_, true),
  54. }
  55. return sf
  56. }
  57. // Read -- возвращает первый элемент очереди (если есть).
  58. func (sf *SafeChan[T]) Read(owner *owner.LOwner) *result.Result[T] {
  59. sf.block.Lock()
  60. defer sf.block.Unlock()
  61. isDest := sf.Owner_.Pass().Owner().Id() != owner.Id()
  62. helpers.If(!isDest).Hassert("SafeChan[T].Read(): ownerDest(%v)!=ownerRead(%v)",
  63. sf.Owner_.Name(), owner.Name())
  64. if len(sf.lstMsg) == 0 {
  65. err := def_err.LetErr(sf.Owner_, "KChan[T].Read(): empty list msg")
  66. return result.ResErr[T](err)
  67. }
  68. msg := sf.lstMsg[0]
  69. sf.lstMsg = sf.lstMsg[1:]
  70. return result.ResOk(msg)
  71. }
  72. // Limit -- ограничение размера канала.
  73. func (sf *SafeChan[T]) Limit() def_spec_base.Num {
  74. sf.block.RLock()
  75. defer sf.block.RUnlock()
  76. return def_spec_base.Num(len(sf.lstMsg))
  77. }
  78. // Len -- возвращает количество элементов в канале.
  79. func (sf *SafeChan[T]) Len() def_spec_base.Num {
  80. sf.block.RLock()
  81. defer sf.block.RUnlock()
  82. return def_spec_base.Num(len(sf.lstMsg))
  83. }
  84. // IsClosed -- возвращает признак закрытия канала.
  85. func (sf *SafeChan[T]) IsClosed() def_spec_base.Bool {
  86. return sf.isClosed.IsOk()
  87. }
  88. // Close -- закрывает канал.
  89. func (sf *SafeChan[T]) Close() {
  90. sf.block.Lock()
  91. defer sf.block.Unlock()
  92. sf.isClosed.Set()
  93. }