Full Code of fanliao/go-promise for AI

master 1890db352a72 cached
8 files
58.1 KB
17.0k tokens
94 symbols
1 requests
Download .txt
Repository: fanliao/go-promise
Branch: master
Commit: 1890db352a72
Files: 8
Total size: 58.1 KB

Directory structure:
gitextract__0ann36z/

├── .gitignore
├── LICENSE
├── README.md
├── future.go
├── future_factory.go
├── future_test.go
├── promise.go
└── utils.go

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

*.exe


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Copyright (c) 2014 fanliao

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
[home]: github.com/fanliao/go-promise

go-promise is a Go promise and future library.

Inspired by [Futures and promises]()

## Installation

    $ go get github.com/fanliao/go-promise

## Features

* Future and Promise

  * ```NewPromise()```
  * ```promise.Future```

* Promise and Future callbacks

  * ```.OnSuccess(v interface{})```
  * ```.OnFailure(v interface{})```
  * ```.OnComplete(v interface{})```
  * ```.OnCancel()```

* Get the result of future

  * ```.Get() ```
  * ```.GetOrTimeout()```
  * ```.GetChan()```

* Set timeout for future

  * ```.SetTimeout(ms)```
  
* Merge multiple promises

  * ```WhenAll(func1, func2, func3, ...)```
  * ```WhenAny(func1, func2, func3, ...)```
  * ```WhenAnyMatched(func1, func2, func3, ...)```

* Pipe
  * ```.Pipe(funcWithDone, funcWithFail)```

* Cancel the future

  * ```.Cancel()```
  * ```.IsCancelled()```

* Create future by function

  * ```Start(func() (r interface{}, e error))```
  * ```Start(func())```
  * ```Start(func(canceller Canceller) (r interface{}, e error))```
  * ```Start(func(canceller Canceller))```

* Immediate wrappers

  * ```Wrap(interface{})```

* Chain API

  * ```Start(taskDone).Done(done1).Fail(fail1).Always(alwaysForDone1).Pipe(f1, f2).Done(done2)```

## Quick start

### Promise and Future 

```go
import "github.com/fanliao/go-promise"
import "net/http"

p := promise.NewPromise()
p.OnSuccess(func(v interface{}) {
   ...
}).OnFailure(func(v interface{}) {
   ...
}).OnComplete(func(v interface{}) {
   ...
})

go func(){
	url := "http://example.com/"
	
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		p.Reject(err)
	}
	
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		p.Reject(err)
	}
	p.Resolve(body)
}()
r, err := p.Get()
```

If you want to provide a read-only view, you can get a future variable:

```go
p.Future //cannot Resolve, Reject for a future
```

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:

```go
import "github.com/fanliao/go-promise"
import "net/http"

task := func()(r interface{}, err error){
	url := "http://example.com/"
	
	resp, err := http.Get(url)
	defer resp.Body.Close()
	if err != nil {
		return nil, err
	}
	
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return body, nil
}

f := promise.Start(task).OnSuccess(func(v interface{}) {
   ...
}).OnFailure(func(v interface{}) {
   ...
}).OnComplete(func(v interface{}) {
   ...
})
r, err := f.Get()
```

### Get the result of future

Please note the process will be block until the future task is completed

```go
f := promise.Start(func() (r interface{}, err error) {
	return "ok", nil  
})
r, err := f.Get()  //return "ok", nil

f := promise.Start(func() (r interface{}, err error) {
	return nil, errors.New("fail")  
})
r, err := f.Get()  //return nil, errorString{"fail"}
```

Can wait until timeout

```go
f := promise.Start(func() (r interface{}, err error) {
	time.Sleep(500 * time.Millisecond)
	return "ok", nil 
})
r, err, timeout := f.GetOrTimeout(100)  //return nil, nil, true
```

### Merge multiple futures

Creates a future that will be completed when all of the supplied future are completed.
```go
task1 := func() (r interface{}, err error) {
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	return "ok2", nil
}

f := promise.WhenAll(task1, task2)
r, err := f.Get()    //return []interface{}{"ok1", "ok2"}
```

If any future is failure, the future returnd by WhenAll will be failure
```go
task1 := func() (r interface{}, err error)  {
	return "ok", nil
}
task2 := func() (r interface{}, err error)  {
	return nil, errors.New("fail2")
}
f := promise.WhenAll(task1, task2)
r, ok := f.Get()    //return nil, *AggregateError
```

Creates a future that will be completed when any of the supplied tasks is completed.
```go
task1 := func() (r interface{}, err error) {
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	time.Sleep(200 * time.Millisecond)
	return nil, errors.New("fail2")
}

f := promise.WhenAny(task1, task2)
r, err := f.Get()  //return "ok1", nil
```

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.
```go
task1 := func() (r interface{}, err error) {
	time.Sleep(200 * time.Millisecond)
	return "ok1", nil
}
task2 := func() (r interface{}, err error) {
	return "ok2", nil
}

f := promise.WhenAnyMatched(func(v interface{}) bool{
	return v == "ok1"
}, task1, task2)
r, err := f.Get()  //return "ok1", nil
```

### Promise pipelining

```go
task1 := func() (r interface{}, err error) {
	return 10, nil
}
task2 := func(v interface{}) (r interface{}, err error) {
	return v.(int) * 2, nil
}

f := promise.Start(task1).Pipe(task2)
r, err := f.Get()   //return 20
```

### Cancel the future or set timeout

If need cancel a future, can pass a canceller object to task function
```go
import "github.com/fanliao/go-promise"
import "net/http"

p := promise.NewPromise().EnableCanceller()

go func(canceller promise.Canceller){
	for i < 50 {
		if canceller.IsCancelled() {
			return
		}
		time.Sleep(100 * time.Millisecond)
	}
}(p.Canceller())
f.Cancel()

r, err := p.Get()   //return nil, promise.CANCELLED
fmt.Println(p.Future.IsCancelled())      //true
```

Or can use Start to submit a future task which can be cancelled
```go
task := func(canceller promise.Canceller) (r interface{}, err error) {
	for i < 50 {
		if canceller.IsCancelled() {
			return 0, nil
		}
		time.Sleep(100 * time.Millisecond)
	}
	return 1, nil
}
f := promise.Start(task1)
f.Cancel()

r, err := f.Get()   //return nil, promise.CANCELLED
fmt.Println(f.IsCancelled())      //true
```

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.

You can also set timeout for a future

```go
task := func(canceller promise.Canceller) (r interface{}, err error) {
	time.Sleep(300 * time.Millisecond)
	if !canceller.IsCancelled(){
		fmt.Println("Run done")
	} 
	return
}

f := promise.Start(task).OnCancel(func() {
	fmt.Println("Future is cancelled")
}).SetTimeout(100)

r, err := f.Get() //return nil, promise.CANCELLED
fmt.Println(f.IsCancelled()) //print true
```

## Document

