[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\n\n# Architecture specific extensions/prefixes\n*.[568vq]\n[568vq].out\n\n*.cgo1.go\n*.cgo2.c\n_cgo_defun.c\n_cgo_gotypes.go\n_cgo_export.*\n\n_testmain.go\n\n*.exe\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2014 fanliao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."
  },
  {
    "path": "README.md",
    "content": "[home]: github.com/fanliao/go-promise\r\n\r\ngo-promise is a Go promise and future library.\r\n\r\nInspired by [Futures and promises]()\r\n\r\n## Installation\r\n\r\n    $ go get github.com/fanliao/go-promise\r\n\r\n## Features\r\n\r\n* Future and Promise\r\n\r\n  * ```NewPromise()```\r\n  * ```promise.Future```\r\n\r\n* Promise and Future callbacks\r\n\r\n  * ```.OnSuccess(v interface{})```\r\n  * ```.OnFailure(v interface{})```\r\n  * ```.OnComplete(v interface{})```\r\n  * ```.OnCancel()```\r\n\r\n* Get the result of future\r\n\r\n  * ```.Get() ```\r\n  * ```.GetOrTimeout()```\r\n  * ```.GetChan()```\r\n\r\n* Set timeout for future\r\n\r\n  * ```.SetTimeout(ms)```\r\n  \r\n* Merge multiple promises\r\n\r\n  * ```WhenAll(func1, func2, func3, ...)```\r\n  * ```WhenAny(func1, func2, func3, ...)```\r\n  * ```WhenAnyMatched(func1, func2, func3, ...)```\r\n\r\n* Pipe\r\n  * ```.Pipe(funcWithDone, funcWithFail)```\r\n\r\n* Cancel the future\r\n\r\n  * ```.Cancel()```\r\n  * ```.IsCancelled()```\r\n\r\n* Create future by function\r\n\r\n  * ```Start(func() (r interface{}, e error))```\r\n  * ```Start(func())```\r\n  * ```Start(func(canceller Canceller) (r interface{}, e error))```\r\n  * ```Start(func(canceller Canceller))```\r\n\r\n* Immediate wrappers\r\n\r\n  * ```Wrap(interface{})```\r\n\r\n* Chain API\r\n\r\n  * ```Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)```\r\n\r\n## Quick start\r\n\r\n### Promise and Future \r\n\r\n```go\r\nimport \"github.com/fanliao/go-promise\"\r\nimport \"net/http\"\r\n\r\np := promise.NewPromise()\r\np.OnSuccess(func(v interface{}) {\r\n   ...\r\n}).OnFailure(func(v interface{}) {\r\n   ...\r\n}).OnComplete(func(v interface{}) {\r\n   ...\r\n})\r\n\r\ngo func(){\r\n\turl := \"http://example.com/\"\r\n\t\r\n\tresp, err := http.Get(url)\r\n\tdefer resp.Body.Close()\r\n\tif err != nil {\r\n\t\tp.Reject(err)\r\n\t}\r\n\t\r\n\tbody, err := ioutil.ReadAll(resp.Body)\r\n\tif err != nil {\r\n\t\tp.Reject(err)\r\n\t}\r\n\tp.Resolve(body)\r\n}()\r\nr, err := p.Get()\r\n```\r\n\r\nIf you want to provide a read-only view, you can get a future variable:\r\n\r\n```go\r\np.Future //cannot Resolve, Reject for a future\r\n```\r\n\r\nCan 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:\r\n\r\n```go\r\nimport \"github.com/fanliao/go-promise\"\r\nimport \"net/http\"\r\n\r\ntask := func()(r interface{}, err error){\r\n\turl := \"http://example.com/\"\r\n\t\r\n\tresp, err := http.Get(url)\r\n\tdefer resp.Body.Close()\r\n\tif err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\t\r\n\tbody, err := ioutil.ReadAll(resp.Body)\r\n\tif err != nil {\r\n\t\treturn nil, err\r\n\t}\r\n\treturn body, nil\r\n}\r\n\r\nf := promise.Start(task).OnSuccess(func(v interface{}) {\r\n   ...\r\n}).OnFailure(func(v interface{}) {\r\n   ...\r\n}).OnComplete(func(v interface{}) {\r\n   ...\r\n})\r\nr, err := f.Get()\r\n```\r\n\r\n### Get the result of future\r\n\r\nPlease note the process will be block until the future task is completed\r\n\r\n```go\r\nf := promise.Start(func() (r interface{}, err error) {\r\n\treturn \"ok\", nil  \r\n})\r\nr, err := f.Get()  //return \"ok\", nil\r\n\r\nf := promise.Start(func() (r interface{}, err error) {\r\n\treturn nil, errors.New(\"fail\")  \r\n})\r\nr, err := f.Get()  //return nil, errorString{\"fail\"}\r\n```\r\n\r\nCan wait until timeout\r\n\r\n```go\r\nf := promise.Start(func() (r interface{}, err error) {\r\n\ttime.Sleep(500 * time.Millisecond)\r\n\treturn \"ok\", nil \r\n})\r\nr, err, timeout := f.GetOrTimeout(100)  //return nil, nil, true\r\n```\r\n\r\n### Merge multiple futures\r\n\r\nCreates a future that will be completed when all of the supplied future are completed.\r\n```go\r\ntask1 := func() (r interface{}, err error) {\r\n\treturn \"ok1\", nil\r\n}\r\ntask2 := func() (r interface{}, err error) {\r\n\treturn \"ok2\", nil\r\n}\r\n\r\nf := promise.WhenAll(task1, task2)\r\nr, err := f.Get()    //return []interface{}{\"ok1\", \"ok2\"}\r\n```\r\n\r\nIf any future is failure, the future returnd by WhenAll will be failure\r\n```go\r\ntask1 := func() (r interface{}, err error)  {\r\n\treturn \"ok\", nil\r\n}\r\ntask2 := func() (r interface{}, err error)  {\r\n\treturn nil, errors.New(\"fail2\")\r\n}\r\nf := promise.WhenAll(task1, task2)\r\nr, ok := f.Get()    //return nil, *AggregateError\r\n```\r\n\r\nCreates a future that will be completed when any of the supplied tasks is completed.\r\n```go\r\ntask1 := func() (r interface{}, err error) {\r\n\treturn \"ok1\", nil\r\n}\r\ntask2 := func() (r interface{}, err error) {\r\n\ttime.Sleep(200 * time.Millisecond)\r\n\treturn nil, errors.New(\"fail2\")\r\n}\r\n\r\nf := promise.WhenAny(task1, task2)\r\nr, err := f.Get()  //return \"ok1\", nil\r\n```\r\n\r\nAlso 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.\r\n```go\r\ntask1 := func() (r interface{}, err error) {\r\n\ttime.Sleep(200 * time.Millisecond)\r\n\treturn \"ok1\", nil\r\n}\r\ntask2 := func() (r interface{}, err error) {\r\n\treturn \"ok2\", nil\r\n}\r\n\r\nf := promise.WhenAnyMatched(func(v interface{}) bool{\r\n\treturn v == \"ok1\"\r\n}, task1, task2)\r\nr, err := f.Get()  //return \"ok1\", nil\r\n```\r\n\r\n### Promise pipelining\r\n\r\n```go\r\ntask1 := func() (r interface{}, err error) {\r\n\treturn 10, nil\r\n}\r\ntask2 := func(v interface{}) (r interface{}, err error) {\r\n\treturn v.(int) * 2, nil\r\n}\r\n\r\nf := promise.Start(task1).Pipe(task2)\r\nr, err := f.Get()   //return 20\r\n```\r\n\r\n### Cancel the future or set timeout\r\n\r\nIf need cancel a future, can pass a canceller object to task function\r\n```go\r\nimport \"github.com/fanliao/go-promise\"\r\nimport \"net/http\"\r\n\r\np := promise.NewPromise().EnableCanceller()\r\n\r\ngo func(canceller promise.Canceller){\r\n\tfor i < 50 {\r\n\t\tif canceller.IsCancelled() {\r\n\t\t\treturn\r\n\t\t}\r\n\t\ttime.Sleep(100 * time.Millisecond)\r\n\t}\r\n}(p.Canceller())\r\nf.Cancel()\r\n\r\nr, err := p.Get()   //return nil, promise.CANCELLED\r\nfmt.Println(p.Future.IsCancelled())      //true\r\n```\r\n\r\nOr can use Start to submit a future task which can be cancelled\r\n```go\r\ntask := func(canceller promise.Canceller) (r interface{}, err error) {\r\n\tfor i < 50 {\r\n\t\tif canceller.IsCancelled() {\r\n\t\t\treturn 0, nil\r\n\t\t}\r\n\t\ttime.Sleep(100 * time.Millisecond)\r\n\t}\r\n\treturn 1, nil\r\n}\r\nf := promise.Start(task1)\r\nf.Cancel()\r\n\r\nr, err := f.Get()   //return nil, promise.CANCELLED\r\nfmt.Println(f.IsCancelled())      //true\r\n```\r\n\r\nWhen 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.\r\n\r\nYou can also set timeout for a future\r\n\r\n```go\r\ntask := func(canceller promise.Canceller) (r interface{}, err error) {\r\n\ttime.Sleep(300 * time.Millisecond)\r\n\tif !canceller.IsCancelled(){\r\n\t\tfmt.Println(\"Run done\")\r\n\t} \r\n\treturn\r\n}\r\n\r\nf := promise.Start(task).OnCancel(func() {\r\n\tfmt.Println(\"Future is cancelled\")\r\n}).SetTimeout(100)\r\n\r\nr, err := f.Get() //return nil, promise.CANCELLED\r\nfmt.Println(f.IsCancelled()) //print true\r\n```\r\n\r\n## Document\r\n\r\n* [GoDoc at godoc.org](http://godoc.org/github.com/fanliao/go-promise)\r\n\r\n## License\r\n\r\ngo-promise is licensed under the MIT Licence, (http://www.apache.org/licenses/LICENSE-2.0.html).\r\n"
  },
  {
    "path": "future.go",
    "content": "/*\nPackage promise provides a complete promise and future implementation.\nA quick start sample:\n\n\nfu := Start(func()(resp interface{}, err error){\n    resp, err = http.Get(\"http://example.com/\")\n    return\n})\n//do somthing...\nresp, err := fu.Get()\n*/\npackage promise\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"sync/atomic\"\n\t\"time\"\n\t\"unsafe\"\n)\n\ntype callbackType int\n\nconst (\n\tCALLBACK_DONE callbackType = iota\n\tCALLBACK_FAIL\n\tCALLBACK_ALWAYS\n\tCALLBACK_CANCEL\n)\n\n//pipe presents a promise that will be chain call\ntype pipe struct {\n\tpipeDoneTask, pipeFailTask func(v interface{}) *Future\n\tpipePromise                *Promise\n}\n\n//getPipe returns piped Future task function and pipe Promise by the status of current Promise.\nfunc (this *pipe) getPipe(isResolved bool) (func(v interface{}) *Future, *Promise) {\n\tif isResolved {\n\t\treturn this.pipeDoneTask, this.pipePromise\n\t} else {\n\t\treturn this.pipeFailTask, this.pipePromise\n\t}\n}\n\n//Canceller is used to check if the future is cancelled\n//It usually be passed to the future task function\n//for future task function can check if the future is cancelled.\ntype Canceller interface {\n\tIsCancelled() bool\n\tCancel()\n}\n\n//canceller provides an implement of Canceller interface.\n//It will be passed to future task function as paramter\ntype canceller struct {\n\tf *Future\n}\n\n//Cancel sets Future task to CANCELLED status\nfunc (this *canceller) Cancel() {\n\tthis.f.Cancel()\n}\n\n//IsCancelled returns true if Future task is cancelld, otherwise false.\nfunc (this *canceller) IsCancelled() (r bool) {\n\treturn this.f.IsCancelled()\n}\n\n//futureVal stores the internal state of Future.\ntype futureVal struct {\n\tdones, fails, always []func(v interface{})\n\tcancels              []func()\n\tpipes                []*pipe\n\tr                    *PromiseResult\n}\n\n//Future provides a read-only view of promise,\n//the value is set by using Resolve, Reject and Cancel methods of related Promise\ntype Future struct {\n\tId    int //Id can be used as identity of Future\n\tfinal chan struct{}\n\t//val point to futureVal that stores status of future\n\t//if need to change the status of future, must copy a new futureVal and modify it,\n\t//then use CAS to put the pointer of new futureVal\n\tval unsafe.Pointer\n}\n\n//Canceller returns a canceller object related to future.\nfunc (this *Future) Canceller() Canceller {\n\treturn &canceller{this}\n}\n\n//IsCancelled returns true if the promise is cancelled, otherwise false\nfunc (this *Future) IsCancelled() bool {\n\tval := this.loadVal()\n\n\tif val != nil && val.r != nil && val.r.Typ == RESULT_CANCELLED {\n\t\treturn true\n\t} else {\n\t\treturn false\n\t}\n}\n\n//SetTimeout sets the future task will be cancelled\n//if future is not complete before time out\nfunc (this *Future) SetTimeout(mm int) *Future {\n\tif mm == 0 {\n\t\tmm = 10\n\t} else {\n\t\tmm = mm * 1000 * 1000\n\t}\n\n\tgo func() {\n\t\t<-time.After((time.Duration)(mm) * time.Nanosecond)\n\t\tthis.Cancel()\n\t}()\n\treturn this\n}\n\n//GetChan returns a channel than can be used to receive result of Promise\nfunc (this *Future) GetChan() <-chan *PromiseResult {\n\tc := make(chan *PromiseResult, 1)\n\tthis.OnComplete(func(v interface{}) {\n\t\tc <- this.loadResult()\n\t}).OnCancel(func() {\n\t\tc <- this.loadResult()\n\t})\n\treturn c\n}\n\n//Get will block current goroutines until the Future is resolved/rejected/cancelled.\n//If Future is resolved, value and nil will be returned\n//If Future is rejected, nil and error will be returned.\n//If Future is cancelled, nil and CANCELLED error will be returned.\nfunc (this *Future) Get() (val interface{}, err error) {\n\t<-this.final\n\treturn getFutureReturnVal(this.loadResult())\n}\n\n//GetOrTimeout is similar to Get(), but GetOrTimeout will not block after timeout.\n//If GetOrTimeout returns with a timeout, timeout value will be true in return values.\n//The unit of paramter is millisecond.\nfunc (this *Future) GetOrTimeout(mm uint) (val interface{}, err error, timout bool) {\n\tif mm == 0 {\n\t\tmm = 10\n\t} else {\n\t\tmm = mm * 1000 * 1000\n\t}\n\n\tselect {\n\tcase <-time.After((time.Duration)(mm) * time.Nanosecond):\n\t\treturn nil, nil, true\n\tcase <-this.final:\n\t\tr, err := getFutureReturnVal(this.loadResult())\n\t\treturn r, err, false\n\t}\n}\n\n//Cancel sets the status of promise to RESULT_CANCELLED.\n//If promise is cancelled, Get() will return nil and CANCELLED error.\n//All callback functions will be not called if Promise is cancalled.\nfunc (this *Future) Cancel() (e error) {\n\treturn this.setResult(&PromiseResult{CANCELLED, RESULT_CANCELLED})\n}\n\n//OnSuccess registers a callback function that will be called when Promise is resolved.\n//If promise is already resolved, the callback will immediately called.\n//The value of Promise will be paramter of Done callback function.\nfunc (this *Future) OnSuccess(callback func(v interface{})) *Future {\n\tthis.addCallback(callback, CALLBACK_DONE)\n\treturn this\n}\n\n//OnFailure registers a callback function that will be called when Promise is rejected.\n//If promise is already rejected, the callback will immediately called.\n//The error of Promise will be paramter of Fail callback function.\nfunc (this *Future) OnFailure(callback func(v interface{})) *Future {\n\tthis.addCallback(callback, CALLBACK_FAIL)\n\treturn this\n}\n\n//OnComplete register a callback function that will be called when Promise is rejected or resolved.\n//If promise is already rejected or resolved, the callback will immediately called.\n//According to the status of Promise, value or error will be paramter of Always callback function.\n//Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected.\n//Always callback will be not called if Promise be called.\nfunc (this *Future) OnComplete(callback func(v interface{})) *Future {\n\tthis.addCallback(callback, CALLBACK_ALWAYS)\n\treturn this\n}\n\n//OnCancel registers a callback function that will be called when Promise is cancelled.\n//If promise is already cancelled, the callback will immediately called.\nfunc (this *Future) OnCancel(callback func()) *Future {\n\tthis.addCallback(callback, CALLBACK_CANCEL)\n\treturn this\n}\n\n//Pipe registers one or two functions that returns a Future, and returns a proxy of pipeline Future.\n//First function will be called when Future is resolved, the returned Future will be as pipeline Future.\n//Secondary function will be called when Futrue is rejected, the returned Future will be as pipeline Future.\nfunc (this *Future) Pipe(callbacks ...interface{}) (result *Future, ok bool) {\n\tif len(callbacks) == 0 ||\n\t\t(len(callbacks) == 1 && callbacks[0] == nil) ||\n\t\t(len(callbacks) > 1 && callbacks[0] == nil && callbacks[1] == nil) {\n\t\tresult = this\n\t\treturn\n\t}\n\n\t//ensure all callback functions match the spec \"func(v interface{}) *Future\"\n\tcs := make([]func(v interface{}) *Future, len(callbacks), len(callbacks))\n\tfor i, callback := range callbacks {\n\t\tif c, ok1 := callback.(func(v interface{}) *Future); ok1 {\n\t\t\tcs[i] = c\n\t\t} else if c, ok1 := callback.(func() *Future); ok1 {\n\t\t\tcs[i] = func(v interface{}) *Future {\n\t\t\t\treturn c()\n\t\t\t}\n\t\t} else if c, ok1 := callback.(func(v interface{})); ok1 {\n\t\t\tcs[i] = func(v interface{}) *Future {\n\t\t\t\treturn Start(func() {\n\t\t\t\t\tc(v)\n\t\t\t\t})\n\t\t\t}\n\t\t} else if c, ok1 := callback.(func(v interface{}) (r interface{}, err error)); ok1 {\n\t\t\tcs[i] = func(v interface{}) *Future {\n\t\t\t\treturn Start(func() (r interface{}, err error) {\n\t\t\t\t\tr, err = c(v)\n\t\t\t\t\treturn\n\t\t\t\t})\n\t\t\t}\n\t\t} else if c, ok1 := callback.(func()); ok1 {\n\t\t\tcs[i] = func(v interface{}) *Future {\n\t\t\t\treturn Start(func() {\n\t\t\t\t\tc()\n\t\t\t\t})\n\t\t\t}\n\t\t} else if c, ok1 := callback.(func() (r interface{}, err error)); ok1 {\n\t\t\tcs[i] = func(v interface{}) *Future {\n\t\t\t\treturn Start(func() (r interface{}, err error) {\n\t\t\t\t\tr, err = c()\n\t\t\t\t\treturn\n\t\t\t\t})\n\t\t\t}\n\t\t} else {\n\t\t\tok = false\n\t\t\treturn\n\t\t}\n\t}\n\n\tfor {\n\t\tv := this.loadVal()\n\t\tr := v.r\n\t\tif r != nil {\n\t\t\tresult = this\n\t\t\tif r.Typ == RESULT_SUCCESS && cs[0] != nil {\n\t\t\t\tresult = (cs[0](r.Result))\n\t\t\t} else if r.Typ == RESULT_FAILURE && len(cs) > 1 && cs[1] != nil {\n\t\t\t\tresult = (cs[1](r.Result))\n\t\t\t}\n\t\t} else {\n\t\t\tnewPipe := &pipe{}\n\t\t\tnewPipe.pipeDoneTask = cs[0]\n\t\t\tif len(cs) > 1 {\n\t\t\t\tnewPipe.pipeFailTask = cs[1]\n\t\t\t}\n\t\t\tnewPipe.pipePromise = NewPromise()\n\n\t\t\tnewVal := *v\n\t\t\tnewVal.pipes = append(newVal.pipes, newPipe)\n\n\t\t\t//use CAS to ensure that the state of Future is not changed,\n\t\t\t//if the state is changed, will retry CAS operation.\n\t\t\tif atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {\n\t\t\t\tresult = newPipe.pipePromise.Future\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\tok = true\n\n\treturn\n}\n\n//result uses Atomic load to return result of the Future\nfunc (this *Future) loadResult() *PromiseResult {\n\tval := this.loadVal()\n\treturn val.r\n}\n\n//val uses Atomic load to return state value of the Future\nfunc (this *Future) loadVal() *futureVal {\n\tr := atomic.LoadPointer(&this.val)\n\treturn (*futureVal)(r)\n}\n\n//setResult sets the value and final status of Promise, it will only be executed for once\nfunc (this *Future) setResult(r *PromiseResult) (e error) { //r *PromiseResult) {\n\tdefer func() {\n\t\tif err := getError(recover()); err != nil {\n\t\t\te = err\n\t\t\tfmt.Println(\"\\nerror in setResult():\", err)\n\t\t}\n\t}()\n\n\te = errors.New(\"Cannot resolve/reject/cancel more than once\")\n\n\tfor {\n\t\tv := this.loadVal()\n\t\tif v.r != nil {\n\t\t\treturn\n\t\t}\n\t\tnewVal := *v\n\t\tnewVal.r = r\n\n\t\t//Use CAS operation to ensure that the state of Promise isn't changed.\n\t\t//If the state is changed, must get latest state and try to call CAS again.\n\t\t//No ABA issue in this case because address of all objects are different.\n\t\tif atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {\n\t\t\t//Close chEnd then all Get() and GetOrTimeout() will be unblocked\n\t\t\tclose(this.final)\n\n\t\t\t//call callback functions and start the Promise pipeline\n\t\t\tif len(v.dones) > 0 || len(v.fails) > 0 || len(v.always) > 0 || len(v.cancels) > 0 {\n\t\t\t\tgo func() {\n\t\t\t\t\texecCallback(r, v.dones, v.fails, v.always, v.cancels)\n\t\t\t\t}()\n\t\t\t}\n\n\t\t\t//start the pipeline\n\t\t\tif len(v.pipes) > 0 {\n\t\t\t\tgo func() {\n\t\t\t\t\tfor _, pipe := range v.pipes {\n\t\t\t\t\t\tpipeTask, pipePromise := pipe.getPipe(r.Typ == RESULT_SUCCESS)\n\t\t\t\t\t\tstartPipe(r, pipeTask, pipePromise)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t}\n\t\t\te = nil\n\t\t\tbreak\n\t\t}\n\t}\n\treturn\n}\n\n//handleOneCallback registers a callback function\nfunc (this *Future) addCallback(callback interface{}, t callbackType) {\n\tif callback == nil {\n\t\treturn\n\t}\n\tif (t == CALLBACK_DONE) ||\n\t\t(t == CALLBACK_FAIL) ||\n\t\t(t == CALLBACK_ALWAYS) {\n\t\tif _, ok := callback.(func(v interface{})); !ok {\n\t\t\tpanic(errors.New(\"Callback function spec must be func(v interface{})\"))\n\t\t}\n\t} else if t == CALLBACK_CANCEL {\n\t\tif _, ok := callback.(func()); !ok {\n\t\t\tpanic(errors.New(\"Callback function spec must be func()\"))\n\t\t}\n\t}\n\n\tfor {\n\t\tv := this.loadVal()\n\t\tr := v.r\n\t\tif r == nil {\n\t\t\tnewVal := *v\n\t\t\tswitch t {\n\t\t\tcase CALLBACK_DONE:\n\t\t\t\tnewVal.dones = append(newVal.dones, callback.(func(v interface{})))\n\t\t\tcase CALLBACK_FAIL:\n\t\t\t\tnewVal.fails = append(newVal.fails, callback.(func(v interface{})))\n\t\t\tcase CALLBACK_ALWAYS:\n\t\t\t\tnewVal.always = append(newVal.always, callback.(func(v interface{})))\n\t\t\tcase CALLBACK_CANCEL:\n\t\t\t\tnewVal.cancels = append(newVal.cancels, callback.(func()))\n\t\t\t}\n\n\t\t\t//use CAS to ensure that the state of Future is not changed,\n\t\t\t//if the state is changed, will retry CAS operation.\n\t\t\tif atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {\n\t\t\t\tbreak\n\t\t\t}\n\t\t} else {\n\t\t\tif (t == CALLBACK_DONE && r.Typ == RESULT_SUCCESS) ||\n\t\t\t\t(t == CALLBACK_FAIL && r.Typ == RESULT_FAILURE) ||\n\t\t\t\t(t == CALLBACK_ALWAYS && r.Typ != RESULT_CANCELLED) {\n\t\t\t\tcallbackFunc := callback.(func(v interface{}))\n\t\t\t\tcallbackFunc(r.Result)\n\t\t\t} else if t == CALLBACK_CANCEL && r.Typ == RESULT_CANCELLED {\n\t\t\t\tcallbackFunc := callback.(func())\n\t\t\t\tcallbackFunc()\n\t\t\t}\n\t\t\tbreak\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "future_factory.go",
    "content": "package promise\n\nimport (\n\t\"sync/atomic\"\n)\n\ntype anyPromiseResult struct {\n\tresult interface{}\n\ti      int\n}\n\n//Start start a goroutines to execute task function\n//and return a Future that presents the result.\n//If option paramter is true, the act function will be sync called.\n//Type of act can be any of below four types:\n//  func() (r interface{}, err error):\n//     if err returned by act != nil or panic error, then Future will be rejected with error,\n//     otherwise be resolved with r.\n//  func():\n//     if act panic error, then Future will be rejected, otherwise be resolved with nil.\n//  func(c promise.Canceller) (r interface{}, err error):\n//     if err returned by act != nil or panic error,\n//     then Future will be rejected with err, otherwise be resolved with r.\n//     We can check c.IsCancelled() to decide whether need to exit act function\n//  func(promise.Canceller):\n//     if act panic error, then Future will be rejected with error, otherwise be resolved with nil.\n//     We can check c.IsCancelled() to decide whether need to exit act function.\n//  error:\n//     Future will be rejected with error immediately\n//  other value:\n//     Future will be resolved with value immediately\nfunc Start(act interface{}, syncs ...bool) *Future {\n\tpr := NewPromise()\n\tif f, ok := act.(*Future); ok {\n\t\treturn f\n\t}\n\n\tif action := getAct(pr, act); action != nil {\n\t\tif syncs != nil && len(syncs) > 0 && !syncs[0] {\n\t\t\t//sync call\n\t\t\tr, err := action()\n\t\t\tif pr.IsCancelled() {\n\t\t\t\tpr.Cancel()\n\t\t\t} else {\n\t\t\t\tif err == nil {\n\t\t\t\t\tpr.Resolve(r)\n\t\t\t\t} else {\n\t\t\t\t\tpr.Reject(err)\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t//async call\n\t\t\tgo func() {\n\t\t\t\tr, err := action()\n\t\t\t\tif pr.IsCancelled() {\n\t\t\t\t\tpr.Cancel()\n\t\t\t\t} else {\n\t\t\t\t\tif err == nil {\n\t\t\t\t\t\tpr.Resolve(r)\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpr.Reject(err)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\t\t}\n\t}\n\n\treturn pr.Future\n}\n\n//Wrap return a Future that presents the wrapped value\nfunc Wrap(value interface{}) *Future {\n\tpr := NewPromise()\n\tif e, ok := value.(error); !ok {\n\t\tpr.Resolve(value)\n\t} else {\n\t\tpr.Reject(e)\n\t}\n\n\treturn pr.Future\n}\n\n//WhenAny returns a Future.\n//If any Future is resolved, this Future will be resolved and return result of resolved Future.\n//Otherwise will rejected with results slice returned by all Futures\n//Legit types of act are same with Start function\nfunc WhenAny(acts ...interface{}) *Future {\n\treturn WhenAnyMatched(nil, acts...)\n}\n\n//WhenAnyMatched returns a Future.\n//If any Future is resolved and match the predicate, this Future will be resolved and return result of resolved Future.\n//If all Futures are cancelled, this Future will be cancelled.\n//Otherwise will rejected with a NoMatchedError included results slice returned by all Futures\n//Legit types of act are same with Start function\nfunc WhenAnyMatched(predicate func(interface{}) bool, acts ...interface{}) *Future {\n\tif predicate == nil {\n\t\tpredicate = func(v interface{}) bool { return true }\n\t}\n\n\tfs := make([]*Future, len(acts))\n\tfor i, act := range acts {\n\t\tfs[i] = Start(act)\n\t}\n\n\tnf, rs := NewPromise(), make([]interface{}, len(fs))\n\tif len(acts) == 0 {\n\t\tnf.Resolve(nil)\n\t}\n\n\tchFails, chDones := make(chan anyPromiseResult), make(chan anyPromiseResult)\n\n\tgo func() {\n\t\tfor i, f := range fs {\n\t\t\tk := i\n\t\t\tf.OnSuccess(func(v interface{}) {\n\t\t\t\tdefer func() { _ = recover() }()\n\t\t\t\tchDones <- anyPromiseResult{v, k}\n\t\t\t}).OnFailure(func(v interface{}) {\n\t\t\t\tdefer func() { _ = recover() }()\n\t\t\t\tchFails <- anyPromiseResult{v, k}\n\t\t\t}).OnCancel(func() {\n\t\t\t\tdefer func() { _ = recover() }()\n\t\t\t\tchFails <- anyPromiseResult{CANCELLED, k}\n\t\t\t})\n\t\t}\n\t}()\n\n\tif len(fs) == 1 {\n\t\tselect {\n\t\tcase r := <-chFails:\n\t\t\tif _, ok := r.result.(CancelledError); ok {\n\t\t\t\tnf.Cancel()\n\t\t\t} else {\n\t\t\t\tnf.Reject(newNoMatchedError1(r.result))\n\t\t\t}\n\t\tcase r := <-chDones:\n\t\t\tif predicate(r.result) {\n\t\t\t\tnf.Resolve(r.result)\n\t\t\t} else {\n\t\t\t\tnf.Reject(newNoMatchedError1(r.result))\n\t\t\t}\n\t\t}\n\t} else {\n\t\tgo func() {\n\t\t\tdefer func() {\n\t\t\t\tif e := recover(); e != nil {\n\t\t\t\t\tnf.Reject(newErrorWithStacks(e))\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tj := 0\n\t\t\tfor {\n\t\t\t\tselect {\n\t\t\t\tcase r := <-chFails:\n\t\t\t\t\trs[r.i] = getError(r.result)\n\t\t\t\tcase r := <-chDones:\n\t\t\t\t\tif predicate(r.result) {\n\t\t\t\t\t\t//try to cancel other futures\n\t\t\t\t\t\tfor _, f := range fs {\n\t\t\t\t\t\t\tf.Cancel()\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t//close the channel for avoid the send side be blocked\n\t\t\t\t\t\tcloseChan := func(c chan anyPromiseResult) {\n\t\t\t\t\t\t\tdefer func() { _ = recover() }()\n\t\t\t\t\t\t\tclose(c)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcloseChan(chDones)\n\t\t\t\t\t\tcloseChan(chFails)\n\n\t\t\t\t\t\t//Resolve the future and return result\n\t\t\t\t\t\tnf.Resolve(r.result)\n\t\t\t\t\t\treturn\n\t\t\t\t\t} else {\n\t\t\t\t\t\trs[r.i] = r.result\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif j++; j == len(fs) {\n\t\t\t\t\tm := 0\n\t\t\t\t\tfor _, r := range rs {\n\t\t\t\t\t\tswitch val := r.(type) {\n\t\t\t\t\t\tcase CancelledError:\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tm++\n\t\t\t\t\t\t\t_ = val\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif m > 0 {\n\t\t\t\t\t\tnf.Reject(newNoMatchedError(rs))\n\t\t\t\t\t} else {\n\t\t\t\t\t\tnf.Cancel()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}()\n\t}\n\treturn nf.Future\n}\n\n//WhenAll receives function slice and returns a Future.\n//If all Futures are resolved, this Future will be resolved and return results slice.\n//Otherwise will rejected with results slice returned by all Futures\n//Legit types of act are same with Start function\nfunc WhenAll(acts ...interface{}) (fu *Future) {\n\tpr := NewPromise()\n\tfu = pr.Future\n\n\tif len(acts) == 0 {\n\t\tpr.Resolve([]interface{}{})\n\t\treturn\n\t}\n\n\tfs := make([]*Future, len(acts))\n\tfor i, act := range acts {\n\t\tfs[i] = Start(act)\n\t}\n\tfu = whenAllFuture(fs...)\n\treturn\n}\n\n//WhenAll receives Futures slice and returns a Future.\n//If all Futures are resolved, this Future will be resolved and return results slice.\n//If any Future is cancelled, this Future will be cancelled.\n//Otherwise will rejected with results slice returned by all Futures.\n//Legit types of act are same with Start function\nfunc whenAllFuture(fs ...*Future) *Future {\n\twf := NewPromise()\n\trs := make([]interface{}, len(fs))\n\n\tif len(fs) == 0 {\n\t\twf.Resolve([]interface{}{})\n\t} else {\n\t\tn := int32(len(fs))\n\t\tcancelOthers := func(j int) {\n\t\t\tfor k, f1 := range fs {\n\t\t\t\tif k != j {\n\t\t\t\t\tf1.Cancel()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tgo func() {\n\t\t\tisCancelled := int32(0)\n\t\t\tfor i, f := range fs {\n\t\t\t\tj := i\n\n\t\t\t\tf.OnSuccess(func(v interface{}) {\n\t\t\t\t\trs[j] = v\n\t\t\t\t\tif atomic.AddInt32(&n, -1) == 0 {\n\t\t\t\t\t\twf.Resolve(rs)\n\t\t\t\t\t}\n\t\t\t\t}).OnFailure(func(v interface{}) {\n\t\t\t\t\tif atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {\n\t\t\t\t\t\t//try to cancel all futures\n\t\t\t\t\t\tcancelOthers(j)\n\n\t\t\t\t\t\t//errs := make([]error, 0, 1)\n\t\t\t\t\t\t//errs = append(errs, v.(error))\n\t\t\t\t\t\te := newAggregateError1(\"Error appears in WhenAll:\", v)\n\t\t\t\t\t\twf.Reject(e)\n\t\t\t\t\t}\n\t\t\t\t}).OnCancel(func() {\n\t\t\t\t\tif atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {\n\t\t\t\t\t\t//try to cancel all futures\n\t\t\t\t\t\tcancelOthers(j)\n\n\t\t\t\t\t\twf.Cancel()\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t}\n\t\t}()\n\t}\n\n\treturn wf.Future\n}\n"
  },
  {
    "path": "future_test.go",
    "content": "package promise\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\tc \"github.com/smartystreets/goconvey/convey\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"testing\"\n\t\"time\"\n)\n\nconst (\n\tTASK_END      = \"task be end,\"\n\tCALL_DONE     = \"callback done,\"\n\tCALL_FAIL     = \"callback fail,\"\n\tCALL_ALWAYS   = \"callback always,\"\n\tWAIT_TASK     = \"wait task end,\"\n\tGET           = \"get task result,\"\n\tDONE_Pipe_END = \"task Pipe done be end,\"\n\tFAIL_Pipe_END = \"task Pipe fail be end,\"\n)\n\n// errorLinq is a trivial implementation of error.\ntype myError struct {\n\tval interface{}\n}\n\nfunc (e *myError) Error() string {\n\treturn fmt.Sprintf(\"%v\", e.val)\n}\n\nfunc newMyError(v interface{}) *myError {\n\treturn &myError{v}\n}\n\nfunc TestResolveAndReject(t *testing.T) {\n\tc.Convey(\"When Promise is resolved\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\tp.Resolve(\"ok\")\n\t\t}()\n\t\tc.Convey(\"Should return the argument of Resolve\", func() {\n\t\t\tr, err := p.Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"When Promise is rejected\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\tp.Reject(errors.New(\"fail\"))\n\t\t}()\n\t\tc.Convey(\"Should return error\", func() {\n\t\t\tr, err := p.Get()\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t\tc.So(r, c.ShouldEqual, nil)\n\t\t})\n\t})\n}\n\nfunc TestCancel(t *testing.T) {\n\tc.Convey(\"When Promise is cancelled\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\tp.Cancel()\n\t\t}()\n\n\t\tc.Convey(\"Should return CancelledError\", func() {\n\t\t\tr, err := p.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(p.IsCancelled(), c.ShouldBeTrue)\n\t\t})\n\t})\n}\n\nfunc TestGetOrTimeout(t *testing.T) {\n\ttimout := 50 * time.Millisecond\n\tc.Convey(\"When Promise is unfinished\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Resolve(\"ok\")\n\t\t}()\n\t\tc.Convey(\"timeout should be true\", func() {\n\t\t\tr, err, timeout := p.GetOrTimeout(10)\n\t\t\tc.So(timeout, c.ShouldBeTrue)\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When Promise is resolved, the argument of Resolve should be returned\", func() {\n\t\t\tr, err, timeout := p.GetOrTimeout(50)\n\t\t\tc.So(timeout, c.ShouldBeFalse)\n\t\t\tc.So(r, c.ShouldEqual, \"ok\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"When Promise is rejected\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Reject(errors.New(\"fail\"))\n\t\t}()\n\t\tc.Convey(\"Should return error\", func() {\n\t\t\tr, err, timeout := p.GetOrTimeout(83)\n\t\t\tc.So(timeout, c.ShouldBeFalse)\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"When Promise is cancelled\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Cancel()\n\t\t}()\n\t\tc.Convey(\"Should return CancelledError\", func() {\n\t\t\tr, err, timeout := p.GetOrTimeout(83)\n\t\t\tc.So(timeout, c.ShouldBeFalse)\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(p.IsCancelled(), c.ShouldBeTrue)\n\t\t})\n\t})\n}\n\nfunc TestGetChan(t *testing.T) {\n\ttimout := 50 * time.Millisecond\n\tc.Convey(\"When Promise is resolved\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Resolve(\"ok\")\n\t\t}()\n\t\tc.Convey(\"Should receive the argument of Resolve from returned channel\", func() {\n\t\t\tfr, ok := <-p.GetChan()\n\t\t\tc.So(fr.Result, c.ShouldEqual, \"ok\")\n\t\t\tc.So(fr.Typ, c.ShouldEqual, RESULT_SUCCESS)\n\t\t\tc.So(ok, c.ShouldBeTrue)\n\t\t})\n\t})\n\n\tc.Convey(\"When Promise is rejected\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Reject(errors.New(\"fail\"))\n\t\t}()\n\t\tc.Convey(\"Should receive error from returned channel\", func() {\n\t\t\tfr, ok := <-p.GetChan()\n\t\t\tc.So(fr.Result, c.ShouldNotBeNil)\n\t\t\tc.So(fr.Typ, c.ShouldEqual, RESULT_FAILURE)\n\t\t\tc.So(ok, c.ShouldBeTrue)\n\t\t})\n\t})\n\n\tc.Convey(\"When Promise is cancelled\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Cancel()\n\t\t}()\n\t\tc.Convey(\"Should receive CancelledError from returned channel\", func() {\n\t\t\tfr, ok := <-p.GetChan()\n\t\t\tc.So(fr.Result, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(p.IsCancelled(), c.ShouldBeTrue)\n\t\t\tc.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED)\n\t\t\tc.So(ok, c.ShouldBeTrue)\n\t\t})\n\n\t\tc.Convey(\"Should receive CancelledError from returned channel at second time\", func() {\n\t\t\tfr, ok := <-p.GetChan()\n\t\t\tc.So(fr.Result, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(p.IsCancelled(), c.ShouldBeTrue)\n\t\t\tc.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED)\n\t\t\tc.So(ok, c.ShouldBeTrue)\n\t\t})\n\t})\n}\n\nfunc TestFuture(t *testing.T) {\n\tc.Convey(\"Future can receive return value and status but cannot change the status\", t, func() {\n\t\tvar fu *Future\n\t\tc.Convey(\"When Future is resolved\", func() {\n\t\t\tfunc() {\n\t\t\t\tp := NewPromise()\n\t\t\t\tgo func() {\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tp.Resolve(\"ok\")\n\t\t\t\t}()\n\t\t\t\tfu = p.Future\n\t\t\t}()\n\t\t\tr, err := fu.Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When Future is rejected\", func() {\n\t\t\tfunc() {\n\t\t\t\tp := NewPromise()\n\t\t\t\tgo func() {\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tp.Reject(errors.New(\"fail\"))\n\t\t\t\t}()\n\t\t\t\tfu = p.Future\n\t\t\t}()\n\t\t\tr, err := fu.Get()\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t\tc.So(r, c.ShouldEqual, nil)\n\t\t})\n\n\t\tc.Convey(\"When Future is cancelled\", func() {\n\t\t\tfunc() {\n\t\t\t\tp := NewPromise()\n\t\t\t\tgo func() {\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tp.Cancel()\n\t\t\t\t}()\n\t\t\t\tfu = p.Future\n\t\t\t}()\n\t\t\tr, err := fu.Get()\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t\tc.So(r, c.ShouldEqual, nil)\n\t\t})\n\t})\n\n}\n\nfunc TestCallbacks(t *testing.T) {\n\ttimout := 50 * time.Millisecond\n\tdone, always, fail, cancel := false, false, false, false\n\n\tp := NewPromise()\n\tgo func() {\n\t\t<-time.After(timout)\n\t\tp.Resolve(\"ok\")\n\t}()\n\n\tc.Convey(\"When Promise is resolved\", t, func() {\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t\tc.Convey(\"The argument of Done should be 'ok'\", t, func() {\n\t\t\t\tc.So(v, c.ShouldEqual, \"ok\")\n\t\t\t})\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t\tc.Convey(\"The argument of Always should be 'ok'\", t, func() {\n\t\t\t\tc.So(v, c.ShouldEqual, \"ok\")\n\t\t\t})\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t\tpanic(\"Unexpected calling\")\n\t\t})\n\t\tr, err := p.Get()\n\n\t\t//The code after Get() and the callback will be concurrent run\n\t\t//So sleep 52 ms to wait all callback be done\n\t\ttime.Sleep(52 * time.Millisecond)\n\n\t\tc.Convey(\"Should call the Done and Always callbacks\", func() {\n\t\t\tc.So(r, c.ShouldEqual, \"ok\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t\tc.So(done, c.ShouldEqual, true)\n\t\t\tc.So(always, c.ShouldEqual, true)\n\t\t\tc.So(fail, c.ShouldEqual, false)\n\t\t})\n\t})\n\n\tc.Convey(\"When adding the callback after Promise is resolved\", t, func() {\n\t\tdone, always, fail := false, false, false\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t\tc.Convey(\"The argument of Done should be 'ok'\", func() {\n\t\t\t\tc.So(v, c.ShouldEqual, \"ok\")\n\t\t\t})\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t\tc.Convey(\"The argument of Always should be 'ok'\", func() {\n\t\t\t\tc.So(v, c.ShouldEqual, \"ok\")\n\t\t\t})\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t\tpanic(\"Unexpected calling\")\n\t\t})\n\t\tc.Convey(\"Should immediately run the Done and Always callbacks\", func() {\n\t\t\tc.So(done, c.ShouldEqual, true)\n\t\t\tc.So(always, c.ShouldEqual, true)\n\t\t\tc.So(fail, c.ShouldEqual, false)\n\t\t})\n\t})\n\n\tvar e *error = nil\n\tdone, always, fail = false, false, false\n\tp = NewPromise()\n\tgo func() {\n\t\t<-time.After(timout)\n\t\tp.Reject(errors.New(\"fail\"))\n\t}()\n\n\tc.Convey(\"When Promise is rejected\", t, func() {\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t\tpanic(\"Unexpected calling\")\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t\tc.Convey(\"The argument of Always should be error\", t, func() {\n\t\t\t\tc.So(v, c.ShouldImplement, e)\n\t\t\t})\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t\tc.Convey(\"The argument of Fail should be error\", t, func() {\n\t\t\t\tc.So(v, c.ShouldImplement, e)\n\t\t\t})\n\t\t})\n\t\tr, err := p.Get()\n\n\t\ttime.Sleep(52 * time.Millisecond)\n\n\t\tc.Convey(\"Should call the Fail and Always callbacks\", func() {\n\t\t\tc.So(r, c.ShouldEqual, nil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t\tc.So(done, c.ShouldEqual, false)\n\t\t\tc.So(always, c.ShouldEqual, true)\n\t\t\tc.So(fail, c.ShouldEqual, true)\n\t\t})\n\t})\n\n\tc.Convey(\"When adding the callback after Promise is rejected\", t, func() {\n\t\tdone, always, fail = false, false, false\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t\tpanic(\"Unexpected calling\")\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t\tc.Convey(\"The argument of Always should be error\", func() {\n\t\t\t\tc.So(v, c.ShouldImplement, e)\n\t\t\t})\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t\tc.Convey(\"The argument of Fail should be error\", func() {\n\t\t\t\tc.So(v, c.ShouldImplement, e)\n\t\t\t})\n\t\t})\n\t\tc.Convey(\"Should immediately run the Fail and Always callbacks\", func() {\n\t\t\tc.So(done, c.ShouldEqual, false)\n\t\t\tc.So(always, c.ShouldEqual, true)\n\t\t\tc.So(fail, c.ShouldEqual, true)\n\t\t})\n\t})\n\n\tdone, always, fail = false, false, false\n\tp = NewPromise()\n\tgo func() {\n\t\t<-time.After(timout)\n\t\tp.Cancel()\n\t}()\n\n\tc.Convey(\"When Promise is cancelled\", t, func() {\n\t\tdone, always, fail, cancel = false, false, false, false\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t}).OnCancel(func() {\n\t\t\tcancel = true\n\t\t})\n\t\tr, err := p.Get()\n\n\t\ttime.Sleep(62 * time.Millisecond)\n\n\t\tc.Convey(\"Only cancel callback be called\", func() {\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t\tc.So(done, c.ShouldEqual, false)\n\t\t\tc.So(always, c.ShouldEqual, false)\n\t\t\tc.So(fail, c.ShouldEqual, false)\n\t\t\tc.So(cancel, c.ShouldEqual, true)\n\t\t})\n\t})\n\n\tc.Convey(\"When adding the callback after Promise is cancelled\", t, func() {\n\t\tdone, always, fail, cancel = false, false, false, false\n\t\tp.OnSuccess(func(v interface{}) {\n\t\t\tdone = true\n\t\t}).OnComplete(func(v interface{}) {\n\t\t\talways = true\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tfail = true\n\t\t}).OnCancel(func() {\n\t\t\tcancel = true\n\t\t})\n\t\tc.Convey(\"Should not call any callbacks\", func() {\n\t\t\tc.So(done, c.ShouldEqual, false)\n\t\t\tc.So(always, c.ShouldEqual, false)\n\t\t\tc.So(fail, c.ShouldEqual, false)\n\t\t\tc.So(cancel, c.ShouldEqual, true)\n\t\t})\n\t})\n\n}\n\nfunc TestStart(t *testing.T) {\n\n\tc.Convey(\"Test start func()\", t, func() {\n\t\tc.Convey(\"When task completed\", func() {\n\t\t\tf := Start(func() {})\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\t\tc.Convey(\"When task panic error\", func() {\n\t\t\tf := Start(func() { panic(\"fail\") })\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"Test start func()(interface{}, error)\", t, func() {\n\t\tc.Convey(\"When task completed\", func() {\n\t\t\tf := Start(func() (interface{}, error) {\n\t\t\t\ttime.Sleep(10)\n\t\t\t\treturn \"ok\", nil\n\t\t\t})\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When task returned error\", func() {\n\t\t\tf := Start(func() (interface{}, error) {\n\t\t\t\ttime.Sleep(10)\n\t\t\t\treturn \"fail\", errors.New(\"fail\")\n\t\t\t})\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\n\t\tc.Convey(\"When task panic error\", func() {\n\t\t\tf := Start(func() (interface{}, error) { panic(\"fail\") })\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"Test start func(canceller Canceller)\", t, func() {\n\t\tc.Convey(\"When task completed\", func() {\n\t\t\tf := Start(func(canceller Canceller) {\n\t\t\t\ttime.Sleep(10)\n\t\t\t})\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When task be cancelled\", func() {\n\t\t\tf := Start(func(canceller Canceller) {\n\t\t\t\ttime.Sleep(10)\n\t\t\t\tif canceller.IsCancelled() {\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t})\n\t\t\tf.Cancel()\n\t\t\tr, err := f.Get()\n\t\t\tc.So(f.IsCancelled(), c.ShouldBeTrue)\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(f.IsCancelled(), c.ShouldBeTrue)\n\t\t})\n\t\tc.Convey(\"When task panic error\", func() {\n\t\t\tf := Start(func(canceller Canceller) { panic(\"fail\") })\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"Test start func(canceller Canceller)(interface{}, error)\", t, func() {\n\t\tc.Convey(\"When task be cancenlled\", func() {\n\t\t\ttask := func(canceller Canceller) (interface{}, error) {\n\t\t\t\ti := 0\n\t\t\t\tfor i < 50 {\n\t\t\t\t\tif canceller.IsCancelled() {\n\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t}\n\t\t\t\t\ttime.Sleep(100 * time.Millisecond)\n\t\t\t\t}\n\t\t\t\tpanic(\"exception\")\n\t\t\t}\n\n\t\t\tf := Start(task)\n\t\t\tf.Cancel()\n\t\t\tr, err := f.Get()\n\n\t\t\tc.So(f.IsCancelled(), c.ShouldBeTrue)\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldEqual, CANCELLED)\n\t\t\tc.So(f.IsCancelled(), c.ShouldBeTrue)\n\t\t})\n\n\t\tc.Convey(\"When task panic error\", func() {\n\t\t\tf := Start(func(canceller Canceller) (interface{}, error) {\n\t\t\t\tpanic(\"fail\")\n\t\t\t})\n\t\t\tr, err := f.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldNotBeNil)\n\t\t})\n\t})\n\n}\n\nfunc TestPipe(t *testing.T) {\n\ttimout := 50 * time.Millisecond\n\ttaskDonePipe := func(v interface{}) *Future {\n\t\treturn Start(func() (interface{}, error) {\n\t\t\t<-time.After(timout)\n\t\t\treturn v.(string) + \"2\", nil\n\t\t})\n\t}\n\n\ttaskFailPipe := func() (interface{}, error) {\n\t\t<-time.After(timout)\n\t\treturn \"fail2\", nil\n\t}\n\n\tc.Convey(\"When task completed\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Resolve(\"ok\")\n\t\t}()\n\t\tfu, ok := p.Pipe(taskDonePipe, taskFailPipe)\n\t\tr, err := fu.Get()\n\t\tc.Convey(\"the done callback will be called, the future returned by done callback will be returned as chain future\", func() {\n\t\t\tc.So(r, c.ShouldEqual, \"ok2\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t\tc.So(ok, c.ShouldEqual, true)\n\t\t})\n\t})\n\n\tc.Convey(\"When task failed\", t, func() {\n\t\tp := NewPromise()\n\t\tgo func() {\n\t\t\t<-time.After(timout)\n\t\t\tp.Reject(errors.New(\"fail\"))\n\t\t}()\n\t\tfu, ok := p.Pipe(taskDonePipe, taskFailPipe)\n\t\tr, err := fu.Get()\n\n\t\tc.Convey(\"the fail callback will be called, the future returned by fail callback will be returned as chain future\", func() {\n\t\t\tc.So(r, c.ShouldEqual, \"fail2\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t\tc.So(ok, c.ShouldEqual, true)\n\t\t})\n\t})\n\n\tc.Convey(\"Test pipe twice\", t, func() {\n\t\tp := NewPromise()\n\t\tpipeFuture1, ok1 := p.Pipe(taskDonePipe, taskFailPipe)\n\t\tc.Convey(\"Calling Pipe succeed at first time\", func() {\n\t\t\tc.So(ok1, c.ShouldEqual, true)\n\t\t})\n\t\tpipeFuture2, ok2 := p.Pipe(taskDonePipe, taskFailPipe)\n\t\tc.Convey(\"Calling Pipe succeed at second time\", func() {\n\t\t\tc.So(ok2, c.ShouldEqual, true)\n\t\t})\n\t\tp.Resolve(\"ok\")\n\n\t\tr, _ := pipeFuture1.Get()\n\t\tc.Convey(\"Pipeline future 1 should return ok2\", func() {\n\t\t\tc.So(r, c.ShouldEqual, \"ok2\")\n\t\t})\n\n\t\tr2, _ := pipeFuture2.Get()\n\t\tc.Convey(\"Pipeline future 2 should return ok2\", func() {\n\t\t\tc.So(r2, c.ShouldEqual, \"ok2\")\n\t\t})\n\t})\n}\n\nfunc TestWhenAny(t *testing.T) {\n\tc.Convey(\"Test WhenAny\", t, func() {\n\t\twhenAnyTasks := func(t1 int, t2 int) *Future {\n\t\t\ttimeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}\n\t\t\tgetTask := func(i int) func() (interface{}, error) {\n\t\t\t\treturn func() (interface{}, error) {\n\t\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\t\ttime.Sleep(timeouts[i] * time.Millisecond)\n\t\t\t\t\t\treturn \"ok\" + strconv.Itoa(i), nil\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttime.Sleep((-1 * timeouts[i]) * time.Millisecond)\n\t\t\t\t\t\treturn nil, newMyError(\"fail\" + strconv.Itoa(i))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttask0 := getTask(0)\n\t\t\ttask1 := getTask(1)\n\t\t\tf := WhenAny(task0, task1)\n\t\t\treturn f\n\t\t}\n\n\t\tc.Convey(\"When all tasks completed, and task 1 be first to complete\", func() {\n\t\t\tr, err := whenAnyTasks(200, 250).Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok0\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When all tasks completed, and task 2 be first to complete\", func() {\n\t\t\tr, err := whenAnyTasks(280, 250).Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok1\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When all tasks failed\", func() {\n\t\t\tr, err := whenAnyTasks(-280, -250).Get()\n\t\t\terrs := err.(*NoMatchedError).Results\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(errs[0].(*myError).val, c.ShouldEqual, \"fail0\")\n\t\t\tc.So(errs[1].(*myError).val, c.ShouldEqual, \"fail1\")\n\t\t})\n\n\t\tc.Convey(\"When one task completed\", func() {\n\t\t\tr, err := whenAnyTasks(-280, 150).Get()\n\t\t\tc.So(r, c.ShouldEqual, \"ok1\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When no task be passed\", func() {\n\t\t\tr, err := WhenAny().Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\t})\n\n\tc.Convey(\"Test WhenAny, and task can be cancelled\", t, func() {\n\t\tvar c1, c2 bool\n\t\twhenAnyCanCancelTasks := func(t1 int, t2 int) *Future {\n\t\t\ttimeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}\n\t\t\tgetTask := func(i int) func(canceller Canceller) (interface{}, error) {\n\t\t\t\treturn func(canceller Canceller) (interface{}, error) {\n\t\t\t\t\tfor j := 0; j < 10; j++ {\n\t\t\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\t\t\ttime.Sleep(timeouts[i] * time.Millisecond)\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ttime.Sleep((-1 * timeouts[i]) * time.Millisecond)\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif canceller.IsCancelled() {\n\t\t\t\t\t\t\tif i == 0 {\n\t\t\t\t\t\t\t\tc1 = true\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tc2 = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\t\treturn \"ok\" + strconv.Itoa(i), nil\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn nil, newMyError(\"fail\" + strconv.Itoa(i))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttask0 := getTask(0)\n\t\t\ttask1 := getTask(1)\n\t\t\tf := WhenAny(Start(task0), Start(task1))\n\t\t\treturn f\n\t\t}\n\t\tc.Convey(\"When task 1 is the first to complete, task 2 will be cancelled\", func() {\n\t\t\tr, err := whenAnyCanCancelTasks(10, 250).Get()\n\n\t\t\tc.So(r, c.ShouldEqual, \"ok0\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tc.So(c2, c.ShouldEqual, true)\n\t\t})\n\n\t\tc.Convey(\"When task 2 is the first to complete, task 1 will be cancelled\", func() {\n\t\t\tr, err := whenAnyCanCancelTasks(200, 10).Get()\n\n\t\t\tc.So(r, c.ShouldEqual, \"ok1\")\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t\ttime.Sleep(1000 * time.Millisecond)\n\t\t\tc.So(c1, c.ShouldEqual, true)\n\t\t})\n\n\t})\n}\n\nfunc TestWhenAnyTrue(t *testing.T) {\n\tc1, c2 := false, false\n\tstartTwoCanCancelTask := func(t1 int, t2 int, predicate func(interface{}) bool) *Future {\n\t\ttimeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}\n\t\tgetTask := func(i int) func(canceller Canceller) (interface{}, error) {\n\t\t\treturn func(canceller Canceller) (interface{}, error) {\n\t\t\t\tfor j := 0; j < 10; j++ {\n\t\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\t\ttime.Sleep(timeouts[i] * time.Millisecond)\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttime.Sleep((-1 * timeouts[i]) * time.Millisecond)\n\t\t\t\t\t}\n\t\t\t\t\tif canceller.IsCancelled() {\n\t\t\t\t\t\tif i == 0 {\n\t\t\t\t\t\t\tc1 = true\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tc2 = true\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\treturn \"ok\" + strconv.Itoa(i), nil\n\t\t\t\t} else {\n\t\t\t\t\treturn nil, newMyError(\"fail\" + strconv.Itoa(i))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttask0 := getTask(0)\n\t\ttask1 := getTask(1)\n\t\tf := WhenAnyMatched(predicate, Start(task0), Start(task1))\n\t\treturn f\n\t}\n\t//第一个任务先完成，第二个后完成，并且设定条件为返回值==第一个的返回值\n\tc.Convey(\"When the task1 is the first to complete, and predicate returns true\", t, func() {\n\t\tr, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool {\n\t\t\treturn v.(string) == \"ok0\"\n\t\t}).Get()\n\t\tc.So(r, c.ShouldEqual, \"ok0\")\n\t\tc.So(err, c.ShouldBeNil)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tc.So(c2, c.ShouldEqual, true)\n\t})\n\n\t//第一个任务后完成，第二个先完成，并且设定条件为返回值==第二个的返回值\n\tc.Convey(\"When the task2 is the first to complete, and predicate returns true\", t, func() {\n\t\tc1, c2 = false, false\n\t\tr, err := startTwoCanCancelTask(230, 50, func(v interface{}) bool {\n\t\t\treturn v.(string) == \"ok1\"\n\t\t}).Get()\n\t\tc.So(r, c.ShouldEqual, \"ok1\")\n\t\tc.So(err, c.ShouldBeNil)\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tc.So(c1, c.ShouldEqual, true)\n\t})\n\n\t//第一个任务后完成，第二个先完成，并且设定条件为返回值不等于任意一个任务的返回值\n\tc.Convey(\"When the task2 is the first to complete, and predicate always returns false\", t, func() {\n\t\tc1, c2 = false, false\n\t\tr, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool {\n\t\t\treturn v.(string) == \"ok11\"\n\t\t}).Get()\n\n\t\t_, ok := err.(*NoMatchedError)\n\t\tc.So(r, c.ShouldBeNil)\n\t\tc.So(ok, c.ShouldBeTrue)\n\t\tc.So(err, c.ShouldNotBeNil)\n\n\t\ttime.Sleep(1000 * time.Millisecond)\n\t\tc.So(c1, c.ShouldEqual, false)\n\t\tc.So(c2, c.ShouldEqual, false)\n\t})\n\n\t//c.Convey(\"When all tasks be cancelled\", t, func() {\n\t//\tgetTask := func(canceller Canceller) (interface{}, error) {\n\t//\t\tfor {\n\t//\t\t\ttime.Sleep(50 * time.Millisecond)\n\t//\t\t\tif canceller.IsCancellationRequested() {\n\t//\t\t\t\tcanceller.Cancel()\n\t//\t\t\t\treturn nil, nil\n\t//\t\t\t}\n\t//\t\t}\n\t//\t}\n\n\t//\tf1 := Start(getTask)\n\t//\tf2 := Start(getTask)\n\t//\tf3 := WhenAnyMatched(nil, f1, f2)\n\n\t//\tf1.RequestCancel()\n\t//\tf2.RequestCancel()\n\n\t//\tr, _ := f3.Get()\n\t//\tc.So(r, c.ShouldBeNil)\n\t//})\n\n}\n\nfunc TestWhenAll(t *testing.T) {\n\tstartTwoTask := func(t1 int, t2 int) (f *Future) {\n\t\ttimeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}\n\t\tgetTask := func(i int) func() (interface{}, error) {\n\t\t\treturn func() (interface{}, error) {\n\t\t\t\tif timeouts[i] > 0 {\n\t\t\t\t\ttime.Sleep(timeouts[i] * time.Millisecond)\n\t\t\t\t\treturn \"ok\" + strconv.Itoa(i), nil\n\t\t\t\t} else {\n\t\t\t\t\ttime.Sleep((-1 * timeouts[i]) * time.Millisecond)\n\t\t\t\t\treturn nil, newMyError(\"fail\" + strconv.Itoa(i))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\ttask0 := getTask(0)\n\t\ttask1 := getTask(1)\n\t\tf = WhenAll(task0, task1)\n\t\treturn f\n\t}\n\tc.Convey(\"Test WhenAllFuture\", t, func() {\n\t\twhenTwoTask := func(t1 int, t2 int) *Future {\n\t\t\treturn startTwoTask(t1, t2)\n\t\t}\n\t\tc.Convey(\"When all tasks completed, and the task1 is the first to complete\", func() {\n\t\t\tr, err := whenTwoTask(200, 230).Get()\n\t\t\tc.So(r, shouldSlicesReSame, []interface{}{\"ok0\", \"ok1\"})\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When all tasks completed, and the task1 is the first to complete\", func() {\n\t\t\tr, err := whenTwoTask(230, 200).Get()\n\t\t\tc.So(r, shouldSlicesReSame, []interface{}{\"ok0\", \"ok1\"})\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When task1 failed, but task2 is completed\", func() {\n\t\t\tr, err := whenTwoTask(-250, 210).Get()\n\t\t\tc.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, \"fail0\")\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When all tasks failed\", func() {\n\t\t\tr, err := whenTwoTask(-250, -110).Get()\n\t\t\tc.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, \"fail1\")\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When no task be passed\", func() {\n\t\t\tr, err := whenAllFuture().Get()\n\t\t\tc.So(r, shouldSlicesReSame, []interface{}{})\n\t\t\tc.So(err, c.ShouldBeNil)\n\t\t})\n\n\t\tc.Convey(\"When all tasks be cancelled\", func() {\n\t\t\tgetTask := func(canceller Canceller) (interface{}, error) {\n\t\t\t\tfor {\n\t\t\t\t\ttime.Sleep(50 * time.Millisecond)\n\t\t\t\t\tif canceller.IsCancelled() {\n\t\t\t\t\t\treturn nil, nil\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tf1 := Start(getTask)\n\t\t\tf2 := Start(getTask)\n\t\t\tf3 := WhenAll(f1, f2)\n\n\t\t\tf1.Cancel()\n\t\t\tf2.Cancel()\n\n\t\t\tr, _ := f3.Get()\n\t\t\tc.So(r, c.ShouldBeNil)\n\t\t})\n\t})\n}\n\nfunc TestWrap(t *testing.T) {\n\tc.Convey(\"Test Wrap a value\", t, func() {\n\t\tr, err := Wrap(10).Get()\n\t\tc.So(r, c.ShouldEqual, 10)\n\t\tc.So(err, c.ShouldBeNil)\n\t})\n}\n\nfunc shouldSlicesReSame(actual interface{}, expected ...interface{}) string {\n\tactualSlice, expectedSlice := reflect.ValueOf(actual), reflect.ValueOf(expected[0])\n\tif actualSlice.Kind() != expectedSlice.Kind() {\n\t\treturn fmt.Sprintf(\"Expected1: '%v'\\nActual:   '%v'\\n\", expected[0], actual)\n\t}\n\n\tif actualSlice.Kind() != reflect.Slice {\n\t\treturn fmt.Sprintf(\"Expected2: '%v'\\nActual:   '%v'\\n\", expected[0], actual)\n\t}\n\n\tif actualSlice.Len() != expectedSlice.Len() {\n\t\treturn fmt.Sprintf(\"Expected3: '%v'\\nActual:   '%v'\\n\", expected[0], actual)\n\t}\n\n\tfor i := 0; i < actualSlice.Len(); i++ {\n\t\tif !reflect.DeepEqual(actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface()) {\n\t\t\treturn fmt.Sprintf(\"Expected4: '%v'\\nActual:   '%v'\\n\", expected[0], actual)\n\t\t}\n\t}\n\treturn \"\"\n}\n"
  },
  {
    "path": "promise.go",
    "content": "package promise\n\nimport (\n\t\"math/rand\"\n\t\"unsafe\"\n)\n\nvar (\n\tCANCELLED error = &CancelledError{}\n)\n\n//CancelledError present the Future object is cancelled.\ntype CancelledError struct {\n}\n\nfunc (e *CancelledError) Error() string {\n\treturn \"Task be cancelled\"\n}\n\n//resultType present the type of Future final status.\ntype resultType int\n\nconst (\n\tRESULT_SUCCESS resultType = iota\n\tRESULT_FAILURE\n\tRESULT_CANCELLED\n)\n\n//PromiseResult presents the result of a promise.\n//If Typ is RESULT_SUCCESS, Result field will present the returned value of Future task.\n//If Typ is RESULT_FAILURE, Result field will present a related error .\n//If Typ is RESULT_CANCELLED, Result field will be null.\ntype PromiseResult struct {\n\tResult interface{} //result of the Promise\n\tTyp    resultType  //success, failure, or cancelled?\n}\n\n//Promise presents an object that acts as a proxy for a result.\n//that is initially unknown, usually because the computation of its\n//value is yet incomplete (refer to wikipedia).\n//You can use Resolve/Reject/Cancel to set the final result of Promise.\n//Future can return a read-only placeholder view of result.\ntype Promise struct {\n\t*Future\n}\n\n//Cancel sets the status of promise to RESULT_CANCELLED.\n//If promise is cancelled, Get() will return nil and CANCELLED error.\n//All callback functions will be not called if Promise is cancalled.\nfunc (this *Promise) Cancel() (e error) {\n\treturn this.Future.Cancel()\n}\n\n//Resolve sets the value for promise, and the status will be changed to RESULT_SUCCESS.\n//if promise is resolved, Get() will return the value and nil error.\nfunc (this *Promise) Resolve(v interface{}) (e error) {\n\treturn this.setResult(&PromiseResult{v, RESULT_SUCCESS})\n}\n\n//Resolve sets the error for promise, and the status will be changed to RESULT_FAILURE.\n//if promise is rejected, Get() will return nil and the related error value.\nfunc (this *Promise) Reject(err error) (e error) {\n\treturn this.setResult(&PromiseResult{err, RESULT_FAILURE})\n}\n\n//OnSuccess registers a callback function that will be called when Promise is resolved.\n//If promise is already resolved, the callback will immediately called.\n//The value of Promise will be paramter of Done callback function.\nfunc (this *Promise) OnSuccess(callback func(v interface{})) *Promise {\n\tthis.Future.OnSuccess(callback)\n\treturn this\n}\n\n//OnFailure registers a callback function that will be called when Promise is rejected.\n//If promise is already rejected, the callback will immediately called.\n//The error of Promise will be paramter of Fail callback function.\nfunc (this *Promise) OnFailure(callback func(v interface{})) *Promise {\n\tthis.Future.OnFailure(callback)\n\treturn this\n}\n\n//OnComplete register a callback function that will be called when Promise is rejected or resolved.\n//If promise is already rejected or resolved, the callback will immediately called.\n//According to the status of Promise, value or error will be paramter of Always callback function.\n//Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected.\n//Always callback will be not called if Promise be called.\nfunc (this *Promise) OnComplete(callback func(v interface{})) *Promise {\n\tthis.Future.OnComplete(callback)\n\treturn this\n}\n\n//OnCancel registers a callback function that will be called when Promise is cancelled.\n//If promise is already cancelled, the callback will immediately called.\nfunc (this *Promise) OnCancel(callback func()) *Promise {\n\tthis.Future.OnCancel(callback)\n\treturn this\n}\n\n//NewPromise is factory function for Promise\nfunc NewPromise() *Promise {\n\tval := &futureVal{\n\t\tmake([]func(v interface{}), 0, 8),\n\t\tmake([]func(v interface{}), 0, 8),\n\t\tmake([]func(v interface{}), 0, 4),\n\t\tmake([]func(), 0, 2),\n\t\tmake([]*pipe, 0, 4), nil,\n\t}\n\tf := &Promise{\n\t\t&Future{\n\t\t\trand.Int(),\n\t\t\tmake(chan struct{}),\n\t\t\tunsafe.Pointer(val),\n\t\t},\n\t}\n\treturn f\n}\n"
  },
  {
    "path": "utils.go",
    "content": "package promise\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"runtime\"\n\t\"strconv\"\n)\n\n//NoMatchedError presents no future that returns matched result in WhenAnyTrue function.\ntype NoMatchedError struct {\n\tResults []interface{}\n}\n\nfunc (e *NoMatchedError) Error() string {\n\treturn \"No matched future\"\n}\n\nfunc (e *NoMatchedError) HasError() bool {\n\tfor _, ie := range e.Results {\n\t\tif _, ok1 := ie.(error); ok1 {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc newNoMatchedError(results []interface{}) *NoMatchedError {\n\treturn &NoMatchedError{results}\n}\n\nfunc newNoMatchedError1(e interface{}) *NoMatchedError {\n\treturn &NoMatchedError{[]interface{}{e}}\n}\n\n//AggregateError aggregate multi errors into an error\ntype AggregateError struct {\n\ts         string\n\tInnerErrs []error\n}\n\nfunc (e *AggregateError) Error() string {\n\tif e.InnerErrs == nil {\n\t\treturn e.s\n\t} else {\n\t\tbuf := bytes.NewBufferString(e.s)\n\t\tbuf.WriteString(\"\\n\\n\")\n\t\tfor i, ie := range e.InnerErrs {\n\t\t\tif ie == nil {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tbuf.WriteString(\"error appears in Future \")\n\t\t\tbuf.WriteString(strconv.Itoa(i))\n\t\t\tbuf.WriteString(\": \")\n\t\t\tbuf.WriteString(ie.Error())\n\t\t\tbuf.WriteString(\"\\n\")\n\t\t}\n\t\tbuf.WriteString(\"\\n\")\n\t\treturn buf.String()\n\t}\n}\n\nfunc newAggregateError(s string, innerErrors []error) *AggregateError {\n\treturn &AggregateError{newErrorWithStacks(s).Error(), innerErrors}\n}\n\nfunc newAggregateError1(s string, e interface{}) *AggregateError {\n\treturn &AggregateError{newErrorWithStacks(s).Error(), []error{getError(e)}}\n}\n\nfunc newErrorWithStacks(i interface{}) (e error) {\n\terr := getError(i)\n\tbuf := bytes.NewBufferString(err.Error())\n\tbuf.WriteString(\"\\n\")\n\n\tpcs := make([]uintptr, 50)\n\tnum := runtime.Callers(2, pcs)\n\tfor _, v := range pcs[0:num] {\n\t\tfun := runtime.FuncForPC(v)\n\t\tfile, line := fun.FileLine(v)\n\t\tname := fun.Name()\n\t\t//fmt.Println(name, file + \":\", line)\n\t\twriteStrings(buf, []string{name, \" \", file, \":\", strconv.Itoa(line), \"\\n\"})\n\t}\n\treturn errors.New(buf.String())\n}\n\nfunc getAct(pr *Promise, act interface{}) (f func() (r interface{}, err error)) {\n\tvar (\n\t\tact1 func() (interface{}, error)\n\t\tact2 func(Canceller) (interface{}, error)\n\t)\n\tcanCancel := false\n\n\t//convert the act to the function that has return value and error if act function haven't return value and error\n\tswitch v := act.(type) {\n\tcase func() (interface{}, error):\n\t\tact1 = v\n\tcase func(Canceller) (interface{}, error):\n\t\tcanCancel = true\n\t\tact2 = v\n\tcase func():\n\t\tact1 = func() (interface{}, error) {\n\t\t\tv()\n\t\t\treturn nil, nil\n\t\t}\n\tcase func(Canceller):\n\t\tcanCancel = true\n\t\tact2 = func(canceller Canceller) (interface{}, error) {\n\t\t\tv(canceller)\n\t\t\treturn nil, nil\n\t\t}\n\tdefault:\n\t\tif e, ok := v.(error); !ok {\n\t\t\tpr.Resolve(v)\n\t\t} else {\n\t\t\tpr.Reject(e)\n\t\t}\n\t\treturn nil\n\t}\n\n\t//If paramters of act function has a Canceller interface, the Future will can be cancelled.\n\tvar canceller Canceller = nil\n\tif pr != nil && canCancel {\n\t\t//pr.EnableCanceller()\n\t\tcanceller = pr.Canceller()\n\t}\n\n\t//return proxy function of act function\n\tf = func() (r interface{}, err error) {\n\t\tdefer func() {\n\t\t\tif e := recover(); e != nil {\n\t\t\t\terr = newErrorWithStacks(e)\n\t\t\t}\n\t\t}()\n\n\t\tif canCancel {\n\t\t\tr, err = act2(canceller)\n\t\t} else {\n\t\t\tr, err = act1()\n\t\t}\n\n\t\treturn\n\t}\n\treturn\n}\n\nfunc startPipe(r *PromiseResult, pipeTask func(v interface{}) *Future, pipePromise *Promise) {\n\t//处理链式异步任务\n\tif pipeTask != nil {\n\t\tf := pipeTask(r.Result)\n\t\tf.OnSuccess(func(v interface{}) {\n\t\t\tpipePromise.Resolve(v)\n\t\t}).OnFailure(func(v interface{}) {\n\t\t\tpipePromise.Reject(getError(v))\n\t\t})\n\t}\n\n}\n\nfunc getFutureReturnVal(r *PromiseResult) (interface{}, error) {\n\tif r.Typ == RESULT_SUCCESS {\n\t\treturn r.Result, nil\n\t} else if r.Typ == RESULT_FAILURE {\n\t\treturn nil, getError(r.Result)\n\t} else {\n\t\treturn nil, getError(r.Result) //&CancelledError{}\n\t}\n}\n\n//执行回调函数\nfunc execCallback(r *PromiseResult,\n\tdones []func(v interface{}),\n\tfails []func(v interface{}),\n\talways []func(v interface{}),\n\tcancels []func()) {\n\n\tif r.Typ == RESULT_CANCELLED {\n\t\tfor _, f := range cancels {\n\t\t\tfunc() {\n\t\t\t\tdefer func() {\n\t\t\t\t\tif e := recover(); e != nil {\n\t\t\t\t\t\terr := newErrorWithStacks(e)\n\t\t\t\t\t\tfmt.Println(\"error happens:\\n \", err)\n\t\t\t\t\t}\n\t\t\t\t}()\n\t\t\t\tf()\n\t\t\t}()\n\t\t}\n\t\treturn\n\t}\n\n\tvar callbacks []func(v interface{})\n\tif r.Typ == RESULT_SUCCESS {\n\t\tcallbacks = dones\n\t} else {\n\t\tcallbacks = fails\n\t}\n\n\tforFs := func(s []func(v interface{})) {\n\t\tforSlice(s, func(f func(v interface{})) { f(r.Result) })\n\t}\n\n\tforFs(callbacks)\n\tforFs(always)\n\n}\n\nfunc forSlice(s []func(v interface{}), f func(func(v interface{}))) {\n\tfor _, e := range s {\n\t\tfunc() {\n\t\t\tdefer func() {\n\t\t\t\tif e := recover(); e != nil {\n\t\t\t\t\terr := newErrorWithStacks(e)\n\t\t\t\t\tfmt.Println(\"error happens:\\n \", err)\n\t\t\t\t}\n\t\t\t}()\n\t\t\tf(e)\n\t\t}()\n\t}\n}\n\n//Error handling struct and functions------------------------------\ntype stringer interface {\n\tString() string\n}\n\nfunc getError(i interface{}) (e error) {\n\tif i != nil {\n\t\tswitch v := i.(type) {\n\t\tcase error:\n\t\t\te = v\n\t\tcase string:\n\t\t\te = errors.New(v)\n\t\tdefault:\n\t\t\tif s, ok := i.(stringer); ok {\n\t\t\t\te = errors.New(s.String())\n\t\t\t} else {\n\t\t\t\te = errors.New(fmt.Sprintf(\"%v\", i))\n\t\t\t}\n\t\t}\n\t}\n\treturn\n}\n\nfunc writeStrings(buf *bytes.Buffer, strings []string) {\n\tfor _, s := range strings {\n\t\tbuf.WriteString(s)\n\t}\n}\n"
  }
]