├── .gitignore ├── LICENSE ├── README.md ├── future.go ├── future_factory.go ├── future_test.go ├── promise.go └── utils.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 fanliao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [home]: github.com/fanliao/go-promise 2 | 3 | go-promise is a Go promise and future library. 4 | 5 | Inspired by [Futures and promises]() 6 | 7 | ## Installation 8 | 9 | $ go get github.com/fanliao/go-promise 10 | 11 | ## Features 12 | 13 | * Future and Promise 14 | 15 | * ```NewPromise()``` 16 | * ```promise.Future``` 17 | 18 | * Promise and Future callbacks 19 | 20 | * ```.OnSuccess(v interface{})``` 21 | * ```.OnFailure(v interface{})``` 22 | * ```.OnComplete(v interface{})``` 23 | * ```.OnCancel()``` 24 | 25 | * Get the result of future 26 | 27 | * ```.Get() ``` 28 | * ```.GetOrTimeout()``` 29 | * ```.GetChan()``` 30 | 31 | * Set timeout for future 32 | 33 | * ```.SetTimeout(ms)``` 34 | 35 | * Merge multiple promises 36 | 37 | * ```WhenAll(func1, func2, func3, ...)``` 38 | * ```WhenAny(func1, func2, func3, ...)``` 39 | * ```WhenAnyMatched(func1, func2, func3, ...)``` 40 | 41 | * Pipe 42 | * ```.Pipe(funcWithDone, funcWithFail)``` 43 | 44 | * Cancel the future 45 | 46 | * ```.Cancel()``` 47 | * ```.IsCancelled()``` 48 | 49 | * Create future by function 50 | 51 | * ```Start(func() (r interface{}, e error))``` 52 | * ```Start(func())``` 53 | * ```Start(func(canceller Canceller) (r interface{}, e error))``` 54 | * ```Start(func(canceller Canceller))``` 55 | 56 | * Immediate wrappers 57 | 58 | * ```Wrap(interface{})``` 59 | 60 | * Chain API 61 | 62 | * ```Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)``` 63 | 64 | ## Quick start 65 | 66 | ### Promise and Future 67 | 68 | ```go 69 | import "github.com/fanliao/go-promise" 70 | import "net/http" 71 | 72 | p := promise.NewPromise() 73 | p.OnSuccess(func(v interface{}) { 74 | ... 75 | }).OnFailure(func(v interface{}) { 76 | ... 77 | }).OnComplete(func(v interface{}) { 78 | ... 79 | }) 80 | 81 | go func(){ 82 | url := "http://example.com/" 83 | 84 | resp, err := http.Get(url) 85 | defer resp.Body.Close() 86 | if err != nil { 87 | p.Reject(err) 88 | } 89 | 90 | body, err := ioutil.ReadAll(resp.Body) 91 | if err != nil { 92 | p.Reject(err) 93 | } 94 | p.Resolve(body) 95 | }() 96 | r, err := p.Get() 97 | ``` 98 | 99 | If you want to provide a read-only view, you can get a future variable: 100 | 101 | ```go 102 | p.Future //cannot Resolve, Reject for a future 103 | ``` 104 | 105 | Can use Start function to submit a future task, it will return a future variable, so cannot Resolve or Reject the future outside of Start function: 106 | 107 | ```go 108 | import "github.com/fanliao/go-promise" 109 | import "net/http" 110 | 111 | task := func()(r interface{}, err error){ 112 | url := "http://example.com/" 113 | 114 | resp, err := http.Get(url) 115 | defer resp.Body.Close() 116 | if err != nil { 117 | return nil, err 118 | } 119 | 120 | body, err := ioutil.ReadAll(resp.Body) 121 | if err != nil { 122 | return nil, err 123 | } 124 | return body, nil 125 | } 126 | 127 | f := promise.Start(task).OnSuccess(func(v interface{}) { 128 | ... 129 | }).OnFailure(func(v interface{}) { 130 | ... 131 | }).OnComplete(func(v interface{}) { 132 | ... 133 | }) 134 | r, err := f.Get() 135 | ``` 136 | 137 | ### Get the result of future 138 | 139 | Please note the process will be block until the future task is completed 140 | 141 | ```go 142 | f := promise.Start(func() (r interface{}, err error) { 143 | return "ok", nil 144 | }) 145 | r, err := f.Get() //return "ok", nil 146 | 147 | f := promise.Start(func() (r interface{}, err error) { 148 | return nil, errors.New("fail") 149 | }) 150 | r, err := f.Get() //return nil, errorString{"fail"} 151 | ``` 152 | 153 | Can wait until timeout 154 | 155 | ```go 156 | f := promise.Start(func() (r interface{}, err error) { 157 | time.Sleep(500 * time.Millisecond) 158 | return "ok", nil 159 | }) 160 | r, err, timeout := f.GetOrTimeout(100) //return nil, nil, true 161 | ``` 162 | 163 | ### Merge multiple futures 164 | 165 | Creates a future that will be completed when all of the supplied future are completed. 166 | ```go 167 | task1 := func() (r interface{}, err error) { 168 | return "ok1", nil 169 | } 170 | task2 := func() (r interface{}, err error) { 171 | return "ok2", nil 172 | } 173 | 174 | f := promise.WhenAll(task1, task2) 175 | r, err := f.Get() //return []interface{}{"ok1", "ok2"} 176 | ``` 177 | 178 | If any future is failure, the future returnd by WhenAll will be failure 179 | ```go 180 | task1 := func() (r interface{}, err error) { 181 | return "ok", nil 182 | } 183 | task2 := func() (r interface{}, err error) { 184 | return nil, errors.New("fail2") 185 | } 186 | f := promise.WhenAll(task1, task2) 187 | r, ok := f.Get() //return nil, *AggregateError 188 | ``` 189 | 190 | Creates a future that will be completed when any of the supplied tasks is completed. 191 | ```go 192 | task1 := func() (r interface{}, err error) { 193 | return "ok1", nil 194 | } 195 | task2 := func() (r interface{}, err error) { 196 | time.Sleep(200 * time.Millisecond) 197 | return nil, errors.New("fail2") 198 | } 199 | 200 | f := promise.WhenAny(task1, task2) 201 | r, err := f.Get() //return "ok1", nil 202 | ``` 203 | 204 | Also can add a predicate function by WhenAnyMatched, the future that will be completed when any of the supplied tasks is completed and match the predicate. 205 | ```go 206 | task1 := func() (r interface{}, err error) { 207 | time.Sleep(200 * time.Millisecond) 208 | return "ok1", nil 209 | } 210 | task2 := func() (r interface{}, err error) { 211 | return "ok2", nil 212 | } 213 | 214 | f := promise.WhenAnyMatched(func(v interface{}) bool{ 215 | return v == "ok1" 216 | }, task1, task2) 217 | r, err := f.Get() //return "ok1", nil 218 | ``` 219 | 220 | ### Promise pipelining 221 | 222 | ```go 223 | task1 := func() (r interface{}, err error) { 224 | return 10, nil 225 | } 226 | task2 := func(v interface{}) (r interface{}, err error) { 227 | return v.(int) * 2, nil 228 | } 229 | 230 | f := promise.Start(task1).Pipe(task2) 231 | r, err := f.Get() //return 20 232 | ``` 233 | 234 | ### Cancel the future or set timeout 235 | 236 | If need cancel a future, can pass a canceller object to task function 237 | ```go 238 | import "github.com/fanliao/go-promise" 239 | import "net/http" 240 | 241 | p := promise.NewPromise().EnableCanceller() 242 | 243 | go func(canceller promise.Canceller){ 244 | for i < 50 { 245 | if canceller.IsCancelled() { 246 | return 247 | } 248 | time.Sleep(100 * time.Millisecond) 249 | } 250 | }(p.Canceller()) 251 | f.Cancel() 252 | 253 | r, err := p.Get() //return nil, promise.CANCELLED 254 | fmt.Println(p.Future.IsCancelled()) //true 255 | ``` 256 | 257 | Or can use Start to submit a future task which can be cancelled 258 | ```go 259 | task := func(canceller promise.Canceller) (r interface{}, err error) { 260 | for i < 50 { 261 | if canceller.IsCancelled() { 262 | return 0, nil 263 | } 264 | time.Sleep(100 * time.Millisecond) 265 | } 266 | return 1, nil 267 | } 268 | f := promise.Start(task1) 269 | f.Cancel() 270 | 271 | r, err := f.Get() //return nil, promise.CANCELLED 272 | fmt.Println(f.IsCancelled()) //true 273 | ``` 274 | 275 | When call WhenAny() function, if a future is completed correctly, then will try to check if other futures enable cancel. If yes, will request cancelling all other futures. 276 | 277 | You can also set timeout for a future 278 | 279 | ```go 280 | task := func(canceller promise.Canceller) (r interface{}, err error) { 281 | time.Sleep(300 * time.Millisecond) 282 | if !canceller.IsCancelled(){ 283 | fmt.Println("Run done") 284 | } 285 | return 286 | } 287 | 288 | f := promise.Start(task).OnCancel(func() { 289 | fmt.Println("Future is cancelled") 290 | }).SetTimeout(100) 291 | 292 | r, err := f.Get() //return nil, promise.CANCELLED 293 | fmt.Println(f.IsCancelled()) //print true 294 | ``` 295 | 296 | ## Document 297 | 298 | * [GoDoc at godoc.org](http://godoc.org/github.com/fanliao/go-promise) 299 | 300 | ## License 301 | 302 | go-promise is licensed under the MIT Licence, (http://www.apache.org/licenses/LICENSE-2.0.html). 303 | -------------------------------------------------------------------------------- /future.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package promise provides a complete promise and future implementation. 3 | A quick start sample: 4 | 5 | 6 | fu := Start(func()(resp interface{}, err error){ 7 | resp, err = http.Get("http://example.com/") 8 | return 9 | }) 10 | //do somthing... 11 | resp, err := fu.Get() 12 | */ 13 | package promise 14 | 15 | import ( 16 | "errors" 17 | "fmt" 18 | "sync/atomic" 19 | "time" 20 | "unsafe" 21 | ) 22 | 23 | type callbackType int 24 | 25 | const ( 26 | CALLBACK_DONE callbackType = iota 27 | CALLBACK_FAIL 28 | CALLBACK_ALWAYS 29 | CALLBACK_CANCEL 30 | ) 31 | 32 | //pipe presents a promise that will be chain call 33 | type pipe struct { 34 | pipeDoneTask, pipeFailTask func(v interface{}) *Future 35 | pipePromise *Promise 36 | } 37 | 38 | //getPipe returns piped Future task function and pipe Promise by the status of current Promise. 39 | func (this *pipe) getPipe(isResolved bool) (func(v interface{}) *Future, *Promise) { 40 | if isResolved { 41 | return this.pipeDoneTask, this.pipePromise 42 | } else { 43 | return this.pipeFailTask, this.pipePromise 44 | } 45 | } 46 | 47 | //Canceller is used to check if the future is cancelled 48 | //It usually be passed to the future task function 49 | //for future task function can check if the future is cancelled. 50 | type Canceller interface { 51 | IsCancelled() bool 52 | Cancel() 53 | } 54 | 55 | //canceller provides an implement of Canceller interface. 56 | //It will be passed to future task function as paramter 57 | type canceller struct { 58 | f *Future 59 | } 60 | 61 | //Cancel sets Future task to CANCELLED status 62 | func (this *canceller) Cancel() { 63 | this.f.Cancel() 64 | } 65 | 66 | //IsCancelled returns true if Future task is cancelld, otherwise false. 67 | func (this *canceller) IsCancelled() (r bool) { 68 | return this.f.IsCancelled() 69 | } 70 | 71 | //futureVal stores the internal state of Future. 72 | type futureVal struct { 73 | dones, fails, always []func(v interface{}) 74 | cancels []func() 75 | pipes []*pipe 76 | r *PromiseResult 77 | } 78 | 79 | //Future provides a read-only view of promise, 80 | //the value is set by using Resolve, Reject and Cancel methods of related Promise 81 | type Future struct { 82 | Id int //Id can be used as identity of Future 83 | final chan struct{} 84 | //val point to futureVal that stores status of future 85 | //if need to change the status of future, must copy a new futureVal and modify it, 86 | //then use CAS to put the pointer of new futureVal 87 | val unsafe.Pointer 88 | } 89 | 90 | //Canceller returns a canceller object related to future. 91 | func (this *Future) Canceller() Canceller { 92 | return &canceller{this} 93 | } 94 | 95 | //IsCancelled returns true if the promise is cancelled, otherwise false 96 | func (this *Future) IsCancelled() bool { 97 | val := this.loadVal() 98 | 99 | if val != nil && val.r != nil && val.r.Typ == RESULT_CANCELLED { 100 | return true 101 | } else { 102 | return false 103 | } 104 | } 105 | 106 | //SetTimeout sets the future task will be cancelled 107 | //if future is not complete before time out 108 | func (this *Future) SetTimeout(mm int) *Future { 109 | if mm == 0 { 110 | mm = 10 111 | } else { 112 | mm = mm * 1000 * 1000 113 | } 114 | 115 | go func() { 116 | <-time.After((time.Duration)(mm) * time.Nanosecond) 117 | this.Cancel() 118 | }() 119 | return this 120 | } 121 | 122 | //GetChan returns a channel than can be used to receive result of Promise 123 | func (this *Future) GetChan() <-chan *PromiseResult { 124 | c := make(chan *PromiseResult, 1) 125 | this.OnComplete(func(v interface{}) { 126 | c <- this.loadResult() 127 | }).OnCancel(func() { 128 | c <- this.loadResult() 129 | }) 130 | return c 131 | } 132 | 133 | //Get will block current goroutines until the Future is resolved/rejected/cancelled. 134 | //If Future is resolved, value and nil will be returned 135 | //If Future is rejected, nil and error will be returned. 136 | //If Future is cancelled, nil and CANCELLED error will be returned. 137 | func (this *Future) Get() (val interface{}, err error) { 138 | <-this.final 139 | return getFutureReturnVal(this.loadResult()) 140 | } 141 | 142 | //GetOrTimeout is similar to Get(), but GetOrTimeout will not block after timeout. 143 | //If GetOrTimeout returns with a timeout, timeout value will be true in return values. 144 | //The unit of paramter is millisecond. 145 | func (this *Future) GetOrTimeout(mm uint) (val interface{}, err error, timout bool) { 146 | if mm == 0 { 147 | mm = 10 148 | } else { 149 | mm = mm * 1000 * 1000 150 | } 151 | 152 | select { 153 | case <-time.After((time.Duration)(mm) * time.Nanosecond): 154 | return nil, nil, true 155 | case <-this.final: 156 | r, err := getFutureReturnVal(this.loadResult()) 157 | return r, err, false 158 | } 159 | } 160 | 161 | //Cancel sets the status of promise to RESULT_CANCELLED. 162 | //If promise is cancelled, Get() will return nil and CANCELLED error. 163 | //All callback functions will be not called if Promise is cancalled. 164 | func (this *Future) Cancel() (e error) { 165 | return this.setResult(&PromiseResult{CANCELLED, RESULT_CANCELLED}) 166 | } 167 | 168 | //OnSuccess registers a callback function that will be called when Promise is resolved. 169 | //If promise is already resolved, the callback will immediately called. 170 | //The value of Promise will be paramter of Done callback function. 171 | func (this *Future) OnSuccess(callback func(v interface{})) *Future { 172 | this.addCallback(callback, CALLBACK_DONE) 173 | return this 174 | } 175 | 176 | //OnFailure registers a callback function that will be called when Promise is rejected. 177 | //If promise is already rejected, the callback will immediately called. 178 | //The error of Promise will be paramter of Fail callback function. 179 | func (this *Future) OnFailure(callback func(v interface{})) *Future { 180 | this.addCallback(callback, CALLBACK_FAIL) 181 | return this 182 | } 183 | 184 | //OnComplete register a callback function that will be called when Promise is rejected or resolved. 185 | //If promise is already rejected or resolved, the callback will immediately called. 186 | //According to the status of Promise, value or error will be paramter of Always callback function. 187 | //Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected. 188 | //Always callback will be not called if Promise be called. 189 | func (this *Future) OnComplete(callback func(v interface{})) *Future { 190 | this.addCallback(callback, CALLBACK_ALWAYS) 191 | return this 192 | } 193 | 194 | //OnCancel registers a callback function that will be called when Promise is cancelled. 195 | //If promise is already cancelled, the callback will immediately called. 196 | func (this *Future) OnCancel(callback func()) *Future { 197 | this.addCallback(callback, CALLBACK_CANCEL) 198 | return this 199 | } 200 | 201 | //Pipe registers one or two functions that returns a Future, and returns a proxy of pipeline Future. 202 | //First function will be called when Future is resolved, the returned Future will be as pipeline Future. 203 | //Secondary function will be called when Futrue is rejected, the returned Future will be as pipeline Future. 204 | func (this *Future) Pipe(callbacks ...interface{}) (result *Future, ok bool) { 205 | if len(callbacks) == 0 || 206 | (len(callbacks) == 1 && callbacks[0] == nil) || 207 | (len(callbacks) > 1 && callbacks[0] == nil && callbacks[1] == nil) { 208 | result = this 209 | return 210 | } 211 | 212 | //ensure all callback functions match the spec "func(v interface{}) *Future" 213 | cs := make([]func(v interface{}) *Future, len(callbacks), len(callbacks)) 214 | for i, callback := range callbacks { 215 | if c, ok1 := callback.(func(v interface{}) *Future); ok1 { 216 | cs[i] = c 217 | } else if c, ok1 := callback.(func() *Future); ok1 { 218 | cs[i] = func(v interface{}) *Future { 219 | return c() 220 | } 221 | } else if c, ok1 := callback.(func(v interface{})); ok1 { 222 | cs[i] = func(v interface{}) *Future { 223 | return Start(func() { 224 | c(v) 225 | }) 226 | } 227 | } else if c, ok1 := callback.(func(v interface{}) (r interface{}, err error)); ok1 { 228 | cs[i] = func(v interface{}) *Future { 229 | return Start(func() (r interface{}, err error) { 230 | r, err = c(v) 231 | return 232 | }) 233 | } 234 | } else if c, ok1 := callback.(func()); ok1 { 235 | cs[i] = func(v interface{}) *Future { 236 | return Start(func() { 237 | c() 238 | }) 239 | } 240 | } else if c, ok1 := callback.(func() (r interface{}, err error)); ok1 { 241 | cs[i] = func(v interface{}) *Future { 242 | return Start(func() (r interface{}, err error) { 243 | r, err = c() 244 | return 245 | }) 246 | } 247 | } else { 248 | ok = false 249 | return 250 | } 251 | } 252 | 253 | for { 254 | v := this.loadVal() 255 | r := v.r 256 | if r != nil { 257 | result = this 258 | if r.Typ == RESULT_SUCCESS && cs[0] != nil { 259 | result = (cs[0](r.Result)) 260 | } else if r.Typ == RESULT_FAILURE && len(cs) > 1 && cs[1] != nil { 261 | result = (cs[1](r.Result)) 262 | } 263 | } else { 264 | newPipe := &pipe{} 265 | newPipe.pipeDoneTask = cs[0] 266 | if len(cs) > 1 { 267 | newPipe.pipeFailTask = cs[1] 268 | } 269 | newPipe.pipePromise = NewPromise() 270 | 271 | newVal := *v 272 | newVal.pipes = append(newVal.pipes, newPipe) 273 | 274 | //use CAS to ensure that the state of Future is not changed, 275 | //if the state is changed, will retry CAS operation. 276 | if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) { 277 | result = newPipe.pipePromise.Future 278 | break 279 | } 280 | } 281 | } 282 | ok = true 283 | 284 | return 285 | } 286 | 287 | //result uses Atomic load to return result of the Future 288 | func (this *Future) loadResult() *PromiseResult { 289 | val := this.loadVal() 290 | return val.r 291 | } 292 | 293 | //val uses Atomic load to return state value of the Future 294 | func (this *Future) loadVal() *futureVal { 295 | r := atomic.LoadPointer(&this.val) 296 | return (*futureVal)(r) 297 | } 298 | 299 | //setResult sets the value and final status of Promise, it will only be executed for once 300 | func (this *Future) setResult(r *PromiseResult) (e error) { //r *PromiseResult) { 301 | defer func() { 302 | if err := getError(recover()); err != nil { 303 | e = err 304 | fmt.Println("\nerror in setResult():", err) 305 | } 306 | }() 307 | 308 | e = errors.New("Cannot resolve/reject/cancel more than once") 309 | 310 | for { 311 | v := this.loadVal() 312 | if v.r != nil { 313 | return 314 | } 315 | newVal := *v 316 | newVal.r = r 317 | 318 | //Use CAS operation to ensure that the state of Promise isn't changed. 319 | //If the state is changed, must get latest state and try to call CAS again. 320 | //No ABA issue in this case because address of all objects are different. 321 | if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) { 322 | //Close chEnd then all Get() and GetOrTimeout() will be unblocked 323 | close(this.final) 324 | 325 | //call callback functions and start the Promise pipeline 326 | if len(v.dones) > 0 || len(v.fails) > 0 || len(v.always) > 0 || len(v.cancels) > 0 { 327 | go func() { 328 | execCallback(r, v.dones, v.fails, v.always, v.cancels) 329 | }() 330 | } 331 | 332 | //start the pipeline 333 | if len(v.pipes) > 0 { 334 | go func() { 335 | for _, pipe := range v.pipes { 336 | pipeTask, pipePromise := pipe.getPipe(r.Typ == RESULT_SUCCESS) 337 | startPipe(r, pipeTask, pipePromise) 338 | } 339 | }() 340 | } 341 | e = nil 342 | break 343 | } 344 | } 345 | return 346 | } 347 | 348 | //handleOneCallback registers a callback function 349 | func (this *Future) addCallback(callback interface{}, t callbackType) { 350 | if callback == nil { 351 | return 352 | } 353 | if (t == CALLBACK_DONE) || 354 | (t == CALLBACK_FAIL) || 355 | (t == CALLBACK_ALWAYS) { 356 | if _, ok := callback.(func(v interface{})); !ok { 357 | panic(errors.New("Callback function spec must be func(v interface{})")) 358 | } 359 | } else if t == CALLBACK_CANCEL { 360 | if _, ok := callback.(func()); !ok { 361 | panic(errors.New("Callback function spec must be func()")) 362 | } 363 | } 364 | 365 | for { 366 | v := this.loadVal() 367 | r := v.r 368 | if r == nil { 369 | newVal := *v 370 | switch t { 371 | case CALLBACK_DONE: 372 | newVal.dones = append(newVal.dones, callback.(func(v interface{}))) 373 | case CALLBACK_FAIL: 374 | newVal.fails = append(newVal.fails, callback.(func(v interface{}))) 375 | case CALLBACK_ALWAYS: 376 | newVal.always = append(newVal.always, callback.(func(v interface{}))) 377 | case CALLBACK_CANCEL: 378 | newVal.cancels = append(newVal.cancels, callback.(func())) 379 | } 380 | 381 | //use CAS to ensure that the state of Future is not changed, 382 | //if the state is changed, will retry CAS operation. 383 | if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) { 384 | break 385 | } 386 | } else { 387 | if (t == CALLBACK_DONE && r.Typ == RESULT_SUCCESS) || 388 | (t == CALLBACK_FAIL && r.Typ == RESULT_FAILURE) || 389 | (t == CALLBACK_ALWAYS && r.Typ != RESULT_CANCELLED) { 390 | callbackFunc := callback.(func(v interface{})) 391 | callbackFunc(r.Result) 392 | } else if t == CALLBACK_CANCEL && r.Typ == RESULT_CANCELLED { 393 | callbackFunc := callback.(func()) 394 | callbackFunc() 395 | } 396 | break 397 | } 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /future_factory.go: -------------------------------------------------------------------------------- 1 | package promise 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | type anyPromiseResult struct { 8 | result interface{} 9 | i int 10 | } 11 | 12 | //Start start a goroutines to execute task function 13 | //and return a Future that presents the result. 14 | //If option paramter is true, the act function will be sync called. 15 | //Type of act can be any of below four types: 16 | // func() (r interface{}, err error): 17 | // if err returned by act != nil or panic error, then Future will be rejected with error, 18 | // otherwise be resolved with r. 19 | // func(): 20 | // if act panic error, then Future will be rejected, otherwise be resolved with nil. 21 | // func(c promise.Canceller) (r interface{}, err error): 22 | // if err returned by act != nil or panic error, 23 | // then Future will be rejected with err, otherwise be resolved with r. 24 | // We can check c.IsCancelled() to decide whether need to exit act function 25 | // func(promise.Canceller): 26 | // if act panic error, then Future will be rejected with error, otherwise be resolved with nil. 27 | // We can check c.IsCancelled() to decide whether need to exit act function. 28 | // error: 29 | // Future will be rejected with error immediately 30 | // other value: 31 | // Future will be resolved with value immediately 32 | func Start(act interface{}, syncs ...bool) *Future { 33 | pr := NewPromise() 34 | if f, ok := act.(*Future); ok { 35 | return f 36 | } 37 | 38 | if action := getAct(pr, act); action != nil { 39 | if syncs != nil && len(syncs) > 0 && !syncs[0] { 40 | //sync call 41 | r, err := action() 42 | if pr.IsCancelled() { 43 | pr.Cancel() 44 | } else { 45 | if err == nil { 46 | pr.Resolve(r) 47 | } else { 48 | pr.Reject(err) 49 | } 50 | } 51 | } else { 52 | //async call 53 | go func() { 54 | r, err := action() 55 | if pr.IsCancelled() { 56 | pr.Cancel() 57 | } else { 58 | if err == nil { 59 | pr.Resolve(r) 60 | } else { 61 | pr.Reject(err) 62 | } 63 | } 64 | }() 65 | } 66 | } 67 | 68 | return pr.Future 69 | } 70 | 71 | //Wrap return a Future that presents the wrapped value 72 | func Wrap(value interface{}) *Future { 73 | pr := NewPromise() 74 | if e, ok := value.(error); !ok { 75 | pr.Resolve(value) 76 | } else { 77 | pr.Reject(e) 78 | } 79 | 80 | return pr.Future 81 | } 82 | 83 | //WhenAny returns a Future. 84 | //If any Future is resolved, this Future will be resolved and return result of resolved Future. 85 | //Otherwise will rejected with results slice returned by all Futures 86 | //Legit types of act are same with Start function 87 | func WhenAny(acts ...interface{}) *Future { 88 | return WhenAnyMatched(nil, acts...) 89 | } 90 | 91 | //WhenAnyMatched returns a Future. 92 | //If any Future is resolved and match the predicate, this Future will be resolved and return result of resolved Future. 93 | //If all Futures are cancelled, this Future will be cancelled. 94 | //Otherwise will rejected with a NoMatchedError included results slice returned by all Futures 95 | //Legit types of act are same with Start function 96 | func WhenAnyMatched(predicate func(interface{}) bool, acts ...interface{}) *Future { 97 | if predicate == nil { 98 | predicate = func(v interface{}) bool { return true } 99 | } 100 | 101 | fs := make([]*Future, len(acts)) 102 | for i, act := range acts { 103 | fs[i] = Start(act) 104 | } 105 | 106 | nf, rs := NewPromise(), make([]interface{}, len(fs)) 107 | if len(acts) == 0 { 108 | nf.Resolve(nil) 109 | } 110 | 111 | chFails, chDones := make(chan anyPromiseResult), make(chan anyPromiseResult) 112 | 113 | go func() { 114 | for i, f := range fs { 115 | k := i 116 | f.OnSuccess(func(v interface{}) { 117 | defer func() { _ = recover() }() 118 | chDones <- anyPromiseResult{v, k} 119 | }).OnFailure(func(v interface{}) { 120 | defer func() { _ = recover() }() 121 | chFails <- anyPromiseResult{v, k} 122 | }).OnCancel(func() { 123 | defer func() { _ = recover() }() 124 | chFails <- anyPromiseResult{CANCELLED, k} 125 | }) 126 | } 127 | }() 128 | 129 | if len(fs) == 1 { 130 | select { 131 | case r := <-chFails: 132 | if _, ok := r.result.(CancelledError); ok { 133 | nf.Cancel() 134 | } else { 135 | nf.Reject(newNoMatchedError1(r.result)) 136 | } 137 | case r := <-chDones: 138 | if predicate(r.result) { 139 | nf.Resolve(r.result) 140 | } else { 141 | nf.Reject(newNoMatchedError1(r.result)) 142 | } 143 | } 144 | } else { 145 | go func() { 146 | defer func() { 147 | if e := recover(); e != nil { 148 | nf.Reject(newErrorWithStacks(e)) 149 | } 150 | }() 151 | 152 | j := 0 153 | for { 154 | select { 155 | case r := <-chFails: 156 | rs[r.i] = getError(r.result) 157 | case r := <-chDones: 158 | if predicate(r.result) { 159 | //try to cancel other futures 160 | for _, f := range fs { 161 | f.Cancel() 162 | } 163 | 164 | //close the channel for avoid the send side be blocked 165 | closeChan := func(c chan anyPromiseResult) { 166 | defer func() { _ = recover() }() 167 | close(c) 168 | } 169 | closeChan(chDones) 170 | closeChan(chFails) 171 | 172 | //Resolve the future and return result 173 | nf.Resolve(r.result) 174 | return 175 | } else { 176 | rs[r.i] = r.result 177 | } 178 | } 179 | 180 | if j++; j == len(fs) { 181 | m := 0 182 | for _, r := range rs { 183 | switch val := r.(type) { 184 | case CancelledError: 185 | default: 186 | m++ 187 | _ = val 188 | } 189 | } 190 | if m > 0 { 191 | nf.Reject(newNoMatchedError(rs)) 192 | } else { 193 | nf.Cancel() 194 | } 195 | break 196 | } 197 | } 198 | }() 199 | } 200 | return nf.Future 201 | } 202 | 203 | //WhenAll receives function slice and returns a Future. 204 | //If all Futures are resolved, this Future will be resolved and return results slice. 205 | //Otherwise will rejected with results slice returned by all Futures 206 | //Legit types of act are same with Start function 207 | func WhenAll(acts ...interface{}) (fu *Future) { 208 | pr := NewPromise() 209 | fu = pr.Future 210 | 211 | if len(acts) == 0 { 212 | pr.Resolve([]interface{}{}) 213 | return 214 | } 215 | 216 | fs := make([]*Future, len(acts)) 217 | for i, act := range acts { 218 | fs[i] = Start(act) 219 | } 220 | fu = whenAllFuture(fs...) 221 | return 222 | } 223 | 224 | //WhenAll receives Futures slice and returns a Future. 225 | //If all Futures are resolved, this Future will be resolved and return results slice. 226 | //If any Future is cancelled, this Future will be cancelled. 227 | //Otherwise will rejected with results slice returned by all Futures. 228 | //Legit types of act are same with Start function 229 | func whenAllFuture(fs ...*Future) *Future { 230 | wf := NewPromise() 231 | rs := make([]interface{}, len(fs)) 232 | 233 | if len(fs) == 0 { 234 | wf.Resolve([]interface{}{}) 235 | } else { 236 | n := int32(len(fs)) 237 | cancelOthers := func(j int) { 238 | for k, f1 := range fs { 239 | if k != j { 240 | f1.Cancel() 241 | } 242 | } 243 | } 244 | 245 | go func() { 246 | isCancelled := int32(0) 247 | for i, f := range fs { 248 | j := i 249 | 250 | f.OnSuccess(func(v interface{}) { 251 | rs[j] = v 252 | if atomic.AddInt32(&n, -1) == 0 { 253 | wf.Resolve(rs) 254 | } 255 | }).OnFailure(func(v interface{}) { 256 | if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) { 257 | //try to cancel all futures 258 | cancelOthers(j) 259 | 260 | //errs := make([]error, 0, 1) 261 | //errs = append(errs, v.(error)) 262 | e := newAggregateError1("Error appears in WhenAll:", v) 263 | wf.Reject(e) 264 | } 265 | }).OnCancel(func() { 266 | if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) { 267 | //try to cancel all futures 268 | cancelOthers(j) 269 | 270 | wf.Cancel() 271 | } 272 | }) 273 | } 274 | }() 275 | } 276 | 277 | return wf.Future 278 | } 279 | -------------------------------------------------------------------------------- /future_test.go: -------------------------------------------------------------------------------- 1 | package promise 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | c "github.com/smartystreets/goconvey/convey" 7 | "reflect" 8 | "strconv" 9 | "testing" 10 | "time" 11 | ) 12 | 13 | const ( 14 | TASK_END = "task be end," 15 | CALL_DONE = "callback done," 16 | CALL_FAIL = "callback fail," 17 | CALL_ALWAYS = "callback always," 18 | WAIT_TASK = "wait task end," 19 | GET = "get task result," 20 | DONE_Pipe_END = "task Pipe done be end," 21 | FAIL_Pipe_END = "task Pipe fail be end," 22 | ) 23 | 24 | // errorLinq is a trivial implementation of error. 25 | type myError struct { 26 | val interface{} 27 | } 28 | 29 | func (e *myError) Error() string { 30 | return fmt.Sprintf("%v", e.val) 31 | } 32 | 33 | func newMyError(v interface{}) *myError { 34 | return &myError{v} 35 | } 36 | 37 | func TestResolveAndReject(t *testing.T) { 38 | c.Convey("When Promise is resolved", t, func() { 39 | p := NewPromise() 40 | go func() { 41 | time.Sleep(50 * time.Millisecond) 42 | p.Resolve("ok") 43 | }() 44 | c.Convey("Should return the argument of Resolve", func() { 45 | r, err := p.Get() 46 | c.So(r, c.ShouldEqual, "ok") 47 | c.So(err, c.ShouldBeNil) 48 | }) 49 | }) 50 | 51 | c.Convey("When Promise is rejected", t, func() { 52 | p := NewPromise() 53 | go func() { 54 | time.Sleep(50 * time.Millisecond) 55 | p.Reject(errors.New("fail")) 56 | }() 57 | c.Convey("Should return error", func() { 58 | r, err := p.Get() 59 | c.So(err, c.ShouldNotBeNil) 60 | c.So(r, c.ShouldEqual, nil) 61 | }) 62 | }) 63 | } 64 | 65 | func TestCancel(t *testing.T) { 66 | c.Convey("When Promise is cancelled", t, func() { 67 | p := NewPromise() 68 | go func() { 69 | time.Sleep(50 * time.Millisecond) 70 | p.Cancel() 71 | }() 72 | 73 | c.Convey("Should return CancelledError", func() { 74 | r, err := p.Get() 75 | c.So(r, c.ShouldBeNil) 76 | c.So(err, c.ShouldEqual, CANCELLED) 77 | c.So(p.IsCancelled(), c.ShouldBeTrue) 78 | }) 79 | }) 80 | } 81 | 82 | func TestGetOrTimeout(t *testing.T) { 83 | timout := 50 * time.Millisecond 84 | c.Convey("When Promise is unfinished", t, func() { 85 | p := NewPromise() 86 | go func() { 87 | <-time.After(timout) 88 | p.Resolve("ok") 89 | }() 90 | c.Convey("timeout should be true", func() { 91 | r, err, timeout := p.GetOrTimeout(10) 92 | c.So(timeout, c.ShouldBeTrue) 93 | c.So(r, c.ShouldBeNil) 94 | c.So(err, c.ShouldBeNil) 95 | }) 96 | 97 | c.Convey("When Promise is resolved, the argument of Resolve should be returned", func() { 98 | r, err, timeout := p.GetOrTimeout(50) 99 | c.So(timeout, c.ShouldBeFalse) 100 | c.So(r, c.ShouldEqual, "ok") 101 | c.So(err, c.ShouldBeNil) 102 | }) 103 | }) 104 | 105 | c.Convey("When Promise is rejected", t, func() { 106 | p := NewPromise() 107 | go func() { 108 | <-time.After(timout) 109 | p.Reject(errors.New("fail")) 110 | }() 111 | c.Convey("Should return error", func() { 112 | r, err, timeout := p.GetOrTimeout(83) 113 | c.So(timeout, c.ShouldBeFalse) 114 | c.So(r, c.ShouldBeNil) 115 | c.So(err, c.ShouldNotBeNil) 116 | }) 117 | }) 118 | 119 | c.Convey("When Promise is cancelled", t, func() { 120 | p := NewPromise() 121 | go func() { 122 | <-time.After(timout) 123 | p.Cancel() 124 | }() 125 | c.Convey("Should return CancelledError", func() { 126 | r, err, timeout := p.GetOrTimeout(83) 127 | c.So(timeout, c.ShouldBeFalse) 128 | c.So(r, c.ShouldBeNil) 129 | c.So(err, c.ShouldEqual, CANCELLED) 130 | c.So(p.IsCancelled(), c.ShouldBeTrue) 131 | }) 132 | }) 133 | } 134 | 135 | func TestGetChan(t *testing.T) { 136 | timout := 50 * time.Millisecond 137 | c.Convey("When Promise is resolved", t, func() { 138 | p := NewPromise() 139 | go func() { 140 | <-time.After(timout) 141 | p.Resolve("ok") 142 | }() 143 | c.Convey("Should receive the argument of Resolve from returned channel", func() { 144 | fr, ok := <-p.GetChan() 145 | c.So(fr.Result, c.ShouldEqual, "ok") 146 | c.So(fr.Typ, c.ShouldEqual, RESULT_SUCCESS) 147 | c.So(ok, c.ShouldBeTrue) 148 | }) 149 | }) 150 | 151 | c.Convey("When Promise is rejected", t, func() { 152 | p := NewPromise() 153 | go func() { 154 | <-time.After(timout) 155 | p.Reject(errors.New("fail")) 156 | }() 157 | c.Convey("Should receive error from returned channel", func() { 158 | fr, ok := <-p.GetChan() 159 | c.So(fr.Result, c.ShouldNotBeNil) 160 | c.So(fr.Typ, c.ShouldEqual, RESULT_FAILURE) 161 | c.So(ok, c.ShouldBeTrue) 162 | }) 163 | }) 164 | 165 | c.Convey("When Promise is cancelled", t, func() { 166 | p := NewPromise() 167 | go func() { 168 | <-time.After(timout) 169 | p.Cancel() 170 | }() 171 | c.Convey("Should receive CancelledError from returned channel", func() { 172 | fr, ok := <-p.GetChan() 173 | c.So(fr.Result, c.ShouldEqual, CANCELLED) 174 | c.So(p.IsCancelled(), c.ShouldBeTrue) 175 | c.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED) 176 | c.So(ok, c.ShouldBeTrue) 177 | }) 178 | 179 | c.Convey("Should receive CancelledError from returned channel at second time", func() { 180 | fr, ok := <-p.GetChan() 181 | c.So(fr.Result, c.ShouldEqual, CANCELLED) 182 | c.So(p.IsCancelled(), c.ShouldBeTrue) 183 | c.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED) 184 | c.So(ok, c.ShouldBeTrue) 185 | }) 186 | }) 187 | } 188 | 189 | func TestFuture(t *testing.T) { 190 | c.Convey("Future can receive return value and status but cannot change the status", t, func() { 191 | var fu *Future 192 | c.Convey("When Future is resolved", func() { 193 | func() { 194 | p := NewPromise() 195 | go func() { 196 | time.Sleep(50 * time.Millisecond) 197 | p.Resolve("ok") 198 | }() 199 | fu = p.Future 200 | }() 201 | r, err := fu.Get() 202 | c.So(r, c.ShouldEqual, "ok") 203 | c.So(err, c.ShouldBeNil) 204 | }) 205 | 206 | c.Convey("When Future is rejected", func() { 207 | func() { 208 | p := NewPromise() 209 | go func() { 210 | time.Sleep(50 * time.Millisecond) 211 | p.Reject(errors.New("fail")) 212 | }() 213 | fu = p.Future 214 | }() 215 | r, err := fu.Get() 216 | c.So(err, c.ShouldNotBeNil) 217 | c.So(r, c.ShouldEqual, nil) 218 | }) 219 | 220 | c.Convey("When Future is cancelled", func() { 221 | func() { 222 | p := NewPromise() 223 | go func() { 224 | time.Sleep(50 * time.Millisecond) 225 | p.Cancel() 226 | }() 227 | fu = p.Future 228 | }() 229 | r, err := fu.Get() 230 | c.So(err, c.ShouldNotBeNil) 231 | c.So(r, c.ShouldEqual, nil) 232 | }) 233 | }) 234 | 235 | } 236 | 237 | func TestCallbacks(t *testing.T) { 238 | timout := 50 * time.Millisecond 239 | done, always, fail, cancel := false, false, false, false 240 | 241 | p := NewPromise() 242 | go func() { 243 | <-time.After(timout) 244 | p.Resolve("ok") 245 | }() 246 | 247 | c.Convey("When Promise is resolved", t, func() { 248 | p.OnSuccess(func(v interface{}) { 249 | done = true 250 | c.Convey("The argument of Done should be 'ok'", t, func() { 251 | c.So(v, c.ShouldEqual, "ok") 252 | }) 253 | }).OnComplete(func(v interface{}) { 254 | always = true 255 | c.Convey("The argument of Always should be 'ok'", t, func() { 256 | c.So(v, c.ShouldEqual, "ok") 257 | }) 258 | }).OnFailure(func(v interface{}) { 259 | fail = true 260 | panic("Unexpected calling") 261 | }) 262 | r, err := p.Get() 263 | 264 | //The code after Get() and the callback will be concurrent run 265 | //So sleep 52 ms to wait all callback be done 266 | time.Sleep(52 * time.Millisecond) 267 | 268 | c.Convey("Should call the Done and Always callbacks", func() { 269 | c.So(r, c.ShouldEqual, "ok") 270 | c.So(err, c.ShouldBeNil) 271 | c.So(done, c.ShouldEqual, true) 272 | c.So(always, c.ShouldEqual, true) 273 | c.So(fail, c.ShouldEqual, false) 274 | }) 275 | }) 276 | 277 | c.Convey("When adding the callback after Promise is resolved", t, func() { 278 | done, always, fail := false, false, false 279 | p.OnSuccess(func(v interface{}) { 280 | done = true 281 | c.Convey("The argument of Done should be 'ok'", func() { 282 | c.So(v, c.ShouldEqual, "ok") 283 | }) 284 | }).OnComplete(func(v interface{}) { 285 | always = true 286 | c.Convey("The argument of Always should be 'ok'", func() { 287 | c.So(v, c.ShouldEqual, "ok") 288 | }) 289 | }).OnFailure(func(v interface{}) { 290 | fail = true 291 | panic("Unexpected calling") 292 | }) 293 | c.Convey("Should immediately run the Done and Always callbacks", func() { 294 | c.So(done, c.ShouldEqual, true) 295 | c.So(always, c.ShouldEqual, true) 296 | c.So(fail, c.ShouldEqual, false) 297 | }) 298 | }) 299 | 300 | var e *error = nil 301 | done, always, fail = false, false, false 302 | p = NewPromise() 303 | go func() { 304 | <-time.After(timout) 305 | p.Reject(errors.New("fail")) 306 | }() 307 | 308 | c.Convey("When Promise is rejected", t, func() { 309 | p.OnSuccess(func(v interface{}) { 310 | done = true 311 | panic("Unexpected calling") 312 | }).OnComplete(func(v interface{}) { 313 | always = true 314 | c.Convey("The argument of Always should be error", t, func() { 315 | c.So(v, c.ShouldImplement, e) 316 | }) 317 | }).OnFailure(func(v interface{}) { 318 | fail = true 319 | c.Convey("The argument of Fail should be error", t, func() { 320 | c.So(v, c.ShouldImplement, e) 321 | }) 322 | }) 323 | r, err := p.Get() 324 | 325 | time.Sleep(52 * time.Millisecond) 326 | 327 | c.Convey("Should call the Fail and Always callbacks", func() { 328 | c.So(r, c.ShouldEqual, nil) 329 | c.So(err, c.ShouldNotBeNil) 330 | c.So(done, c.ShouldEqual, false) 331 | c.So(always, c.ShouldEqual, true) 332 | c.So(fail, c.ShouldEqual, true) 333 | }) 334 | }) 335 | 336 | c.Convey("When adding the callback after Promise is rejected", t, func() { 337 | done, always, fail = false, false, false 338 | p.OnSuccess(func(v interface{}) { 339 | done = true 340 | panic("Unexpected calling") 341 | }).OnComplete(func(v interface{}) { 342 | always = true 343 | c.Convey("The argument of Always should be error", func() { 344 | c.So(v, c.ShouldImplement, e) 345 | }) 346 | }).OnFailure(func(v interface{}) { 347 | fail = true 348 | c.Convey("The argument of Fail should be error", func() { 349 | c.So(v, c.ShouldImplement, e) 350 | }) 351 | }) 352 | c.Convey("Should immediately run the Fail and Always callbacks", func() { 353 | c.So(done, c.ShouldEqual, false) 354 | c.So(always, c.ShouldEqual, true) 355 | c.So(fail, c.ShouldEqual, true) 356 | }) 357 | }) 358 | 359 | done, always, fail = false, false, false 360 | p = NewPromise() 361 | go func() { 362 | <-time.After(timout) 363 | p.Cancel() 364 | }() 365 | 366 | c.Convey("When Promise is cancelled", t, func() { 367 | done, always, fail, cancel = false, false, false, false 368 | p.OnSuccess(func(v interface{}) { 369 | done = true 370 | }).OnComplete(func(v interface{}) { 371 | always = true 372 | }).OnFailure(func(v interface{}) { 373 | fail = true 374 | }).OnCancel(func() { 375 | cancel = true 376 | }) 377 | r, err := p.Get() 378 | 379 | time.Sleep(62 * time.Millisecond) 380 | 381 | c.Convey("Only cancel callback be called", func() { 382 | c.So(r, c.ShouldBeNil) 383 | c.So(err, c.ShouldNotBeNil) 384 | c.So(done, c.ShouldEqual, false) 385 | c.So(always, c.ShouldEqual, false) 386 | c.So(fail, c.ShouldEqual, false) 387 | c.So(cancel, c.ShouldEqual, true) 388 | }) 389 | }) 390 | 391 | c.Convey("When adding the callback after Promise is cancelled", t, func() { 392 | done, always, fail, cancel = false, false, false, false 393 | p.OnSuccess(func(v interface{}) { 394 | done = true 395 | }).OnComplete(func(v interface{}) { 396 | always = true 397 | }).OnFailure(func(v interface{}) { 398 | fail = true 399 | }).OnCancel(func() { 400 | cancel = true 401 | }) 402 | c.Convey("Should not call any callbacks", func() { 403 | c.So(done, c.ShouldEqual, false) 404 | c.So(always, c.ShouldEqual, false) 405 | c.So(fail, c.ShouldEqual, false) 406 | c.So(cancel, c.ShouldEqual, true) 407 | }) 408 | }) 409 | 410 | } 411 | 412 | func TestStart(t *testing.T) { 413 | 414 | c.Convey("Test start func()", t, func() { 415 | c.Convey("When task completed", func() { 416 | f := Start(func() {}) 417 | r, err := f.Get() 418 | c.So(r, c.ShouldBeNil) 419 | c.So(err, c.ShouldBeNil) 420 | }) 421 | c.Convey("When task panic error", func() { 422 | f := Start(func() { panic("fail") }) 423 | r, err := f.Get() 424 | c.So(r, c.ShouldBeNil) 425 | c.So(err, c.ShouldNotBeNil) 426 | }) 427 | }) 428 | 429 | c.Convey("Test start func()(interface{}, error)", t, func() { 430 | c.Convey("When task completed", func() { 431 | f := Start(func() (interface{}, error) { 432 | time.Sleep(10) 433 | return "ok", nil 434 | }) 435 | r, err := f.Get() 436 | c.So(r, c.ShouldEqual, "ok") 437 | c.So(err, c.ShouldBeNil) 438 | }) 439 | 440 | c.Convey("When task returned error", func() { 441 | f := Start(func() (interface{}, error) { 442 | time.Sleep(10) 443 | return "fail", errors.New("fail") 444 | }) 445 | r, err := f.Get() 446 | c.So(r, c.ShouldBeNil) 447 | c.So(err, c.ShouldNotBeNil) 448 | }) 449 | 450 | c.Convey("When task panic error", func() { 451 | f := Start(func() (interface{}, error) { panic("fail") }) 452 | r, err := f.Get() 453 | c.So(r, c.ShouldBeNil) 454 | c.So(err, c.ShouldNotBeNil) 455 | }) 456 | }) 457 | 458 | c.Convey("Test start func(canceller Canceller)", t, func() { 459 | c.Convey("When task completed", func() { 460 | f := Start(func(canceller Canceller) { 461 | time.Sleep(10) 462 | }) 463 | r, err := f.Get() 464 | c.So(r, c.ShouldBeNil) 465 | c.So(err, c.ShouldBeNil) 466 | }) 467 | 468 | c.Convey("When task be cancelled", func() { 469 | f := Start(func(canceller Canceller) { 470 | time.Sleep(10) 471 | if canceller.IsCancelled() { 472 | return 473 | } 474 | }) 475 | f.Cancel() 476 | r, err := f.Get() 477 | c.So(f.IsCancelled(), c.ShouldBeTrue) 478 | c.So(r, c.ShouldBeNil) 479 | c.So(err, c.ShouldEqual, CANCELLED) 480 | c.So(f.IsCancelled(), c.ShouldBeTrue) 481 | }) 482 | c.Convey("When task panic error", func() { 483 | f := Start(func(canceller Canceller) { panic("fail") }) 484 | r, err := f.Get() 485 | c.So(r, c.ShouldBeNil) 486 | c.So(err, c.ShouldNotBeNil) 487 | }) 488 | }) 489 | 490 | c.Convey("Test start func(canceller Canceller)(interface{}, error)", t, func() { 491 | c.Convey("When task be cancenlled", func() { 492 | task := func(canceller Canceller) (interface{}, error) { 493 | i := 0 494 | for i < 50 { 495 | if canceller.IsCancelled() { 496 | return nil, nil 497 | } 498 | time.Sleep(100 * time.Millisecond) 499 | } 500 | panic("exception") 501 | } 502 | 503 | f := Start(task) 504 | f.Cancel() 505 | r, err := f.Get() 506 | 507 | c.So(f.IsCancelled(), c.ShouldBeTrue) 508 | c.So(r, c.ShouldBeNil) 509 | c.So(err, c.ShouldEqual, CANCELLED) 510 | c.So(f.IsCancelled(), c.ShouldBeTrue) 511 | }) 512 | 513 | c.Convey("When task panic error", func() { 514 | f := Start(func(canceller Canceller) (interface{}, error) { 515 | panic("fail") 516 | }) 517 | r, err := f.Get() 518 | c.So(r, c.ShouldBeNil) 519 | c.So(err, c.ShouldNotBeNil) 520 | }) 521 | }) 522 | 523 | } 524 | 525 | func TestPipe(t *testing.T) { 526 | timout := 50 * time.Millisecond 527 | taskDonePipe := func(v interface{}) *Future { 528 | return Start(func() (interface{}, error) { 529 | <-time.After(timout) 530 | return v.(string) + "2", nil 531 | }) 532 | } 533 | 534 | taskFailPipe := func() (interface{}, error) { 535 | <-time.After(timout) 536 | return "fail2", nil 537 | } 538 | 539 | c.Convey("When task completed", t, func() { 540 | p := NewPromise() 541 | go func() { 542 | <-time.After(timout) 543 | p.Resolve("ok") 544 | }() 545 | fu, ok := p.Pipe(taskDonePipe, taskFailPipe) 546 | r, err := fu.Get() 547 | c.Convey("the done callback will be called, the future returned by done callback will be returned as chain future", func() { 548 | c.So(r, c.ShouldEqual, "ok2") 549 | c.So(err, c.ShouldBeNil) 550 | c.So(ok, c.ShouldEqual, true) 551 | }) 552 | }) 553 | 554 | c.Convey("When task failed", t, func() { 555 | p := NewPromise() 556 | go func() { 557 | <-time.After(timout) 558 | p.Reject(errors.New("fail")) 559 | }() 560 | fu, ok := p.Pipe(taskDonePipe, taskFailPipe) 561 | r, err := fu.Get() 562 | 563 | c.Convey("the fail callback will be called, the future returned by fail callback will be returned as chain future", func() { 564 | c.So(r, c.ShouldEqual, "fail2") 565 | c.So(err, c.ShouldBeNil) 566 | c.So(ok, c.ShouldEqual, true) 567 | }) 568 | }) 569 | 570 | c.Convey("Test pipe twice", t, func() { 571 | p := NewPromise() 572 | pipeFuture1, ok1 := p.Pipe(taskDonePipe, taskFailPipe) 573 | c.Convey("Calling Pipe succeed at first time", func() { 574 | c.So(ok1, c.ShouldEqual, true) 575 | }) 576 | pipeFuture2, ok2 := p.Pipe(taskDonePipe, taskFailPipe) 577 | c.Convey("Calling Pipe succeed at second time", func() { 578 | c.So(ok2, c.ShouldEqual, true) 579 | }) 580 | p.Resolve("ok") 581 | 582 | r, _ := pipeFuture1.Get() 583 | c.Convey("Pipeline future 1 should return ok2", func() { 584 | c.So(r, c.ShouldEqual, "ok2") 585 | }) 586 | 587 | r2, _ := pipeFuture2.Get() 588 | c.Convey("Pipeline future 2 should return ok2", func() { 589 | c.So(r2, c.ShouldEqual, "ok2") 590 | }) 591 | }) 592 | } 593 | 594 | func TestWhenAny(t *testing.T) { 595 | c.Convey("Test WhenAny", t, func() { 596 | whenAnyTasks := func(t1 int, t2 int) *Future { 597 | timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)} 598 | getTask := func(i int) func() (interface{}, error) { 599 | return func() (interface{}, error) { 600 | if timeouts[i] > 0 { 601 | time.Sleep(timeouts[i] * time.Millisecond) 602 | return "ok" + strconv.Itoa(i), nil 603 | } else { 604 | time.Sleep((-1 * timeouts[i]) * time.Millisecond) 605 | return nil, newMyError("fail" + strconv.Itoa(i)) 606 | } 607 | } 608 | } 609 | task0 := getTask(0) 610 | task1 := getTask(1) 611 | f := WhenAny(task0, task1) 612 | return f 613 | } 614 | 615 | c.Convey("When all tasks completed, and task 1 be first to complete", func() { 616 | r, err := whenAnyTasks(200, 250).Get() 617 | c.So(r, c.ShouldEqual, "ok0") 618 | c.So(err, c.ShouldBeNil) 619 | }) 620 | 621 | c.Convey("When all tasks completed, and task 2 be first to complete", func() { 622 | r, err := whenAnyTasks(280, 250).Get() 623 | c.So(r, c.ShouldEqual, "ok1") 624 | c.So(err, c.ShouldBeNil) 625 | }) 626 | 627 | c.Convey("When all tasks failed", func() { 628 | r, err := whenAnyTasks(-280, -250).Get() 629 | errs := err.(*NoMatchedError).Results 630 | c.So(r, c.ShouldBeNil) 631 | c.So(errs[0].(*myError).val, c.ShouldEqual, "fail0") 632 | c.So(errs[1].(*myError).val, c.ShouldEqual, "fail1") 633 | }) 634 | 635 | c.Convey("When one task completed", func() { 636 | r, err := whenAnyTasks(-280, 150).Get() 637 | c.So(r, c.ShouldEqual, "ok1") 638 | c.So(err, c.ShouldBeNil) 639 | }) 640 | 641 | c.Convey("When no task be passed", func() { 642 | r, err := WhenAny().Get() 643 | c.So(r, c.ShouldBeNil) 644 | c.So(err, c.ShouldBeNil) 645 | }) 646 | }) 647 | 648 | c.Convey("Test WhenAny, and task can be cancelled", t, func() { 649 | var c1, c2 bool 650 | whenAnyCanCancelTasks := func(t1 int, t2 int) *Future { 651 | timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)} 652 | getTask := func(i int) func(canceller Canceller) (interface{}, error) { 653 | return func(canceller Canceller) (interface{}, error) { 654 | for j := 0; j < 10; j++ { 655 | if timeouts[i] > 0 { 656 | time.Sleep(timeouts[i] * time.Millisecond) 657 | } else { 658 | time.Sleep((-1 * timeouts[i]) * time.Millisecond) 659 | } 660 | if canceller.IsCancelled() { 661 | if i == 0 { 662 | c1 = true 663 | } else { 664 | c2 = true 665 | } 666 | return nil, nil 667 | } 668 | } 669 | if timeouts[i] > 0 { 670 | return "ok" + strconv.Itoa(i), nil 671 | } else { 672 | return nil, newMyError("fail" + strconv.Itoa(i)) 673 | } 674 | } 675 | } 676 | task0 := getTask(0) 677 | task1 := getTask(1) 678 | f := WhenAny(Start(task0), Start(task1)) 679 | return f 680 | } 681 | c.Convey("When task 1 is the first to complete, task 2 will be cancelled", func() { 682 | r, err := whenAnyCanCancelTasks(10, 250).Get() 683 | 684 | c.So(r, c.ShouldEqual, "ok0") 685 | c.So(err, c.ShouldBeNil) 686 | time.Sleep(1000 * time.Millisecond) 687 | c.So(c2, c.ShouldEqual, true) 688 | }) 689 | 690 | c.Convey("When task 2 is the first to complete, task 1 will be cancelled", func() { 691 | r, err := whenAnyCanCancelTasks(200, 10).Get() 692 | 693 | c.So(r, c.ShouldEqual, "ok1") 694 | c.So(err, c.ShouldBeNil) 695 | time.Sleep(1000 * time.Millisecond) 696 | c.So(c1, c.ShouldEqual, true) 697 | }) 698 | 699 | }) 700 | } 701 | 702 | func TestWhenAnyTrue(t *testing.T) { 703 | c1, c2 := false, false 704 | startTwoCanCancelTask := func(t1 int, t2 int, predicate func(interface{}) bool) *Future { 705 | timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)} 706 | getTask := func(i int) func(canceller Canceller) (interface{}, error) { 707 | return func(canceller Canceller) (interface{}, error) { 708 | for j := 0; j < 10; j++ { 709 | if timeouts[i] > 0 { 710 | time.Sleep(timeouts[i] * time.Millisecond) 711 | } else { 712 | time.Sleep((-1 * timeouts[i]) * time.Millisecond) 713 | } 714 | if canceller.IsCancelled() { 715 | if i == 0 { 716 | c1 = true 717 | } else { 718 | c2 = true 719 | } 720 | return nil, nil 721 | } 722 | } 723 | if timeouts[i] > 0 { 724 | return "ok" + strconv.Itoa(i), nil 725 | } else { 726 | return nil, newMyError("fail" + strconv.Itoa(i)) 727 | } 728 | } 729 | } 730 | task0 := getTask(0) 731 | task1 := getTask(1) 732 | f := WhenAnyMatched(predicate, Start(task0), Start(task1)) 733 | return f 734 | } 735 | //第一个任务先完成,第二个后完成,并且设定条件为返回值==第一个的返回值 736 | c.Convey("When the task1 is the first to complete, and predicate returns true", t, func() { 737 | r, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool { 738 | return v.(string) == "ok0" 739 | }).Get() 740 | c.So(r, c.ShouldEqual, "ok0") 741 | c.So(err, c.ShouldBeNil) 742 | time.Sleep(1000 * time.Millisecond) 743 | c.So(c2, c.ShouldEqual, true) 744 | }) 745 | 746 | //第一个任务后完成,第二个先完成,并且设定条件为返回值==第二个的返回值 747 | c.Convey("When the task2 is the first to complete, and predicate returns true", t, func() { 748 | c1, c2 = false, false 749 | r, err := startTwoCanCancelTask(230, 50, func(v interface{}) bool { 750 | return v.(string) == "ok1" 751 | }).Get() 752 | c.So(r, c.ShouldEqual, "ok1") 753 | c.So(err, c.ShouldBeNil) 754 | time.Sleep(1000 * time.Millisecond) 755 | c.So(c1, c.ShouldEqual, true) 756 | }) 757 | 758 | //第一个任务后完成,第二个先完成,并且设定条件为返回值不等于任意一个任务的返回值 759 | c.Convey("When the task2 is the first to complete, and predicate always returns false", t, func() { 760 | c1, c2 = false, false 761 | r, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool { 762 | return v.(string) == "ok11" 763 | }).Get() 764 | 765 | _, ok := err.(*NoMatchedError) 766 | c.So(r, c.ShouldBeNil) 767 | c.So(ok, c.ShouldBeTrue) 768 | c.So(err, c.ShouldNotBeNil) 769 | 770 | time.Sleep(1000 * time.Millisecond) 771 | c.So(c1, c.ShouldEqual, false) 772 | c.So(c2, c.ShouldEqual, false) 773 | }) 774 | 775 | //c.Convey("When all tasks be cancelled", t, func() { 776 | // getTask := func(canceller Canceller) (interface{}, error) { 777 | // for { 778 | // time.Sleep(50 * time.Millisecond) 779 | // if canceller.IsCancellationRequested() { 780 | // canceller.Cancel() 781 | // return nil, nil 782 | // } 783 | // } 784 | // } 785 | 786 | // f1 := Start(getTask) 787 | // f2 := Start(getTask) 788 | // f3 := WhenAnyMatched(nil, f1, f2) 789 | 790 | // f1.RequestCancel() 791 | // f2.RequestCancel() 792 | 793 | // r, _ := f3.Get() 794 | // c.So(r, c.ShouldBeNil) 795 | //}) 796 | 797 | } 798 | 799 | func TestWhenAll(t *testing.T) { 800 | startTwoTask := func(t1 int, t2 int) (f *Future) { 801 | timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)} 802 | getTask := func(i int) func() (interface{}, error) { 803 | return func() (interface{}, error) { 804 | if timeouts[i] > 0 { 805 | time.Sleep(timeouts[i] * time.Millisecond) 806 | return "ok" + strconv.Itoa(i), nil 807 | } else { 808 | time.Sleep((-1 * timeouts[i]) * time.Millisecond) 809 | return nil, newMyError("fail" + strconv.Itoa(i)) 810 | } 811 | } 812 | } 813 | task0 := getTask(0) 814 | task1 := getTask(1) 815 | f = WhenAll(task0, task1) 816 | return f 817 | } 818 | c.Convey("Test WhenAllFuture", t, func() { 819 | whenTwoTask := func(t1 int, t2 int) *Future { 820 | return startTwoTask(t1, t2) 821 | } 822 | c.Convey("When all tasks completed, and the task1 is the first to complete", func() { 823 | r, err := whenTwoTask(200, 230).Get() 824 | c.So(r, shouldSlicesReSame, []interface{}{"ok0", "ok1"}) 825 | c.So(err, c.ShouldBeNil) 826 | }) 827 | 828 | c.Convey("When all tasks completed, and the task1 is the first to complete", func() { 829 | r, err := whenTwoTask(230, 200).Get() 830 | c.So(r, shouldSlicesReSame, []interface{}{"ok0", "ok1"}) 831 | c.So(err, c.ShouldBeNil) 832 | }) 833 | 834 | c.Convey("When task1 failed, but task2 is completed", func() { 835 | r, err := whenTwoTask(-250, 210).Get() 836 | c.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, "fail0") 837 | c.So(r, c.ShouldBeNil) 838 | }) 839 | 840 | c.Convey("When all tasks failed", func() { 841 | r, err := whenTwoTask(-250, -110).Get() 842 | c.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, "fail1") 843 | c.So(r, c.ShouldBeNil) 844 | }) 845 | 846 | c.Convey("When no task be passed", func() { 847 | r, err := whenAllFuture().Get() 848 | c.So(r, shouldSlicesReSame, []interface{}{}) 849 | c.So(err, c.ShouldBeNil) 850 | }) 851 | 852 | c.Convey("When all tasks be cancelled", func() { 853 | getTask := func(canceller Canceller) (interface{}, error) { 854 | for { 855 | time.Sleep(50 * time.Millisecond) 856 | if canceller.IsCancelled() { 857 | return nil, nil 858 | } 859 | } 860 | } 861 | 862 | f1 := Start(getTask) 863 | f2 := Start(getTask) 864 | f3 := WhenAll(f1, f2) 865 | 866 | f1.Cancel() 867 | f2.Cancel() 868 | 869 | r, _ := f3.Get() 870 | c.So(r, c.ShouldBeNil) 871 | }) 872 | }) 873 | } 874 | 875 | func TestWrap(t *testing.T) { 876 | c.Convey("Test Wrap a value", t, func() { 877 | r, err := Wrap(10).Get() 878 | c.So(r, c.ShouldEqual, 10) 879 | c.So(err, c.ShouldBeNil) 880 | }) 881 | } 882 | 883 | func shouldSlicesReSame(actual interface{}, expected ...interface{}) string { 884 | actualSlice, expectedSlice := reflect.ValueOf(actual), reflect.ValueOf(expected[0]) 885 | if actualSlice.Kind() != expectedSlice.Kind() { 886 | return fmt.Sprintf("Expected1: '%v'\nActual: '%v'\n", expected[0], actual) 887 | } 888 | 889 | if actualSlice.Kind() != reflect.Slice { 890 | return fmt.Sprintf("Expected2: '%v'\nActual: '%v'\n", expected[0], actual) 891 | } 892 | 893 | if actualSlice.Len() != expectedSlice.Len() { 894 | return fmt.Sprintf("Expected3: '%v'\nActual: '%v'\n", expected[0], actual) 895 | } 896 | 897 | for i := 0; i < actualSlice.Len(); i++ { 898 | if !reflect.DeepEqual(actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface()) { 899 | return fmt.Sprintf("Expected4: '%v'\nActual: '%v'\n", expected[0], actual) 900 | } 901 | } 902 | return "" 903 | } 904 | -------------------------------------------------------------------------------- /promise.go: -------------------------------------------------------------------------------- 1 | package promise 2 | 3 | import ( 4 | "math/rand" 5 | "unsafe" 6 | ) 7 | 8 | var ( 9 | CANCELLED error = &CancelledError{} 10 | ) 11 | 12 | //CancelledError present the Future object is cancelled. 13 | type CancelledError struct { 14 | } 15 | 16 | func (e *CancelledError) Error() string { 17 | return "Task be cancelled" 18 | } 19 | 20 | //resultType present the type of Future final status. 21 | type resultType int 22 | 23 | const ( 24 | RESULT_SUCCESS resultType = iota 25 | RESULT_FAILURE 26 | RESULT_CANCELLED 27 | ) 28 | 29 | //PromiseResult presents the result of a promise. 30 | //If Typ is RESULT_SUCCESS, Result field will present the returned value of Future task. 31 | //If Typ is RESULT_FAILURE, Result field will present a related error . 32 | //If Typ is RESULT_CANCELLED, Result field will be null. 33 | type PromiseResult struct { 34 | Result interface{} //result of the Promise 35 | Typ resultType //success, failure, or cancelled? 36 | } 37 | 38 | //Promise presents an object that acts as a proxy for a result. 39 | //that is initially unknown, usually because the computation of its 40 | //value is yet incomplete (refer to wikipedia). 41 | //You can use Resolve/Reject/Cancel to set the final result of Promise. 42 | //Future can return a read-only placeholder view of result. 43 | type Promise struct { 44 | *Future 45 | } 46 | 47 | //Cancel sets the status of promise to RESULT_CANCELLED. 48 | //If promise is cancelled, Get() will return nil and CANCELLED error. 49 | //All callback functions will be not called if Promise is cancalled. 50 | func (this *Promise) Cancel() (e error) { 51 | return this.Future.Cancel() 52 | } 53 | 54 | //Resolve sets the value for promise, and the status will be changed to RESULT_SUCCESS. 55 | //if promise is resolved, Get() will return the value and nil error. 56 | func (this *Promise) Resolve(v interface{}) (e error) { 57 | return this.setResult(&PromiseResult{v, RESULT_SUCCESS}) 58 | } 59 | 60 | //Resolve sets the error for promise, and the status will be changed to RESULT_FAILURE. 61 | //if promise is rejected, Get() will return nil and the related error value. 62 | func (this *Promise) Reject(err error) (e error) { 63 | return this.setResult(&PromiseResult{err, RESULT_FAILURE}) 64 | } 65 | 66 | //OnSuccess registers a callback function that will be called when Promise is resolved. 67 | //If promise is already resolved, the callback will immediately called. 68 | //The value of Promise will be paramter of Done callback function. 69 | func (this *Promise) OnSuccess(callback func(v interface{})) *Promise { 70 | this.Future.OnSuccess(callback) 71 | return this 72 | } 73 | 74 | //OnFailure registers a callback function that will be called when Promise is rejected. 75 | //If promise is already rejected, the callback will immediately called. 76 | //The error of Promise will be paramter of Fail callback function. 77 | func (this *Promise) OnFailure(callback func(v interface{})) *Promise { 78 | this.Future.OnFailure(callback) 79 | return this 80 | } 81 | 82 | //OnComplete register a callback function that will be called when Promise is rejected or resolved. 83 | //If promise is already rejected or resolved, the callback will immediately called. 84 | //According to the status of Promise, value or error will be paramter of Always callback function. 85 | //Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected. 86 | //Always callback will be not called if Promise be called. 87 | func (this *Promise) OnComplete(callback func(v interface{})) *Promise { 88 | this.Future.OnComplete(callback) 89 | return this 90 | } 91 | 92 | //OnCancel registers a callback function that will be called when Promise is cancelled. 93 | //If promise is already cancelled, the callback will immediately called. 94 | func (this *Promise) OnCancel(callback func()) *Promise { 95 | this.Future.OnCancel(callback) 96 | return this 97 | } 98 | 99 | //NewPromise is factory function for Promise 100 | func NewPromise() *Promise { 101 | val := &futureVal{ 102 | make([]func(v interface{}), 0, 8), 103 | make([]func(v interface{}), 0, 8), 104 | make([]func(v interface{}), 0, 4), 105 | make([]func(), 0, 2), 106 | make([]*pipe, 0, 4), nil, 107 | } 108 | f := &Promise{ 109 | &Future{ 110 | rand.Int(), 111 | make(chan struct{}), 112 | unsafe.Pointer(val), 113 | }, 114 | } 115 | return f 116 | } 117 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package promise 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "runtime" 8 | "strconv" 9 | ) 10 | 11 | //NoMatchedError presents no future that returns matched result in WhenAnyTrue function. 12 | type NoMatchedError struct { 13 | Results []interface{} 14 | } 15 | 16 | func (e *NoMatchedError) Error() string { 17 | return "No matched future" 18 | } 19 | 20 | func (e *NoMatchedError) HasError() bool { 21 | for _, ie := range e.Results { 22 | if _, ok1 := ie.(error); ok1 { 23 | return true 24 | } 25 | } 26 | return false 27 | } 28 | 29 | func newNoMatchedError(results []interface{}) *NoMatchedError { 30 | return &NoMatchedError{results} 31 | } 32 | 33 | func newNoMatchedError1(e interface{}) *NoMatchedError { 34 | return &NoMatchedError{[]interface{}{e}} 35 | } 36 | 37 | //AggregateError aggregate multi errors into an error 38 | type AggregateError struct { 39 | s string 40 | InnerErrs []error 41 | } 42 | 43 | func (e *AggregateError) Error() string { 44 | if e.InnerErrs == nil { 45 | return e.s 46 | } else { 47 | buf := bytes.NewBufferString(e.s) 48 | buf.WriteString("\n\n") 49 | for i, ie := range e.InnerErrs { 50 | if ie == nil { 51 | continue 52 | } 53 | buf.WriteString("error appears in Future ") 54 | buf.WriteString(strconv.Itoa(i)) 55 | buf.WriteString(": ") 56 | buf.WriteString(ie.Error()) 57 | buf.WriteString("\n") 58 | } 59 | buf.WriteString("\n") 60 | return buf.String() 61 | } 62 | } 63 | 64 | func newAggregateError(s string, innerErrors []error) *AggregateError { 65 | return &AggregateError{newErrorWithStacks(s).Error(), innerErrors} 66 | } 67 | 68 | func newAggregateError1(s string, e interface{}) *AggregateError { 69 | return &AggregateError{newErrorWithStacks(s).Error(), []error{getError(e)}} 70 | } 71 | 72 | func newErrorWithStacks(i interface{}) (e error) { 73 | err := getError(i) 74 | buf := bytes.NewBufferString(err.Error()) 75 | buf.WriteString("\n") 76 | 77 | pcs := make([]uintptr, 50) 78 | num := runtime.Callers(2, pcs) 79 | for _, v := range pcs[0:num] { 80 | fun := runtime.FuncForPC(v) 81 | file, line := fun.FileLine(v) 82 | name := fun.Name() 83 | //fmt.Println(name, file + ":", line) 84 | writeStrings(buf, []string{name, " ", file, ":", strconv.Itoa(line), "\n"}) 85 | } 86 | return errors.New(buf.String()) 87 | } 88 | 89 | func getAct(pr *Promise, act interface{}) (f func() (r interface{}, err error)) { 90 | var ( 91 | act1 func() (interface{}, error) 92 | act2 func(Canceller) (interface{}, error) 93 | ) 94 | canCancel := false 95 | 96 | //convert the act to the function that has return value and error if act function haven't return value and error 97 | switch v := act.(type) { 98 | case func() (interface{}, error): 99 | act1 = v 100 | case func(Canceller) (interface{}, error): 101 | canCancel = true 102 | act2 = v 103 | case func(): 104 | act1 = func() (interface{}, error) { 105 | v() 106 | return nil, nil 107 | } 108 | case func(Canceller): 109 | canCancel = true 110 | act2 = func(canceller Canceller) (interface{}, error) { 111 | v(canceller) 112 | return nil, nil 113 | } 114 | default: 115 | if e, ok := v.(error); !ok { 116 | pr.Resolve(v) 117 | } else { 118 | pr.Reject(e) 119 | } 120 | return nil 121 | } 122 | 123 | //If paramters of act function has a Canceller interface, the Future will can be cancelled. 124 | var canceller Canceller = nil 125 | if pr != nil && canCancel { 126 | //pr.EnableCanceller() 127 | canceller = pr.Canceller() 128 | } 129 | 130 | //return proxy function of act function 131 | f = func() (r interface{}, err error) { 132 | defer func() { 133 | if e := recover(); e != nil { 134 | err = newErrorWithStacks(e) 135 | } 136 | }() 137 | 138 | if canCancel { 139 | r, err = act2(canceller) 140 | } else { 141 | r, err = act1() 142 | } 143 | 144 | return 145 | } 146 | return 147 | } 148 | 149 | func startPipe(r *PromiseResult, pipeTask func(v interface{}) *Future, pipePromise *Promise) { 150 | //处理链式异步任务 151 | if pipeTask != nil { 152 | f := pipeTask(r.Result) 153 | f.OnSuccess(func(v interface{}) { 154 | pipePromise.Resolve(v) 155 | }).OnFailure(func(v interface{}) { 156 | pipePromise.Reject(getError(v)) 157 | }) 158 | } 159 | 160 | } 161 | 162 | func getFutureReturnVal(r *PromiseResult) (interface{}, error) { 163 | if r.Typ == RESULT_SUCCESS { 164 | return r.Result, nil 165 | } else if r.Typ == RESULT_FAILURE { 166 | return nil, getError(r.Result) 167 | } else { 168 | return nil, getError(r.Result) //&CancelledError{} 169 | } 170 | } 171 | 172 | //执行回调函数 173 | func execCallback(r *PromiseResult, 174 | dones []func(v interface{}), 175 | fails []func(v interface{}), 176 | always []func(v interface{}), 177 | cancels []func()) { 178 | 179 | if r.Typ == RESULT_CANCELLED { 180 | for _, f := range cancels { 181 | func() { 182 | defer func() { 183 | if e := recover(); e != nil { 184 | err := newErrorWithStacks(e) 185 | fmt.Println("error happens:\n ", err) 186 | } 187 | }() 188 | f() 189 | }() 190 | } 191 | return 192 | } 193 | 194 | var callbacks []func(v interface{}) 195 | if r.Typ == RESULT_SUCCESS { 196 | callbacks = dones 197 | } else { 198 | callbacks = fails 199 | } 200 | 201 | forFs := func(s []func(v interface{})) { 202 | forSlice(s, func(f func(v interface{})) { f(r.Result) }) 203 | } 204 | 205 | forFs(callbacks) 206 | forFs(always) 207 | 208 | } 209 | 210 | func forSlice(s []func(v interface{}), f func(func(v interface{}))) { 211 | for _, e := range s { 212 | func() { 213 | defer func() { 214 | if e := recover(); e != nil { 215 | err := newErrorWithStacks(e) 216 | fmt.Println("error happens:\n ", err) 217 | } 218 | }() 219 | f(e) 220 | }() 221 | } 222 | } 223 | 224 | //Error handling struct and functions------------------------------ 225 | type stringer interface { 226 | String() string 227 | } 228 | 229 | func getError(i interface{}) (e error) { 230 | if i != nil { 231 | switch v := i.(type) { 232 | case error: 233 | e = v 234 | case string: 235 | e = errors.New(v) 236 | default: 237 | if s, ok := i.(stringer); ok { 238 | e = errors.New(s.String()) 239 | } else { 240 | e = errors.New(fmt.Sprintf("%v", i)) 241 | } 242 | } 243 | } 244 | return 245 | } 246 | 247 | func writeStrings(buf *bytes.Buffer, strings []string) { 248 | for _, s := range strings { 249 | buf.WriteString(s) 250 | } 251 | } 252 | --------------------------------------------------------------------------------