* [GoDoc at godoc.org](http://godoc.org/github.com/fanliao/go-promise)

## License

go-promise is licensed under the MIT Licence, (http://www.apache.org/licenses/LICENSE-2.0.html).


================================================
FILE: future.go
================================================
/*
Package promise provides a complete promise and future implementation.
A quick start sample:


fu := Start(func()(resp interface{}, err error){
    resp, err = http.Get("http://example.com/")
    return
})
//do somthing...
resp, err := fu.Get()
*/
package promise

import (
	"errors"
	"fmt"
	"sync/atomic"
	"time"
	"unsafe"
)

type callbackType int

const (
	CALLBACK_DONE callbackType = iota
	CALLBACK_FAIL
	CALLBACK_ALWAYS
	CALLBACK_CANCEL
)

//pipe presents a promise that will be chain call
type pipe struct {
	pipeDoneTask, pipeFailTask func(v interface{}) *Future
	pipePromise                *Promise
}

//getPipe returns piped Future task function and pipe Promise by the status of current Promise.
func (this *pipe) getPipe(isResolved bool) (func(v interface{}) *Future, *Promise) {
	if isResolved {
		return this.pipeDoneTask, this.pipePromise
	} else {
		return this.pipeFailTask, this.pipePromise
	}
}

//Canceller is used to check if the future is cancelled
//It usually be passed to the future task function
//for future task function can check if the future is cancelled.
type Canceller interface {
	IsCancelled() bool
	Cancel()
}

//canceller provides an implement of Canceller interface.
//It will be passed to future task function as paramter
type canceller struct {
	f *Future
}

//Cancel sets Future task to CANCELLED status
func (this *canceller) Cancel() {
	this.f.Cancel()
}

//IsCancelled returns true if Future task is cancelld, otherwise false.
func (this *canceller) IsCancelled() (r bool) {
	return this.f.IsCancelled()
}

//futureVal stores the internal state of Future.
type futureVal struct {
	dones, fails, always []func(v interface{})
	cancels              []func()
	pipes                []*pipe
	r                    *PromiseResult
}

//Future provides a read-only view of promise,
//the value is set by using Resolve, Reject and Cancel methods of related Promise
type Future struct {
	Id    int //Id can be used as identity of Future
	final chan struct{}
	//val point to futureVal that stores status of future
	//if need to change the status of future, must copy a new futureVal and modify it,
	//then use CAS to put the pointer of new futureVal
	val unsafe.Pointer
}

//Canceller returns a canceller object related to future.
func (this *Future) Canceller() Canceller {
	return &canceller{this}
}

//IsCancelled returns true if the promise is cancelled, otherwise false
func (this *Future) IsCancelled() bool {
	val := this.loadVal()

	if val != nil && val.r != nil && val.r.Typ == RESULT_CANCELLED {
		return true
	} else {
		return false
	}
}

//SetTimeout sets the future task will be cancelled
//if future is not complete before time out
func (this *Future) SetTimeout(mm int) *Future {
	if mm == 0 {
		mm = 10
	} else {
		mm = mm * 1000 * 1000
	}

	go func() {
		<-time.After((time.Duration)(mm) * time.Nanosecond)
		this.Cancel()
	}()
	return this
}

//GetChan returns a channel than can be used to receive result of Promise
func (this *Future) GetChan() <-chan *PromiseResult {
	c := make(chan *PromiseResult, 1)
	this.OnComplete(func(v interface{}) {
		c <- this.loadResult()
	}).OnCancel(func() {
		c <- this.loadResult()
	})
	return c
}

//Get will block current goroutines until the Future is resolved/rejected/cancelled.
//If Future is resolved, value and nil will be returned
//If Future is rejected, nil and error will be returned.
//If Future is cancelled, nil and CANCELLED error will be returned.
func (this *Future) Get() (val interface{}, err error) {
	<-this.final
	return getFutureReturnVal(this.loadResult())
}

//GetOrTimeout is similar to Get(), but GetOrTimeout will not block after timeout.
//If GetOrTimeout returns with a timeout, timeout value will be true in return values.
//The unit of paramter is millisecond.
func (this *Future) GetOrTimeout(mm uint) (val interface{}, err error, timout bool) {
	if mm == 0 {
		mm = 10
	} else {
		mm = mm * 1000 * 1000
	}

	select {
	case <-time.After((time.Duration)(mm) * time.Nanosecond):
		return nil, nil, true
	case <-this.final:
		r, err := getFutureReturnVal(this.loadResult())
		return r, err, false
	}
}

//Cancel sets the status of promise to RESULT_CANCELLED.
//If promise is cancelled, Get() will return nil and CANCELLED error.
//All callback functions will be not called if Promise is cancalled.
func (this *Future) Cancel() (e error) {
	return this.setResult(&PromiseResult{CANCELLED, RESULT_CANCELLED})
}

//OnSuccess registers a callback function that will be called when Promise is resolved.
//If promise is already resolved, the callback will immediately called.
//The value of Promise will be paramter of Done callback function.
func (this *Future) OnSuccess(callback func(v interface{})) *Future {
	this.addCallback(callback, CALLBACK_DONE)
	return this
}

//OnFailure registers a callback function that will be called when Promise is rejected.
//If promise is already rejected, the callback will immediately called.
//The error of Promise will be paramter of Fail callback function.
func (this *Future) OnFailure(callback func(v interface{})) *Future {
	this.addCallback(callback, CALLBACK_FAIL)
	return this
}

//OnComplete register a callback function that will be called when Promise is rejected or resolved.
//If promise is already rejected or resolved, the callback will immediately called.
//According to the status of Promise, value or error will be paramter of Always callback function.
//Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected.
//Always callback will be not called if Promise be called.
func (this *Future) OnComplete(callback func(v interface{})) *Future {
	this.addCallback(callback, CALLBACK_ALWAYS)
	return this
}

//OnCancel registers a callback function that will be called when Promise is cancelled.
//If promise is already cancelled, the callback will immediately called.
func (this *Future) OnCancel(callback func()) *Future {
	this.addCallback(callback, CALLBACK_CANCEL)
	return this
}

//Pipe registers one or two functions that returns a Future, and returns a proxy of pipeline Future.
//First function will be called when Future is resolved, the returned Future will be as pipeline Future.
//Secondary function will be called when Futrue is rejected, the returned Future will be as pipeline Future.
func (this *Future) Pipe(callbacks ...interface{}) (result *Future, ok bool) {
	if len(callbacks) == 0 ||
		(len(callbacks) == 1 && callbacks[0] == nil) ||
		(len(callbacks) > 1 && callbacks[0] == nil && callbacks[1] == nil) {
		result = this
		return
	}

	//ensure all callback functions match the spec "func(v interface{}) *Future"
	cs := make([]func(v interface{}) *Future, len(callbacks), len(callbacks))
	for i, callback := range callbacks {
		if c, ok1 := callback.(func(v interface{}) *Future); ok1 {
			cs[i] = c
		} else if c, ok1 := callback.(func() *Future); ok1 {
			cs[i] = func(v interface{}) *Future {
				return c()
			}
		} else if c, ok1 := callback.(func(v interface{})); ok1 {
			cs[i] = func(v interface{}) *Future {
				return Start(func() {
					c(v)
				})
			}
		} else if c, ok1 := callback.(func(v interface{}) (r interface{}, err error)); ok1 {
			cs[i] = func(v interface{}) *Future {
				return Start(func() (r interface{}, err error) {
					r, err = c(v)
					return
				})
			}
		} else if c, ok1 := callback.(func()); ok1 {
			cs[i] = func(v interface{}) *Future {
				return Start(func() {
					c()
				})
			}
		} else if c, ok1 := callback.(func() (r interface{}, err error)); ok1 {
			cs[i] = func(v interface{}) *Future {
				return Start(func() (r interface{}, err error) {
					r, err = c()
					return
				})
			}
		} else {
			ok = false
			return
		}
	}

	for {
		v := this.loadVal()
		r := v.r
		if r != nil {
			result = this
			if r.Typ == RESULT_SUCCESS && cs[0] != nil {
				result = (cs[0](r.Result))
			} else if r.Typ == RESULT_FAILURE && len(cs) > 1 && cs[1] != nil {
				result = (cs[1](r.Result))
			}
		} else {
			newPipe := &pipe{}
			newPipe.pipeDoneTask = cs[0]
			if len(cs) > 1 {
				newPipe.pipeFailTask = cs[1]
			}
			newPipe.pipePromise = NewPromise()

			newVal := *v
			newVal.pipes = append(newVal.pipes, newPipe)

			//use CAS to ensure that the state of Future is not changed,
			//if the state is changed, will retry CAS operation.
			if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
				result = newPipe.pipePromise.Future
				break
			}
		}
	}
	ok = true

	return
}

//result uses Atomic load to return result of the Future
func (this *Future) loadResult() *PromiseResult {
	val := this.loadVal()
	return val.r
}

//val uses Atomic load to return state value of the Future
func (this *Future) loadVal() *futureVal {
	r := atomic.LoadPointer(&this.val)
	return (*futureVal)(r)
}

//setResult sets the value and final status of Promise, it will only be executed for once
func (this *Future) setResult(r *PromiseResult) (e error) { //r *PromiseResult) {
	defer func() {
		if err := getError(recover()); err != nil {
			e = err
			fmt.Println("\nerror in setResult():", err)
		}
	}()

	e = errors.New("Cannot resolve/reject/cancel more than once")

	for {
		v := this.loadVal()
		if v.r != nil {
			return
		}
		newVal := *v
		newVal.r = r

		//Use CAS operation to ensure that the state of Promise isn't changed.
		//If the state is changed, must get latest state and try to call CAS again.
		//No ABA issue in this case because address of all objects are different.
		if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
			//Close chEnd then all Get() and GetOrTimeout() will be unblocked
			close(this.final)

			//call callback functions and start the Promise pipeline
			if len(v.dones) > 0 || len(v.fails) > 0 || len(v.always) > 0 || len(v.cancels) > 0 {
				go func() {
					execCallback(r, v.dones, v.fails, v.always, v.cancels)
				}()
			}

			//start the pipeline
			if len(v.pipes) > 0 {
				go func() {
					for _, pipe := range v.pipes {
						pipeTask, pipePromise := pipe.getPipe(r.Typ == RESULT_SUCCESS)
						startPipe(r, pipeTask, pipePromise)
					}
				}()
			}
			e = nil
			break
		}
	}
	return
}

