github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/commons/futures/future.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package futures 19 20 import ( 21 "context" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/commons/objects" 24 "sync" 25 ) 26 27 type Promise interface { 28 Succeed(v any) 29 Failed(err error) 30 Close() 31 } 32 33 type Result interface { 34 objects.Object 35 } 36 37 type Future interface { 38 Await(ctx context.Context) (result Result, err error) 39 } 40 41 var ( 42 pool = sync.Pool{} 43 ) 44 45 type sch struct { 46 locker sync.Locker 47 ch chan value 48 closed bool 49 } 50 51 func (s *sch) send(v value) { 52 s.locker.Lock() 53 if s.closed { 54 s.locker.Unlock() 55 return 56 } 57 s.ch <- v 58 s.locker.Unlock() 59 } 60 61 func (s *sch) destroy() { 62 s.locker.Lock() 63 if !s.closed { 64 s.closed = true 65 close(s.ch) 66 } 67 s.locker.Unlock() 68 } 69 70 func (s *sch) get() <-chan value { 71 return s.ch 72 } 73 74 func New() (p Promise, f Future) { 75 var ch *sch 76 cached := pool.Get() 77 if cached == nil { 78 ch = &sch{ 79 locker: new(sync.Mutex), 80 ch: make(chan value, 1), 81 closed: false, 82 } 83 } else { 84 ch = cached.(*sch) 85 } 86 p = promise{ 87 ch: ch, 88 } 89 f = future{ 90 ch: ch, 91 } 92 return 93 } 94 95 func ReleaseUnused(p Promise) { 96 pool.Put(p.(promise).ch) 97 } 98 99 type value struct { 100 val any 101 err error 102 } 103 104 type promise struct { 105 ch *sch 106 } 107 108 func (p promise) Succeed(v any) { 109 p.ch.send(value{ 110 val: v, 111 }) 112 } 113 114 func (p promise) Failed(err error) { 115 if err == nil { 116 err = errors.Warning("fns: empty failed result").WithMeta("fns", "futures") 117 } 118 p.ch.send(value{ 119 err: err, 120 }) 121 } 122 123 func (p promise) Close() { 124 p.ch.destroy() 125 } 126 127 type future struct { 128 ch *sch 129 } 130 131 func (f future) Await(ctx context.Context) (r Result, err error) { 132 select { 133 case <-ctx.Done(): 134 f.ch.destroy() 135 err = errors.Timeout("fns: get result value from future timeout").WithMeta("fns", "futures") 136 break 137 case data, ok := <-f.ch.get(): 138 pool.Put(f.ch) 139 if !ok { 140 err = errors.Warning("fns: future was closed").WithMeta("fns", "futures") 141 break 142 } 143 if data.err != nil { 144 err = data.err 145 break 146 } 147 r = objects.New(data.val) 148 break 149 } 150 return 151 } 152 153 func Await(ctx context.Context, ff ...Future) (r []any) { 154 for _, f := range ff { 155 fr, fErr := f.Await(ctx) 156 if fErr != nil { 157 r = append(r, fErr) 158 continue 159 } 160 r = append(r, fr) 161 } 162 return 163 }