github.com/influx6/npkg@v0.8.8/nthen/nthen.go (about)

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