//handleOneCallback registers a callback function
func (this *Future) addCallback(callback interface{}, t callbackType) {
	if callback == nil {
		return
	}
	if (t == CALLBACK_DONE) ||
		(t == CALLBACK_FAIL) ||
		(t == CALLBACK_ALWAYS) {
		if _, ok := callback.(func(v interface{})); !ok {
			panic(errors.New("Callback function spec must be func(v interface{})"))
		}
	} else if t == CALLBACK_CANCEL {
		if _, ok := callback.(func()); !ok {
			panic(errors.New("Callback function spec must be func()"))
		}
	}

	for {
		v := this.loadVal()
		r := v.r
		if r == nil {
			newVal := *v
			switch t {
			case CALLBACK_DONE:
				newVal.dones = append(newVal.dones, callback.(func(v interface{})))
			case CALLBACK_FAIL:
				newVal.fails = append(newVal.fails, callback.(func(v interface{})))
			case CALLBACK_ALWAYS:
				newVal.always = append(newVal.always, callback.(func(v interface{})))
			case CALLBACK_CANCEL:
				newVal.cancels = append(newVal.cancels, callback.(func()))
			}

			//use CAS to ensure that the state of Future is not changed,
			//if the state is changed, will retry CAS operation.
			if atomic.CompareAndSwapPointer(&this.val, unsafe.Pointer(v), unsafe.Pointer(&newVal)) {
				break
			}
		} else {
			if (t == CALLBACK_DONE && r.Typ == RESULT_SUCCESS) ||
				(t == CALLBACK_FAIL && r.Typ == RESULT_FAILURE) ||
				(t == CALLBACK_ALWAYS && r.Typ != RESULT_CANCELLED) {
				callbackFunc := callback.(func(v interface{}))
				callbackFunc(r.Result)
			} else if t == CALLBACK_CANCEL && r.Typ == RESULT_CANCELLED {
				callbackFunc := callback.(func())
				callbackFunc()
			}
			break
		}
	}
}


================================================
FILE: future_factory.go
================================================
package promise

import (
	"sync/atomic"
)

type anyPromiseResult struct {
	result interface{}
	i      int
}

//Start start a goroutines to execute task function
//and return a Future that presents the result.
//If option paramter is true, the act function will be sync called.
//Type of act can be any of below four types:
//  func() (r interface{}, err error):
//     if err returned by act != nil or panic error, then Future will be rejected with error,
//     otherwise be resolved with r.
//  func():
//     if act panic error, then Future will be rejected, otherwise be resolved with nil.
//  func(c promise.Canceller) (r interface{}, err error):
//     if err returned by act != nil or panic error,
//     then Future will be rejected with err, otherwise be resolved with r.
//     We can check c.IsCancelled() to decide whether need to exit act function
//  func(promise.Canceller):
//     if act panic error, then Future will be rejected with error, otherwise be resolved with nil.
//     We can check c.IsCancelled() to decide whether need to exit act function.
//  error:
//     Future will be rejected with error immediately
//  other value:
//     Future will be resolved with value immediately
func Start(act interface{}, syncs ...bool) *Future {
	pr := NewPromise()
	if f, ok := act.(*Future); ok {
		return f
	}

	if action := getAct(pr, act); action != nil {
		if syncs != nil && len(syncs) > 0 && !syncs[0] {
			//sync call
			r, err := action()
			if pr.IsCancelled() {
				pr.Cancel()
			} else {
				if err == nil {
					pr.Resolve(r)
				} else {
					pr.Reject(err)
				}
			}
		} else {
			//async call
			go func() {
				r, err := action()
				if pr.IsCancelled() {
					pr.Cancel()
				} else {
					if err == nil {
						pr.Resolve(r)
					} else {
						pr.Reject(err)
					}
				}
			}()
		}
	}

	return pr.Future
}

//Wrap return a Future that presents the wrapped value
func Wrap(value interface{}) *Future {
	pr := NewPromise()
	if e, ok := value.(error); !ok {
		pr.Resolve(value)
	} else {
		pr.Reject(e)
	}

	return pr.Future
}

//WhenAny returns a Future.
//If any Future is resolved, this Future will be resolved and return result of resolved Future.
//Otherwise will rejected with results slice returned by all Futures
//Legit types of act are same with Start function
func WhenAny(acts ...interface{}) *Future {
	return WhenAnyMatched(nil, acts...)
}

//WhenAnyMatched returns a Future.
//If any Future is resolved and match the predicate, this Future will be resolved and return result of resolved Future.
//If all Futures are cancelled, this Future will be cancelled.
//Otherwise will rejected with a NoMatchedError included results slice returned by all Futures
//Legit types of act are same with Start function
func WhenAnyMatched(predicate func(interface{}) bool, acts ...interface{}) *Future {
	if predicate == nil {
		predicate = func(v interface{}) bool { return true }
	}

	fs := make([]*Future, len(acts))
	for i, act := range acts {
		fs[i] = Start(act)
	}

	nf, rs := NewPromise(), make([]interface{}, len(fs))
	if len(acts) == 0 {
		nf.Resolve(nil)
	}

	chFails, chDones := make(chan anyPromiseResult), make(chan anyPromiseResult)

	go func() {
		for i, f := range fs {
			k := i
			f.OnSuccess(func(v interface{}) {
				defer func() { _ = recover() }()
				chDones <- anyPromiseResult{v, k}
			}).OnFailure(func(v interface{}) {
				defer func() { _ = recover() }()
				chFails <- anyPromiseResult{v, k}
			}).OnCancel(func() {
				defer func() { _ = recover() }()
				chFails <- anyPromiseResult{CANCELLED, k}
			})
		}
	}()

	if len(fs) == 1 {
		select {
		case r := <-chFails:
			if _, ok := r.result.(CancelledError); ok {
				nf.Cancel()
			} else {
				nf.Reject(newNoMatchedError1(r.result))
			}
		case r := <-chDones:
			if predicate(r.result) {
				nf.Resolve(r.result)
			} else {
				nf.Reject(newNoMatchedError1(r.result))
			}
		}
	} else {
		go func() {
			defer func() {
				if e := recover(); e != nil {
					nf.Reject(newErrorWithStacks(e))
				}
			}()

			j := 0
			for {
				select {
				case r := <-chFails:
					rs[r.i] = getError(r.result)
				case r := <-chDones:
					if predicate(r.result) {
						//try to cancel other futures
						for _, f := range fs {
							f.Cancel()
						}

						//close the channel for avoid the send side be blocked
						closeChan := func(c chan anyPromiseResult) {
							defer func() { _ = recover() }()
							close(c)
						}
						closeChan(chDones)
						closeChan(chFails)

						//Resolve the future and return result
						nf.Resolve(r.result)
						return
					} else {
						rs[r.i] = r.result
					}
				}

				if j++; j == len(fs) {
					m := 0
					for _, r := range rs {
						switch val := r.(type) {
						case CancelledError:
						default:
							m++
							_ = val
						}
					}
					if m > 0 {
						nf.Reject(newNoMatchedError(rs))
					} else {
						nf.Cancel()
					}
					break
				}
			}
		}()
	}
	return nf.Future
}

//WhenAll receives function slice and returns a Future.
//If all Futures are resolved, this Future will be resolved and return results slice.
//Otherwise will rejected with results slice returned by all Futures
//Legit types of act are same with Start function
func WhenAll(acts ...interface{}) (fu *Future) {
	pr := NewPromise()
	fu = pr.Future

	if len(acts) == 0 {
		pr.Resolve([]interface{}{})
		return
	}

	fs := make([]*Future, len(acts))
	for i, act := range acts {
		fs[i] = Start(act)
	}
	fu = whenAllFuture(fs...)
	return
}

//WhenAll receives Futures slice and returns a Future.
//If all Futures are resolved, this Future will be resolved and return results slice.
//If any Future is cancelled, this Future will be cancelled.
//Otherwise will rejected with results slice returned by all Futures.
//Legit types of act are same with Start function
func whenAllFuture(fs ...*Future) *Future {
	wf := NewPromise()
	rs := make([]interface{}, len(fs))

	if len(fs) == 0 {
		wf.Resolve([]interface{}{})
	} else {
		n := int32(len(fs))
		cancelOthers := func(j int) {
			for k, f1 := range fs {
				if k != j {
					f1.Cancel()
				}
			}
		}

		go func() {
			isCancelled := int32(0)
			for i, f := range fs {
				j := i

				f.OnSuccess(func(v interface{}) {
					rs[j] = v
					if atomic.AddInt32(&n, -1) == 0 {
						wf.Resolve(rs)
					}
				}).OnFailure(func(v interface{}) {
					if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
						//try to cancel all futures
						cancelOthers(j)

						//errs := make([]error, 0, 1)
						//errs = append(errs, v.(error))
						e := newAggregateError1("Error appears in WhenAll:", v)
						wf.Reject(e)
					}
				}).OnCancel(func() {
					if atomic.CompareAndSwapInt32(&isCancelled, 0, 1) {
						//try to cancel all futures
						cancelOthers(j)

						wf.Cancel()
					}
				})
			}
		}()
	}

	return wf.Future
}


================================================
FILE: future_test.go
================================================
package promise

import (
	"errors"
	"fmt"
	c "github.com/smartystreets/goconvey/convey"
	"reflect"
	"strconv"
	"testing"
	"time"
)

const (
	TASK_END      = "task be end,"
	CALL_DONE     = "callback done,"
	CALL_FAIL     = "callback fail,"
	CALL_ALWAYS   = "callback always,"
	WAIT_TASK     = "wait task end,"
	GET           = "get task result,"
	DONE_Pipe_END = "task Pipe done be end,"
	FAIL_Pipe_END = "task Pipe fail be end,"
)

// errorLinq is a trivial implementation of error.
type myError struct {
	val interface{}
}

func (e *myError) Error() string {
	return fmt.Sprintf("%v", e.val)
}

func newMyError(v interface{}) *myError {
	return &myError{v}
}

