github.com/influx6/npkg@v0.8.8/nthen/nthen.go (about) 1 package nthen 2 3 type Future struct { 4 err error 5 val interface{} 6 resolved chan interface{} 7 } 8 9 func NewFuture() *Future { 10 return &Future{ 11 resolved: make(chan interface{}, 0), 12 } 13 } 14 15 func Fn(fn func(ft *Future)) *Future { 16 var ft = NewFuture() 17 go fn(ft) 18 return ft 19 } 20 21 func From(fn func() (interface{}, error)) *Future { 22 var ft = NewFuture() 23 go func() { 24 var val, err = fn() 25 if err != nil { 26 ft.WithError(err) 27 return 28 } 29 ft.WithValue(val) 30 }() 31 return ft 32 } 33 34 35 // CollectFor collects all resolved results (value or error) 36 // as a list which is used to resolve the returned future. 37 func CollectFor(fts ...*Future) *Future { 38 var ft = NewFuture() 39 go func(targets []*Future) { 40 var results = make([]interface{}, len(targets)) 41 for index, work := range targets { 42 work.Wait() 43 results[index] = work.Value() 44 } 45 ft.WithValue(results) 46 }(fts) 47 return ft 48 } 49 50 // WaitFor for collects all resolved successfully values 51 // and returns as a list of values but resolves the 52 // future with an error and a partial list if 53 // any of the futures resolved with an error. 54 func WaitFor(fts ...*Future) *Future { 55 var ft = NewFuture() 56 go func(targets []*Future) { 57 var results = make([]interface{}, 0, len(targets)) 58 for _, work := range targets { 59 work.Wait() 60 var value, err = work.Get() 61 if value != nil { 62 results = append(results, value) 63 } 64 if err != nil { 65 ft.WithValueAndError(results, err) 66 break 67 } 68 } 69 ft.WithValue(results) 70 }(fts) 71 return ft 72 } 73 74 // Then will async-ly wait in a goroutine for the target 75 // future to be resolved at which the provided next Future will 76 // be resolved as well. 77 func (f *Future) Then(next *Future) { 78 go func(){ 79 f.WaitThen(next) 80 }() 81 } 82 83 // WaitThen will block till this future resolves, at which it 84 // resolves the next future provided as an argument. 85 func (f *Future) WaitThen(next *Future) { 86 f.Wait() 87 if f.val != nil { 88 next.WithValue(f.val) 89 } 90 next.WithError(f.err) 91 } 92 93 // Wait blocks till future is resolved. 94 func (f *Future) Wait() { 95 <-f.resolved 96 } 97 98 // IsResolved returns true/false if future is resolved either as error or value. 99 func (f *Future) IsResolved() bool { 100 select { 101 case <-f.resolved: 102 return true 103 default: 104 return false 105 } 106 } 107 108 // Get returns result of future as a tuple of value and error. 109 func (f *Future) Get() (interface{}, error) { 110 f.Wait() 111 return f.val, f.err 112 } 113 114 // Value returns the value of the future, it blocks if the future is yet 115 // resolved and will wait till it's resolved. 116 func (f *Future) Value() interface{} { 117 f.Wait() 118 return f.val 119 } 120 121 // Err returns the error of the future, it blocks if the future is yet 122 // resolved and will wait till it's resolved. 123 func (f *Future) Err() error { 124 f.Wait() 125 return f.err 126 } 127 128 // WithError resolves this Future as a failed operation with provided 129 // error. 130 func (f *Future) WithError(v error) { 131 select { 132 case <-f.resolved: 133 return 134 default: 135 f.err = v 136 close(f.resolved) 137 } 138 return 139 } 140 141 // WithValueAndError resolves this Future as a with a value for 142 // both result and error. Useful for operations where a 143 // value is returned but so was an error. 144 func (f *Future) WithValueAndError(v interface{}, err error) { 145 select { 146 case <-f.resolved: 147 return 148 default: 149 f.val = v 150 f.err = err 151 close(f.resolved) 152 } 153 return 154 } 155 156 157 // WithValue resolves this Future as a completed operation with provided 158 // value. 159 func (f *Future) WithValue(v interface{}) { 160 select { 161 case <-f.resolved: 162 return 163 default: 164 f.val = v 165 close(f.resolved) 166 } 167 return 168 } 169