iterable.go 1.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package iter
  2. import (
  3. "sync"
  4. "github.com/anacrolix/missinggo/v2"
  5. )
  6. type Iterable interface {
  7. Iter(Callback)
  8. }
  9. type iterator struct {
  10. it Iterable
  11. ch chan interface{}
  12. value interface{}
  13. ok bool
  14. mu sync.Mutex
  15. stopped missinggo.Event
  16. }
  17. func NewIterator(it Iterable) (ret *iterator) {
  18. ret = &iterator{
  19. it: it,
  20. ch: make(chan interface{}),
  21. }
  22. go func() {
  23. // Have to do this in a goroutine, because the interface is synchronous.
  24. it.Iter(func(value interface{}) bool {
  25. select {
  26. case ret.ch <- value:
  27. return true
  28. case <-ret.stopped.LockedChan(&ret.mu):
  29. return false
  30. }
  31. })
  32. close(ret.ch)
  33. ret.mu.Lock()
  34. ret.stopped.Set()
  35. ret.mu.Unlock()
  36. }()
  37. return
  38. }
  39. func (me *iterator) Value() interface{} {
  40. if !me.ok {
  41. panic("no value")
  42. }
  43. return me.value
  44. }
  45. func (me *iterator) Next() bool {
  46. me.value, me.ok = <-me.ch
  47. return me.ok
  48. }
  49. func (me *iterator) Stop() {
  50. me.mu.Lock()
  51. me.stopped.Set()
  52. me.mu.Unlock()
  53. }
  54. func IterableAsSlice(it Iterable) (ret []interface{}) {
  55. it.Iter(func(value interface{}) bool {
  56. ret = append(ret, value)
  57. return true
  58. })
  59. return
  60. }