func TestResolveAndReject(t *testing.T) {
	c.Convey("When Promise is resolved", t, func() {
		p := NewPromise()
		go func() {
			time.Sleep(50 * time.Millisecond)
			p.Resolve("ok")
		}()
		c.Convey("Should return the argument of Resolve", func() {
			r, err := p.Get()
			c.So(r, c.ShouldEqual, "ok")
			c.So(err, c.ShouldBeNil)
		})
	})

	c.Convey("When Promise is rejected", t, func() {
		p := NewPromise()
		go func() {
			time.Sleep(50 * time.Millisecond)
			p.Reject(errors.New("fail"))
		}()
		c.Convey("Should return error", func() {
			r, err := p.Get()
			c.So(err, c.ShouldNotBeNil)
			c.So(r, c.ShouldEqual, nil)
		})
	})
}

func TestCancel(t *testing.T) {
	c.Convey("When Promise is cancelled", t, func() {
		p := NewPromise()
		go func() {
			time.Sleep(50 * time.Millisecond)
			p.Cancel()
		}()

		c.Convey("Should return CancelledError", func() {
			r, err := p.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldEqual, CANCELLED)
			c.So(p.IsCancelled(), c.ShouldBeTrue)
		})
	})
}

func TestGetOrTimeout(t *testing.T) {
	timout := 50 * time.Millisecond
	c.Convey("When Promise is unfinished", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Resolve("ok")
		}()
		c.Convey("timeout should be true", func() {
			r, err, timeout := p.GetOrTimeout(10)
			c.So(timeout, c.ShouldBeTrue)
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When Promise is resolved, the argument of Resolve should be returned", func() {
			r, err, timeout := p.GetOrTimeout(50)
			c.So(timeout, c.ShouldBeFalse)
			c.So(r, c.ShouldEqual, "ok")
			c.So(err, c.ShouldBeNil)
		})
	})

	c.Convey("When Promise is rejected", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Reject(errors.New("fail"))
		}()
		c.Convey("Should return error", func() {
			r, err, timeout := p.GetOrTimeout(83)
			c.So(timeout, c.ShouldBeFalse)
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})
	})

	c.Convey("When Promise is cancelled", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Cancel()
		}()
		c.Convey("Should return CancelledError", func() {
			r, err, timeout := p.GetOrTimeout(83)
			c.So(timeout, c.ShouldBeFalse)
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldEqual, CANCELLED)
			c.So(p.IsCancelled(), c.ShouldBeTrue)
		})
	})
}

func TestGetChan(t *testing.T) {
	timout := 50 * time.Millisecond
	c.Convey("When Promise is resolved", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Resolve("ok")
		}()
		c.Convey("Should receive the argument of Resolve from returned channel", func() {
			fr, ok := <-p.GetChan()
			c.So(fr.Result, c.ShouldEqual, "ok")
			c.So(fr.Typ, c.ShouldEqual, RESULT_SUCCESS)
			c.So(ok, c.ShouldBeTrue)
		})
	})

	c.Convey("When Promise is rejected", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Reject(errors.New("fail"))
		}()
		c.Convey("Should receive error from returned channel", func() {
			fr, ok := <-p.GetChan()
			c.So(fr.Result, c.ShouldNotBeNil)
			c.So(fr.Typ, c.ShouldEqual, RESULT_FAILURE)
			c.So(ok, c.ShouldBeTrue)
		})
	})

	c.Convey("When Promise is cancelled", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Cancel()
		}()
		c.Convey("Should receive CancelledError from returned channel", func() {
			fr, ok := <-p.GetChan()
			c.So(fr.Result, c.ShouldEqual, CANCELLED)
			c.So(p.IsCancelled(), c.ShouldBeTrue)
			c.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED)
			c.So(ok, c.ShouldBeTrue)
		})

		c.Convey("Should receive CancelledError from returned channel at second time", func() {
			fr, ok := <-p.GetChan()
			c.So(fr.Result, c.ShouldEqual, CANCELLED)
			c.So(p.IsCancelled(), c.ShouldBeTrue)
			c.So(fr.Typ, c.ShouldEqual, RESULT_CANCELLED)
			c.So(ok, c.ShouldBeTrue)
		})
	})
}

func TestFuture(t *testing.T) {
	c.Convey("Future can receive return value and status but cannot change the status", t, func() {
		var fu *Future
		c.Convey("When Future is resolved", func() {
			func() {
				p := NewPromise()
				go func() {
					time.Sleep(50 * time.Millisecond)
					p.Resolve("ok")
				}()
				fu = p.Future
			}()
			r, err := fu.Get()
			c.So(r, c.ShouldEqual, "ok")
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When Future is rejected", func() {
			func() {
				p := NewPromise()
				go func() {
					time.Sleep(50 * time.Millisecond)
					p.Reject(errors.New("fail"))
				}()
				fu = p.Future
			}()
			r, err := fu.Get()
			c.So(err, c.ShouldNotBeNil)
			c.So(r, c.ShouldEqual, nil)
		})

		c.Convey("When Future is cancelled", func() {
			func() {
				p := NewPromise()
				go func() {
					time.Sleep(50 * time.Millisecond)
					p.Cancel()
				}()
				fu = p.Future
			}()
			r, err := fu.Get()
			c.So(err, c.ShouldNotBeNil)
			c.So(r, c.ShouldEqual, nil)
		})
	})

}

func TestCallbacks(t *testing.T) {
	timout := 50 * time.Millisecond
	done, always, fail, cancel := false, false, false, false

	p := NewPromise()
	go func() {
		<-time.After(timout)
		p.Resolve("ok")
	}()

	c.Convey("When Promise is resolved", t, func() {
		p.OnSuccess(func(v interface{}) {
			done = true
			c.Convey("The argument of Done should be 'ok'", t, func() {
				c.So(v, c.ShouldEqual, "ok")
			})
		}).OnComplete(func(v interface{}) {
			always = true
			c.Convey("The argument of Always should be 'ok'", t, func() {
				c.So(v, c.ShouldEqual, "ok")
			})
		}).OnFailure(func(v interface{}) {
			fail = true
			panic("Unexpected calling")
		})
		r, err := p.Get()

		//The code after Get() and the callback will be concurrent run
		//So sleep 52 ms to wait all callback be done
		time.Sleep(52 * time.Millisecond)

		c.Convey("Should call the Done and Always callbacks", func() {
			c.So(r, c.ShouldEqual, "ok")
			c.So(err, c.ShouldBeNil)
			c.So(done, c.ShouldEqual, true)
			c.So(always, c.ShouldEqual, true)
			c.So(fail, c.ShouldEqual, false)
		})
	})

	c.Convey("When adding the callback after Promise is resolved", t, func() {
		done, always, fail := false, false, false
		p.OnSuccess(func(v interface{}) {
			done = true
			c.Convey("The argument of Done should be 'ok'", func() {
				c.So(v, c.ShouldEqual, "ok")
			})
		}).OnComplete(func(v interface{}) {
			always = true
			c.Convey("The argument of Always should be 'ok'", func() {
				c.So(v, c.ShouldEqual, "ok")
			})
		}).OnFailure(func(v interface{}) {
			fail = true
			panic("Unexpected calling")
		})
		c.Convey("Should immediately run the Done and Always callbacks", func() {
			c.So(done, c.ShouldEqual, true)
			c.So(always, c.ShouldEqual, true)
			c.So(fail, c.ShouldEqual, false)
		})
	})

	var e *error = nil
	done, always, fail = false, false, false
	p = NewPromise()
	go func() {
		<-time.After(timout)
		p.Reject(errors.New("fail"))
	}()

	c.Convey("When Promise is rejected", t, func() {
		p.OnSuccess(func(v interface{}) {
			done = true
			panic("Unexpected calling")
		}).OnComplete(func(v interface{}) {
			always = true
			c.Convey("The argument of Always should be error", t, func() {
				c.So(v, c.ShouldImplement, e)
			})
		}).OnFailure(func(v interface{}) {
			fail = true
			c.Convey("The argument of Fail should be error", t, func() {
				c.So(v, c.ShouldImplement, e)
			})
		})
		r, err := p.Get()

		time.Sleep(52 * time.Millisecond)

		c.Convey("Should call the Fail and Always callbacks", func() {
			c.So(r, c.ShouldEqual, nil)
			c.So(err, c.ShouldNotBeNil)
			c.So(done, c.ShouldEqual, false)
			c.So(always, c.ShouldEqual, true)
			c.So(fail, c.ShouldEqual, true)
		})
	})

	c.Convey("When adding the callback after Promise is rejected", t, func() {
		done, always, fail = false, false, false
		p.OnSuccess(func(v interface{}) {
			done = true
			panic("Unexpected calling")
		}).OnComplete(func(v interface{}) {
			always = true
			c.Convey("The argument of Always should be error", func() {
				c.So(v, c.ShouldImplement, e)
			})
		}).OnFailure(func(v interface{}) {
			fail = true
			c.Convey("The argument of Fail should be error", func() {
				c.So(v, c.ShouldImplement, e)
			})
		})
		c.Convey("Should immediately run the Fail and Always callbacks", func() {
			c.So(done, c.ShouldEqual, false)
			c.So(always, c.ShouldEqual, true)
			c.So(fail, c.ShouldEqual, true)
		})
	})

	done, always, fail = false, false, false
	p = NewPromise()
	go func() {
		<-time.After(timout)
		p.Cancel()
	}()

	c.Convey("When Promise is cancelled", t, func() {
		done, always, fail, cancel = false, false, false, false
		p.OnSuccess(func(v interface{}) {
			done = true
		}).OnComplete(func(v interface{}) {
			always = true
		}).OnFailure(func(v interface{}) {
			fail = true
		}).OnCancel(func() {
			cancel = true
		})
		r, err := p.Get()

		time.Sleep(62 * time.Millisecond)

		c.Convey("Only cancel callback be called", func() {
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
			c.So(done, c.ShouldEqual, false)
			c.So(always, c.ShouldEqual, false)
			c.So(fail, c.ShouldEqual, false)
			c.So(cancel, c.ShouldEqual, true)
		})
	})

	c.Convey("When adding the callback after Promise is cancelled", t, func() {
		done, always, fail, cancel = false, false, false, false
		p.OnSuccess(func(v interface{}) {
			done = true
		}).OnComplete(func(v interface{}) {
			always = true
		}).OnFailure(func(v interface{}) {
			fail = true
		}).OnCancel(func() {
			cancel = true
		})
		c.Convey("Should not call any callbacks", func() {
			c.So(done, c.ShouldEqual, false)
			c.So(always, c.ShouldEqual, false)
			c.So(fail, c.ShouldEqual, false)
			c.So(cancel, c.ShouldEqual, true)
		})
	})

}

