github.com/pubgo/xprocess@v0.1.11/xprocess_future/future.promise.go (about)

     1  package xprocess_future
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  
     8  	"github.com/pubgo/xerror"
     9  	"github.com/pubgo/xlog"
    10  	"github.com/pubgo/xprocess/xprocess_abc"
    11  	"github.com/pubgo/xprocess/xprocess_waitgroup"
    12  	"github.com/pubgo/xprocess/xutil"
    13  	"go.uber.org/atomic"
    14  )
    15  
    16  type promise struct {
    17  	stack  string
    18  	closed atomic.Bool
    19  	done   sync.Once
    20  	err    atomic.Error
    21  	wg     xprocess_waitgroup.WaitGroup
    22  	data   chan xprocess_abc.FutureValue
    23  }
    24  
    25  func (s *promise) cancel()        { s.closed.Store(true) }
    26  func (s *promise) waitForClose()  { s.done.Do(func() { go func() { s.wg.Wait(); close(s.data) }() }) }
    27  func (s *promise) isClosed() bool { return s.closed.Load() }
    28  func (s *promise) Await() chan xprocess_abc.FutureValue {
    29  	s.waitForClose()
    30  
    31  	var val = make(chan xprocess_abc.FutureValue)
    32  	go func() {
    33  		defer close(val)
    34  		for data := range s.data {
    35  			val <- data
    36  			s.wg.Done()
    37  		}
    38  	}()
    39  
    40  	return val
    41  }
    42  
    43  func (s *promise) yield(data interface{}) {
    44  	if s.isClosed() {
    45  		xlog.Warnf("[xprocess] [promise] %s closed", s.stack)
    46  		return
    47  	}
    48  
    49  	switch val := data.(type) {
    50  	case func():
    51  		s.Go(val)
    52  	case *futureValue:
    53  		s.wg.Inc()
    54  		go func() { s.data <- val }()
    55  	default:
    56  		s.wg.Inc()
    57  		value := newFutureValue()
    58  		value.values = []reflect.Value{reflect.ValueOf(data)}
    59  		go func() { s.data <- value }()
    60  	}
    61  }
    62  
    63  func (s *promise) await(val xprocess_abc.FutureValue, fn interface{}) {
    64  	if s.isClosed() {
    65  		xlog.Warnf("[xprocess] [promise] %s closed", s.stack)
    66  		return
    67  	}
    68  
    69  	s.yield(Await(val, fn))
    70  }
    71  
    72  func (s *promise) Map(fn interface{}) (val1 xprocess_abc.Value) {
    73  	s.waitForClose()
    74  
    75  	defer xerror.Resp(func(err xerror.XErr) { val1 = &value{err: err} })
    76  
    77  	xerror.Assert(fn == nil, "[fn] should not be nil")
    78  
    79  	var errs []error
    80  	var values []xprocess_abc.FutureValue
    81  	for data := range s.Await() {
    82  		if err := data.Err(); err != nil {
    83  			errs = append(errs, err)
    84  		}
    85  
    86  		values = append(values, Await(data, fn))
    87  	}
    88  
    89  	// 遇到未知错误
    90  	xerror.PanicErrs(errs...)
    91  
    92  	if len(values) == 0 {
    93  		return
    94  	}
    95  
    96  	tfn := reflect.TypeOf(fn)
    97  
    98  	// fn没有输出
    99  	if tfn.NumOut() == 0 {
   100  		return &value{}
   101  	}
   102  
   103  	var t = tfn.Out(0)
   104  	var rst = reflect.MakeSlice(reflect.SliceOf(t), 0, len(values))
   105  	for i := range values {
   106  		val := values[i].Raw()[0]
   107  
   108  		if !val.IsValid() {
   109  			if t.Kind() == reflect.Ptr {
   110  				val = reflect.New(t).Elem()
   111  			} else {
   112  				val = reflect.Zero(t)
   113  			}
   114  		}
   115  
   116  		rst = reflect.Append(rst, val)
   117  	}
   118  	xerror.PanicErrs(errs...)
   119  
   120  	return &value{val: rst.Interface()}
   121  }
   122  
   123  func (s *promise) Go(fn func()) {
   124  	s.wg.Inc()
   125  	go func() {
   126  		defer s.wg.Done()
   127  		defer xerror.Resp(func(err xerror.XErr) { s.cancel(); s.err.Store(err) })
   128  		fn()
   129  	}()
   130  }
   131  
   132  func Promise(fn func(g xprocess_abc.Future)) xprocess_abc.IPromise {
   133  	xerror.Assert(fn == nil, "[fn] should not be nil")
   134  
   135  	s := &promise{data: make(chan xprocess_abc.FutureValue), stack: xutil.FuncStack(fn)}
   136  	s.Go(func() { fn(&future{p: s}) })
   137  	return s
   138  }
   139  
   140  func Async(fn interface{}, args ...interface{}) (val1 xprocess_abc.FutureValue) {
   141  	var value = newFutureValue()
   142  
   143  	defer xerror.Resp(func(err xerror.XErr) { val1 = value.setErr(err) })
   144  
   145  	xerror.Assert(fn == nil, "[fn] should not be nil")
   146  
   147  	var vfn = xutil.FuncRaw(fn)
   148  	var data = make(chan []reflect.Value, 1)
   149  	value.valFn = func() []reflect.Value { return <-data }
   150  	go func() {
   151  		defer xerror.Resp(func(err1 xerror.XErr) {
   152  			value.setErr(err1.WrapF("recovery error, input:%#v, func:%s, caller:%s",
   153  				args, reflect.TypeOf(fn), xutil.FuncStack(fn)))
   154  			data <- make([]reflect.Value, 0)
   155  		})
   156  
   157  		data <- vfn(args...)
   158  	}()
   159  
   160  	return value
   161  }
   162  
   163  func Await(val xprocess_abc.FutureValue, fn interface{}) (val1 xprocess_abc.FutureValue) {
   164  	var value = newFutureValue()
   165  
   166  	defer xerror.Resp(func(err xerror.XErr) { val1 = value.setErr(err) })
   167  
   168  	xerror.Assert(val == nil, "[val] should not be nil")
   169  	xerror.Assert(fn == nil, "[fn] should not be nil")
   170  
   171  	var data = make(chan []reflect.Value, 1)
   172  	value.valFn = func() []reflect.Value { return <-data }
   173  
   174  	var vfn = xutil.FuncValue(fn)
   175  	go func() {
   176  		if err := val.Err(); err != nil {
   177  			value.setErr(err)
   178  			data <- make([]reflect.Value, 0)
   179  			return
   180  		}
   181  
   182  		defer xerror.Resp(func(err1 xerror.XErr) {
   183  			value.setErr(err1.WrapF("input:%s, func:%s", val.Raw(), reflect.TypeOf(fn)))
   184  			data <- make([]reflect.Value, 0)
   185  		})
   186  
   187  		data <- vfn(val.Raw()...)
   188  	}()
   189  
   190  	return value
   191  }
   192  
   193  func valueStr(values ...reflect.Value) string {
   194  	var data []interface{}
   195  	for _, dt := range values {
   196  		var val interface{}
   197  		if dt.IsValid() {
   198  			val = dt.Interface()
   199  		}
   200  		data = append(data, val)
   201  	}
   202  	return fmt.Sprint(data...)
   203  }
   204  
   205  func RunComplete(values ...xprocess_abc.FutureValue) (err error) {
   206  	defer xerror.RespErr(&err)
   207  
   208  	var errs []error
   209  	for i := range values {
   210  		if err := values[i].Err(); err != nil {
   211  			errs = append(errs, err)
   212  		}
   213  	}
   214  
   215  	xerror.PanicErrs(errs...)
   216  	return nil
   217  }