func TestStart(t *testing.T) {

	c.Convey("Test start func()", t, func() {
		c.Convey("When task completed", func() {
			f := Start(func() {})
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldBeNil)
		})
		c.Convey("When task panic error", func() {
			f := Start(func() { panic("fail") })
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})
	})

	c.Convey("Test start func()(interface{}, error)", t, func() {
		c.Convey("When task completed", func() {
			f := Start(func() (interface{}, error) {
				time.Sleep(10)
				return "ok", nil
			})
			r, err := f.Get()
			c.So(r, c.ShouldEqual, "ok")
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When task returned error", func() {
			f := Start(func() (interface{}, error) {
				time.Sleep(10)
				return "fail", errors.New("fail")
			})
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})

		c.Convey("When task panic error", func() {
			f := Start(func() (interface{}, error) { panic("fail") })
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})
	})

	c.Convey("Test start func(canceller Canceller)", t, func() {
		c.Convey("When task completed", func() {
			f := Start(func(canceller Canceller) {
				time.Sleep(10)
			})
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When task be cancelled", func() {
			f := Start(func(canceller Canceller) {
				time.Sleep(10)
				if canceller.IsCancelled() {
					return
				}
			})
			f.Cancel()
			r, err := f.Get()
			c.So(f.IsCancelled(), c.ShouldBeTrue)
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldEqual, CANCELLED)
			c.So(f.IsCancelled(), c.ShouldBeTrue)
		})
		c.Convey("When task panic error", func() {
			f := Start(func(canceller Canceller) { panic("fail") })
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})
	})

	c.Convey("Test start func(canceller Canceller)(interface{}, error)", t, func() {
		c.Convey("When task be cancenlled", func() {
			task := func(canceller Canceller) (interface{}, error) {
				i := 0
				for i < 50 {
					if canceller.IsCancelled() {
						return nil, nil
					}
					time.Sleep(100 * time.Millisecond)
				}
				panic("exception")
			}

			f := Start(task)
			f.Cancel()
			r, err := f.Get()

			c.So(f.IsCancelled(), c.ShouldBeTrue)
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldEqual, CANCELLED)
			c.So(f.IsCancelled(), c.ShouldBeTrue)
		})

		c.Convey("When task panic error", func() {
			f := Start(func(canceller Canceller) (interface{}, error) {
				panic("fail")
			})
			r, err := f.Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldNotBeNil)
		})
	})

}

func TestPipe(t *testing.T) {
	timout := 50 * time.Millisecond
	taskDonePipe := func(v interface{}) *Future {
		return Start(func() (interface{}, error) {
			<-time.After(timout)
			return v.(string) + "2", nil
		})
	}

	taskFailPipe := func() (interface{}, error) {
		<-time.After(timout)
		return "fail2", nil
	}

	c.Convey("When task completed", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Resolve("ok")
		}()
		fu, ok := p.Pipe(taskDonePipe, taskFailPipe)
		r, err := fu.Get()
		c.Convey("the done callback will be called, the future returned by done callback will be returned as chain future", func() {
			c.So(r, c.ShouldEqual, "ok2")
			c.So(err, c.ShouldBeNil)
			c.So(ok, c.ShouldEqual, true)
		})
	})

	c.Convey("When task failed", t, func() {
		p := NewPromise()
		go func() {
			<-time.After(timout)
			p.Reject(errors.New("fail"))
		}()
		fu, ok := p.Pipe(taskDonePipe, taskFailPipe)
		r, err := fu.Get()

		c.Convey("the fail callback will be called, the future returned by fail callback will be returned as chain future", func() {
			c.So(r, c.ShouldEqual, "fail2")
			c.So(err, c.ShouldBeNil)
			c.So(ok, c.ShouldEqual, true)
		})
	})

	c.Convey("Test pipe twice", t, func() {
		p := NewPromise()
		pipeFuture1, ok1 := p.Pipe(taskDonePipe, taskFailPipe)
		c.Convey("Calling Pipe succeed at first time", func() {
			c.So(ok1, c.ShouldEqual, true)
		})
		pipeFuture2, ok2 := p.Pipe(taskDonePipe, taskFailPipe)
		c.Convey("Calling Pipe succeed at second time", func() {
			c.So(ok2, c.ShouldEqual, true)
		})
		p.Resolve("ok")

		r, _ := pipeFuture1.Get()
		c.Convey("Pipeline future 1 should return ok2", func() {
			c.So(r, c.ShouldEqual, "ok2")
		})

		r2, _ := pipeFuture2.Get()
		c.Convey("Pipeline future 2 should return ok2", func() {
			c.So(r2, c.ShouldEqual, "ok2")
		})
	})
}

func TestWhenAny(t *testing.T) {
	c.Convey("Test WhenAny", t, func() {
		whenAnyTasks := func(t1 int, t2 int) *Future {
			timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}
			getTask := func(i int) func() (interface{}, error) {
				return func() (interface{}, error) {
					if timeouts[i] > 0 {
						time.Sleep(timeouts[i] * time.Millisecond)
						return "ok" + strconv.Itoa(i), nil
					} else {
						time.Sleep((-1 * timeouts[i]) * time.Millisecond)
						return nil, newMyError("fail" + strconv.Itoa(i))
					}
				}
			}
			task0 := getTask(0)
			task1 := getTask(1)
			f := WhenAny(task0, task1)
			return f
		}

		c.Convey("When all tasks completed, and task 1 be first to complete", func() {
			r, err := whenAnyTasks(200, 250).Get()
			c.So(r, c.ShouldEqual, "ok0")
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When all tasks completed, and task 2 be first to complete", func() {
			r, err := whenAnyTasks(280, 250).Get()
			c.So(r, c.ShouldEqual, "ok1")
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When all tasks failed", func() {
			r, err := whenAnyTasks(-280, -250).Get()
			errs := err.(*NoMatchedError).Results
			c.So(r, c.ShouldBeNil)
			c.So(errs[0].(*myError).val, c.ShouldEqual, "fail0")
			c.So(errs[1].(*myError).val, c.ShouldEqual, "fail1")
		})

		c.Convey("When one task completed", func() {
			r, err := whenAnyTasks(-280, 150).Get()
			c.So(r, c.ShouldEqual, "ok1")
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When no task be passed", func() {
			r, err := WhenAny().Get()
			c.So(r, c.ShouldBeNil)
			c.So(err, c.ShouldBeNil)
		})
	})

	c.Convey("Test WhenAny, and task can be cancelled", t, func() {
		var c1, c2 bool
		whenAnyCanCancelTasks := func(t1 int, t2 int) *Future {
			timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}
			getTask := func(i int) func(canceller Canceller) (interface{}, error) {
				return func(canceller Canceller) (interface{}, error) {
					for j := 0; j < 10; j++ {
						if timeouts[i] > 0 {
							time.Sleep(timeouts[i] * time.Millisecond)
						} else {
							time.Sleep((-1 * timeouts[i]) * time.Millisecond)
						}
						if canceller.IsCancelled() {
							if i == 0 {
								c1 = true
							} else {
								c2 = true
							}
							return nil, nil
						}
					}
					if timeouts[i] > 0 {
						return "ok" + strconv.Itoa(i), nil
					} else {
						return nil, newMyError("fail" + strconv.Itoa(i))
					}
				}
			}
			task0 := getTask(0)
			task1 := getTask(1)
			f := WhenAny(Start(task0), Start(task1))
			return f
		}
		c.Convey("When task 1 is the first to complete, task 2 will be cancelled", func() {
			r, err := whenAnyCanCancelTasks(10, 250).Get()

			c.So(r, c.ShouldEqual, "ok0")
			c.So(err, c.ShouldBeNil)
			time.Sleep(1000 * time.Millisecond)
			c.So(c2, c.ShouldEqual, true)
		})

		c.Convey("When task 2 is the first to complete, task 1 will be cancelled", func() {
			r, err := whenAnyCanCancelTasks(200, 10).Get()

			c.So(r, c.ShouldEqual, "ok1")
			c.So(err, c.ShouldBeNil)
			time.Sleep(1000 * time.Millisecond)
			c.So(c1, c.ShouldEqual, true)
		})

	})
}

func TestWhenAnyTrue(t *testing.T) {
	c1, c2 := false, false
	startTwoCanCancelTask := func(t1 int, t2 int, predicate func(interface{}) bool) *Future {
		timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}
		getTask := func(i int) func(canceller Canceller) (interface{}, error) {
			return func(canceller Canceller) (interface{}, error) {
				for j := 0; j < 10; j++ {
					if timeouts[i] > 0 {
						time.Sleep(timeouts[i] * time.Millisecond)
					} else {
						time.Sleep((-1 * timeouts[i]) * time.Millisecond)
					}
					if canceller.IsCancelled() {
						if i == 0 {
							c1 = true
						} else {
							c2 = true
						}
						return nil, nil
					}
				}
				if timeouts[i] > 0 {
					return "ok" + strconv.Itoa(i), nil
				} else {
					return nil, newMyError("fail" + strconv.Itoa(i))
				}
			}
		}
		task0 := getTask(0)
		task1 := getTask(1)
		f := WhenAnyMatched(predicate, Start(task0), Start(task1))
		return f
	}
	//第一个任务先完成,第二个后完成,并且设定条件为返回值==第一个的返回值
	c.Convey("When the task1 is the first to complete, and predicate returns true", t, func() {
		r, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool {
			return v.(string) == "ok0"
		}).Get()
		c.So(r, c.ShouldEqual, "ok0")
		c.So(err, c.ShouldBeNil)
		time.Sleep(1000 * time.Millisecond)
		c.So(c2, c.ShouldEqual, true)
	})

	//第一个任务后完成,第二个先完成,并且设定条件为返回值==第二个的返回值
	c.Convey("When the task2 is the first to complete, and predicate returns true", t, func() {
		c1, c2 = false, false
		r, err := startTwoCanCancelTask(230, 50, func(v interface{}) bool {
			return v.(string) == "ok1"
		}).Get()
		c.So(r, c.ShouldEqual, "ok1")
		c.So(err, c.ShouldBeNil)
		time.Sleep(1000 * time.Millisecond)
		c.So(c1, c.ShouldEqual, true)
	})

	//第一个任务后完成,第二个先完成,并且设定条件为返回值不等于任意一个任务的返回值
	c.Convey("When the task2 is the first to complete, and predicate always returns false", t, func() {
		c1, c2 = false, false
		r, err := startTwoCanCancelTask(30, 250, func(v interface{}) bool {
			return v.(string) == "ok11"
		}).Get()

		_, ok := err.(*NoMatchedError)
		c.So(r, c.ShouldBeNil)
		c.So(ok, c.ShouldBeTrue)
		c.So(err, c.ShouldNotBeNil)

		time.Sleep(1000 * time.Millisecond)
		c.So(c1, c.ShouldEqual, false)
		c.So(c2, c.ShouldEqual, false)
	})

	//c.Convey("When all tasks be cancelled", t, func() {
	//	getTask := func(canceller Canceller) (interface{}, error) {
	//		for {
	//			time.Sleep(50 * time.Millisecond)
	//			if canceller.IsCancellationRequested() {
	//				canceller.Cancel()
	//				return nil, nil
	//			}
	//		}
	//	}

	//	f1 := Start(getTask)
	//	f2 := Start(getTask)
	//	f3 := WhenAnyMatched(nil, f1, f2)

	//	f1.RequestCancel()
	//	f2.RequestCancel()

	//	r, _ := f3.Get()
	//	c.So(r, c.ShouldBeNil)
	//})

}

func TestWhenAll(t *testing.T) {
	startTwoTask := func(t1 int, t2 int) (f *Future) {
		timeouts := []time.Duration{time.Duration(t1), time.Duration(t2)}
		getTask := func(i int) func() (interface{}, error) {
			return func() (interface{}, error) {
				if timeouts[i] > 0 {
					time.Sleep(timeouts[i] * time.Millisecond)
					return "ok" + strconv.Itoa(i), nil
				} else {
					time.Sleep((-1 * timeouts[i]) * time.Millisecond)
					return nil, newMyError("fail" + strconv.Itoa(i))
				}
			}
		}
		task0 := getTask(0)
		task1 := getTask(1)
		f = WhenAll(task0, task1)
		return f
	}
	c.Convey("Test WhenAllFuture", t, func() {
		whenTwoTask := func(t1 int, t2 int) *Future {
			return startTwoTask(t1, t2)
		}
		c.Convey("When all tasks completed, and the task1 is the first to complete", func() {
			r, err := whenTwoTask(200, 230).Get()
			c.So(r, shouldSlicesReSame, []interface{}{"ok0", "ok1"})
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When all tasks completed, and the task1 is the first to complete", func() {
			r, err := whenTwoTask(230, 200).Get()
			c.So(r, shouldSlicesReSame, []interface{}{"ok0", "ok1"})
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When task1 failed, but task2 is completed", func() {
			r, err := whenTwoTask(-250, 210).Get()
			c.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, "fail0")
			c.So(r, c.ShouldBeNil)
		})

		c.Convey("When all tasks failed", func() {
			r, err := whenTwoTask(-250, -110).Get()
			c.So(err.(*AggregateError).InnerErrs[0].(*myError).val, c.ShouldEqual, "fail1")
			c.So(r, c.ShouldBeNil)
		})

		c.Convey("When no task be passed", func() {
			r, err := whenAllFuture().Get()
			c.So(r, shouldSlicesReSame, []interface{}{})
			c.So(err, c.ShouldBeNil)
		})

		c.Convey("When all tasks be cancelled", func() {
			getTask := func(canceller Canceller) (interface{}, error) {
				for {
					time.Sleep(50 * time.Millisecond)
					if canceller.IsCancelled() {
						return nil, nil
					}
				}
			}

			f1 := Start(getTask)
			f2 := Start(getTask)
			f3 := WhenAll(f1, f2)

			f1.Cancel()
			f2.Cancel()

			r, _ := f3.Get()
			c.So(r, c.ShouldBeNil)
		})
	})
}

func TestWrap(t *testing.T) {
	c.Convey("Test Wrap a value", t, func() {
		r, err := Wrap(10).Get()
		c.So(r, c.ShouldEqual, 10)
		c.So(err, c.ShouldBeNil)
	})
}

func shouldSlicesReSame(actual interface{}, expected ...interface{}) string {
	actualSlice, expectedSlice := reflect.ValueOf(actual), reflect.ValueOf(expected[0])
	if actualSlice.Kind() != expectedSlice.Kind() {
		return fmt.Sprintf("Expected1: '%v'\nActual:   '%v'\n", expected[0], actual)
	}

	if actualSlice.Kind() != reflect.Slice {
		return fmt.Sprintf("Expected2: '%v'\nActual:   '%v'\n", expected[0], actual)
	}

	if actualSlice.Len() != expectedSlice.Len() {
		return fmt.Sprintf("Expected3: '%v'\nActual:   '%v'\n", expected[0], actual)
	}

	for i := 0; i < actualSlice.Len(); i++ {
		if !reflect.DeepEqual(actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface()) {
			return fmt.Sprintf("Expected4: '%v'\nActual:   '%v'\n", expected[0], actual)
		}
	}
	return ""
}


================================================
FILE: promise.go
================================================
package promise

import (
	"math/rand"
	"unsafe"
)

var (
	CANCELLED error = &CancelledError{}
)

//CancelledError present the Future object is cancelled.
type CancelledError struct {
}

func (e *CancelledError) Error() string {
	return "Task be cancelled"
}

//resultType present the type of Future final status.
type resultType int

const (
	RESULT_SUCCESS resultType = iota
	RESULT_FAILURE
	RESULT_CANCELLED
)

//PromiseResult presents the result of a promise.
//If Typ is RESULT_SUCCESS, Result field will present the returned value of Future task.
//If Typ is RESULT_FAILURE, Result field will present a related error .
//If Typ is RESULT_CANCELLED, Result field will be null.
type PromiseResult struct {
	Result interface{} //result of the Promise
	Typ    resultType  //success, failure, or cancelled?
}

//Promise presents an object that acts as a proxy for a result.
//that is initially unknown, usually because the computation of its
//value is yet incomplete (refer to wikipedia).
//You can use Resolve/Reject/Cancel to set the final result of Promise.
//Future can return a read-only placeholder view of result.
type Promise struct {
	*Future
}

//Cancel sets the status of promise to RESULT_CANCELLED.
//If promise is cancelled, Get() will return nil and CANCELLED error.
//All callback functions will be not called if Promise is cancalled.
func (this *Promise) Cancel() (e error) {
	return this.Future.Cancel()
}

//Resolve sets the value for promise, and the status will be changed to RESULT_SUCCESS.
//if promise is resolved, Get() will return the value and nil error.
func (this *Promise) Resolve(v interface{}) (e error) {
	return this.setResult(&PromiseResult{v, RESULT_SUCCESS})
}

//Resolve sets the error for promise, and the status will be changed to RESULT_FAILURE.
//if promise is rejected, Get() will return nil and the related error value.
func (this *Promise) Reject(err error) (e error) {
	return this.setResult(&PromiseResult{err, RESULT_FAILURE})
}

//OnSuccess registers a callback function that will be called when Promise is resolved.
//If promise is already resolved, the callback will immediately called.
//The value of Promise will be paramter of Done callback function.
func (this *Promise) OnSuccess(callback func(v interface{})) *Promise {
	this.Future.OnSuccess(callback)
	return this
}

//OnFailure registers a callback function that will be called when Promise is rejected.
//If promise is already rejected, the callback will immediately called.
//The error of Promise will be paramter of Fail callback function.
func (this *Promise) OnFailure(callback func(v interface{})) *Promise {
	this.Future.OnFailure(callback)
	return this
}

//OnComplete register a callback function that will be called when Promise is rejected or resolved.
//If promise is already rejected or resolved, the callback will immediately called.
//According to the status of Promise, value or error will be paramter of Always callback function.
//Value is the paramter if Promise is resolved, or error is the paramter if Promise is rejected.
//Always callback will be not called if Promise be called.
func (this *Promise) OnComplete(callback func(v interface{})) *Promise {
	this.Future.OnComplete(callback)
	return this
}

//OnCancel registers a callback function that will be called when Promise is cancelled.
//If promise is already cancelled, the callback will immediately called.
func (this *Promise) OnCancel(callback func()) *Promise {
	this.Future.OnCancel(callback)
	return this
}

//NewPromise is factory function for Promise
func NewPromise() *Promise {
	val := &futureVal{
		make([]func(v interface{}), 0, 8),
		make([]func(v interface{}), 0, 8),
		make([]func(v interface{}), 0, 4),
		make([]func(), 0, 2),
		make([]*pipe, 0, 4), nil,
	}
	f := &Promise{
		&Future{
			rand.Int(),
			make(chan struct{}),
			unsafe.Pointer(val),
		},
	}
	return f
}


================================================
FILE: utils.go
================================================
package promise

import (
	"bytes"
	"errors"
	"fmt"
	"runtime"
	"strconv"
)

//NoMatchedError presents no future that returns matched result in WhenAnyTrue function.
type NoMatchedError struct {
	Results []interface{}
}

func (e *NoMatchedError) Error() string {
	return "No matched future"
}

func (e *NoMatchedError) HasError() bool {
	for _, ie := range e.Results {
		if _, ok1 := ie.(error); ok1 {
			return true
		}
	}
	return false
}

func newNoMatchedError(results []interface{}) *NoMatchedError {
	return &NoMatchedError{results}
}

func newNoMatchedError1(e interface{}) *NoMatchedError {
	return &NoMatchedError{[]interface{}{e}}
}

//AggregateError aggregate multi errors into an error
type AggregateError struct {
	s         string
	InnerErrs []error
}

func (e *AggregateError) Error() string {
	if e.InnerErrs == nil {
		return e.s
	} else {
		buf := bytes.NewBufferString(e.s)
		buf.WriteString("\n\n")
		for i, ie := range e.InnerErrs {
			if ie == nil {
				continue
			}
			buf.WriteString("error appears in Future ")
			buf.WriteString(strconv.Itoa(i))
			buf.WriteString(": ")
			buf.WriteString(ie.Error())
			buf.WriteString("\n")
		}
		buf.WriteString("\n")
		return buf.String()
	}
}

func newAggregateError(s string, innerErrors []error) *AggregateError {
	return &AggregateError{newErrorWithStacks(s).Error(), innerErrors}
}

func newAggregateError1(s string, e interface{}) *AggregateError {
	return &AggregateError{newErrorWithStacks(s).Error(), []error{getError(e)}}
}

func newErrorWithStacks(i interface{}) (e error) {
	err := getError(i)
	buf := bytes.NewBufferString(err.Error())
	buf.WriteString("\n")

	pcs := make([]uintptr, 50)
	num := runtime.Callers(2, pcs)
	for _, v := range pcs[0:num] {
		fun := runtime.FuncForPC(v)
		file, line := fun.FileLine(v)
		name := fun.Name()
		//fmt.Println(name, file + ":", line)
		writeStrings(buf, []string{name, " ", file, ":", strconv.Itoa(line), "\n"})
	}
	return errors.New(buf.String())
}

func getAct(pr *Promise, act interface{}) (f func() (r interface{}, err error)) {
	var (
		act1 func() (interface{}, error)
		act2 func(Canceller) (interface{}, error)
	)
	canCancel := false

	//convert the act to the function that has return value and error if act function haven't return value and error
	switch v := act.(type) {
	case func() (interface{}, error):
		act1 = v
	case func(Canceller) (interface{}, error):
		canCancel = true
		act2 = v
	case func():
		act1 = func() (interface{}, error) {
			v()
			return nil, nil
		}
	case func(Canceller):
		canCancel = true
		act2 = func(canceller Canceller) (interface{}, error) {
			v(canceller)
			return nil, nil
		}
	default:
		if e, ok := v.(error); !ok {
			pr.Resolve(v)
		} else {
			pr.Reject(e)
		}
		return nil
	}

	//If paramters of act function has a Canceller interface, the Future will can be cancelled.
	var canceller Canceller = nil
	if pr != nil && canCancel {
		//pr.EnableCanceller()
		canceller = pr.Canceller()
	}

	//return proxy function of act function
	f = func() (r interface{}, err error) {
		defer func() {
			if e := recover(); e != nil {
				err = newErrorWithStacks(e)
			}
		}()

		if canCancel {
			r, err = act2(canceller)
		} else {
			r, err = act1()
		}

		return
	}
	return
}

func startPipe(r *PromiseResult, pipeTask func(v interface{}) *Future, pipePromise *Promise) {
	//处理链式异步任务
	if pipeTask != nil {
		f := pipeTask(r.Result)
		f.OnSuccess(func(v interface{}) {
			pipePromise.Resolve(v)
		}).OnFailure(func(v interface{}) {
			pipePromise.Reject(getError(v))
		})
	}

}

func getFutureReturnVal(r *PromiseResult) (interface{}, error) {
	if r.Typ == RESULT_SUCCESS {
		return r.Result, nil
	} else if r.Typ == RESULT_FAILURE {
		return nil, getError(r.Result)
	} else {
		return nil, getError(r.Result) //&CancelledError{}
	}
}

//执行回调函数
func execCallback(r *PromiseResult,
	dones []func(v interface{}),
	fails []func(v interface{}),
	always []func(v interface{}),
	cancels []func()) {

	if r.Typ == RESULT_CANCELLED {
		for _, f := range cancels {
			func() {
				defer func() {
					if e := recover(); e != nil {
						err := newErrorWithStacks(e)
						fmt.Println("error happens:\n ", err)
					}
				}()
				f()
			}()
		}
		return
	}

	var callbacks []func(v interface{})
	if r.Typ == RESULT_SUCCESS {
		callbacks = dones
	} else {
		callbacks = fails
	}

	forFs := func(s []func(v interface{})) {
		forSlice(s, func(f func(v interface{})) { f(r.Result) })
	}

	forFs(callbacks)
	forFs(always)

}

func forSlice(s []func(v interface{}), f func(func(v interface{}))) {
	for _, e := range s {
		func() {
			defer func() {
				if e := recover(); e != nil {
					err := newErrorWithStacks(e)
					fmt.Println("error happens:\n ", err)
				}
			}()
			f(e)
		}()
	}
}

//Error handling struct and functions------------------------------
type stringer interface {
	String() string
}

func getError(i interface{}) (e error) {
	if i != nil {
		switch v := i.(type) {
		case error:
			e = v
		case string:
			e = errors.New(v)
		default:
			if s, ok := i.(stringer); ok {
				e = errors.New(s.String())
			} else {
				e = errors.New(fmt.Sprintf("%v", i))
			}
		}
	}
	return
}

func writeStrings(buf *bytes.Buffer, strings []string) {
	for _, s := range strings {
		buf.WriteString(s)
	}
}
Download .txt
gitextract__0ann36z/

├── .gitignore
├── LICENSE
├── README.md
├── future.go
├── future_factory.go
├── future_test.go
├── promise.go
└── utils.go
Download .txt
SYMBOL INDEX (94 symbols across 5 files)

FILE: future.go
  type callbackType (line 23) | type callbackType
  constant CALLBACK_DONE (line 26) | CALLBACK_DONE callbackType = iota
  constant CALLBACK_FAIL (line 27) | CALLBACK_FAIL
  constant CALLBACK_ALWAYS (line 28) | CALLBACK_ALWAYS
  constant CALLBACK_CANCEL (line 29) | CALLBACK_CANCEL
  type pipe (line 33) | type pipe struct
    method getPipe (line 39) | func (this *pipe) getPipe(isResolved bool) (func(v interface{}) *Futur...
  type Canceller (line 50) | type Canceller interface
  type canceller (line 57) | type canceller struct
    method Cancel (line 62) | func (this *canceller) Cancel() {
    method IsCancelled (line 67) | func (this *canceller) IsCancelled() (r bool) {
  type futureVal (line 72) | type futureVal struct
  type Future (line 81) | type Future struct
    method Canceller (line 91) | func (this *Future) Canceller() Canceller {
    method IsCancelled (line 96) | func (this *Future) IsCancelled() bool {
    method SetTimeout (line 108) | func (this *Future) SetTimeout(mm int) *Future {
    method GetChan (line 123) | func (this *Future) GetChan() <-chan *PromiseResult {
    method Get (line 137) | func (this *Future) Get() (val interface{}, err error) {
    method GetOrTimeout (line 145) | func (this *Future) GetOrTimeout(mm uint) (val interface{}, err error,...
    method Cancel (line 164) | func (this *Future) Cancel() (e error) {
    method OnSuccess (line 171) | func (this *Future) OnSuccess(callback func(v interface{})) *Future {
    method OnFailure (line 179) | func (this *Future) OnFailure(callback func(v interface{})) *Future {
    method OnComplete (line 189) | func (this *Future) OnComplete(callback func(v interface{})) *Future {
    method OnCancel (line 196) | func (this *Future) OnCancel(callback func()) *Future {
    method Pipe (line 204) | func (this *Future) Pipe(callbacks ...interface{}) (result *Future, ok...
    method loadResult (line 288) | func (this *Future) loadResult() *PromiseResult {
    method loadVal (line 294) | func (this *Future) loadVal() *futureVal {
    method setResult (line 300) | func (this *Future) setResult(r *PromiseResult) (e error) { //r *Promi...
    method addCallback (line 349) | func (this *Future) addCallback(callback interface{}, t callbackType) {

FILE: future_factory.go
  type anyPromiseResult (line 7) | type anyPromiseResult struct
  function Start (line 32) | func Start(act interface{}, syncs ...bool) *Future {
  function Wrap (line 72) | func Wrap(value interface{}) *Future {
  function WhenAny (line 87) | func WhenAny(acts ...interface{}) *Future {
  function WhenAnyMatched (line 96) | func WhenAnyMatched(predicate func(interface{}) bool, acts ...interface{...
  function WhenAll (line 207) | func WhenAll(acts ...interface{}) (fu *Future) {
  function whenAllFuture (line 229) | func whenAllFuture(fs ...*Future) *Future {

FILE: future_test.go
  constant TASK_END (line 14) | TASK_END      = "task be end,"
  constant CALL_DONE (line 15) | CALL_DONE     = "callback done,"
  constant CALL_FAIL (line 16) | CALL_FAIL     = "callback fail,"
  constant CALL_ALWAYS (line 17) | CALL_ALWAYS   = "callback always,"
  constant WAIT_TASK (line 18) | WAIT_TASK     = "wait task end,"
  constant GET (line 19) | GET           = "get task result,"
  constant DONE_Pipe_END (line 20) | DONE_Pipe_END = "task Pipe done be end,"
  constant FAIL_Pipe_END (line 21) | FAIL_Pipe_END = "task Pipe fail be end,"
  type myError (line 25) | type myError struct
    method Error (line 29) | func (e *myError) Error() string {
  function newMyError (line 33) | func newMyError(v interface{}) *myError {
  function TestResolveAndReject (line 37) | func TestResolveAndReject(t *testing.T) {
  function TestCancel (line 65) | func TestCancel(t *testing.T) {
  function TestGetOrTimeout (line 82) | func TestGetOrTimeout(t *testing.T) {
  function TestGetChan (line 135) | func TestGetChan(t *testing.T) {
  function TestFuture (line 189) | func TestFuture(t *testing.T) {
  function TestCallbacks (line 237) | func TestCallbacks(t *testing.T) {
  function TestStart (line 412) | func TestStart(t *testing.T) {
  function TestPipe (line 525) | func TestPipe(t *testing.T) {
  function TestWhenAny (line 594) | func TestWhenAny(t *testing.T) {
  function TestWhenAnyTrue (line 702) | func TestWhenAnyTrue(t *testing.T) {
  function TestWhenAll (line 799) | func TestWhenAll(t *testing.T) {
  function TestWrap (line 875) | func TestWrap(t *testing.T) {
  function shouldSlicesReSame (line 883) | func shouldSlicesReSame(actual interface{}, expected ...interface{}) str...

FILE: promise.go
  type CancelledError (line 13) | type CancelledError struct
    method Error (line 16) | func (e *CancelledError) Error() string {
  type resultType (line 21) | type resultType
  constant RESULT_SUCCESS (line 24) | RESULT_SUCCESS resultType = iota
  constant RESULT_FAILURE (line 25) | RESULT_FAILURE
  constant RESULT_CANCELLED (line 26) | RESULT_CANCELLED
  type PromiseResult (line 33) | type PromiseResult struct
  type Promise (line 43) | type Promise struct
    method Cancel (line 50) | func (this *Promise) Cancel() (e error) {
    method Resolve (line 56) | func (this *Promise) Resolve(v interface{}) (e error) {
    method Reject (line 62) | func (this *Promise) Reject(err error) (e error) {
    method OnSuccess (line 69) | func (this *Promise) OnSuccess(callback func(v interface{})) *Promise {
    method OnFailure (line 77) | func (this *Promise) OnFailure(callback func(v interface{})) *Promise {
    method OnComplete (line 87) | func (this *Promise) OnComplete(callback func(v interface{})) *Promise {
    method OnCancel (line 94) | func (this *Promise) OnCancel(callback func()) *Promise {
  function NewPromise (line 100) | func NewPromise() *Promise {

FILE: utils.go
  type NoMatchedError (line 12) | type NoMatchedError struct
    method Error (line 16) | func (e *NoMatchedError) Error() string {
    method HasError (line 20) | func (e *NoMatchedError) HasError() bool {
  function newNoMatchedError (line 29) | func newNoMatchedError(results []interface{}) *NoMatchedError {
  function newNoMatchedError1 (line 33) | func newNoMatchedError1(e interface{}) *NoMatchedError {
  type AggregateError (line 38) | type AggregateError struct
    method Error (line 43) | func (e *AggregateError) Error() string {
  function newAggregateError (line 64) | func newAggregateError(s string, innerErrors []error) *AggregateError {
  function newAggregateError1 (line 68) | func newAggregateError1(s string, e interface{}) *AggregateError {
  function newErrorWithStacks (line 72) | func newErrorWithStacks(i interface{}) (e error) {
  function getAct (line 89) | func getAct(pr *Promise, act interface{}) (f func() (r interface{}, err ...
  function startPipe (line 149) | func startPipe(r *PromiseResult, pipeTask func(v interface{}) *Future, p...
  function getFutureReturnVal (line 162) | func getFutureReturnVal(r *PromiseResult) (interface{}, error) {
  function execCallback (line 173) | func execCallback(r *PromiseResult,
  function forSlice (line 210) | func forSlice(s []func(v interface{}), f func(func(v interface{}))) {
  type stringer (line 225) | type stringer interface
  function getError (line 229) | func getError(i interface{}) (e error) {
  function writeStrings (line 247) | func writeStrings(buf *bytes.Buffer, strings []string) {
Condensed preview — 8 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (67K chars).
[
  {
    "path": ".gitignore",
    "chars": 252,
    "preview": "# 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 spe"
  },
  {
    "path": "LICENSE",
    "chars": 1073,
    "preview": "The MIT License (MIT)\n\nCopyright (c) 2014 fanliao\n\nPermission is hereby granted, free of charge, to any person obtaining"
  },
  {
    "path": "README.md",
    "chars": 6851,
    "preview": "[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 prom"
  },
  {
    "path": "future.go",
    "chars": 11783,
    "preview": "/*\nPackage promise provides a complete promise and future implementation.\nA quick start sample:\n\n\nfu := Start(func()(res"
  },
  {
    "path": "future_factory.go",
    "chars": 6824,
    "preview": "package promise\n\nimport (\n\t\"sync/atomic\"\n)\n\ntype anyPromiseResult struct {\n\tresult interface{}\n\ti      int\n}\n\n//Start st"
  },
  {
    "path": "future_test.go",
    "chars": 23613,
    "preview": "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"
  },
  {
    "path": "promise.go",
    "chars": 3875,
    "preview": "package promise\n\nimport (\n\t\"math/rand\"\n\t\"unsafe\"\n)\n\nvar (\n\tCANCELLED error = &CancelledError{}\n)\n\n//CancelledError prese"
  },
  {
    "path": "utils.go",
    "chars": 5256,
    "preview": "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 re"
  }
]

About this extraction

This page contains the full source code of the fanliao/go-promise GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 8 files (58.1 KB), approximately 17.0k tokens, and a symbol index with 94 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!