go.temporal.io/server@v1.23.0/common/future/future_impl.go (about) 1 // The MIT License 2 // 3 // Copyright (c) 2020 Temporal Technologies Inc. All rights reserved. 4 // 5 // Copyright (c) 2020 Uber Technologies, Inc. 6 // 7 // Permission is hereby granted, free of charge, to any person obtaining a copy 8 // of this software and associated documentation files (the "Software"), to deal 9 // in the Software without restriction, including without limitation the rights 10 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 // copies of the Software, and to permit persons to whom the Software is 12 // furnished to do so, subject to the following conditions: 13 // 14 // The above copyright notice and this permission notice shall be included in 15 // all copies or substantial portions of the Software. 16 // 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 // THE SOFTWARE. 24 25 package future 26 27 import ( 28 "context" 29 "sync/atomic" 30 ) 31 32 const ( 33 // pending status indicates future is not ready 34 // setting status indicates future is in transition to be ready, used to prevent data race 35 // ready status indicates future is ready 36 37 pending int32 = iota 38 setting 39 ready 40 ) 41 42 type ( 43 FutureImpl[T any] struct { 44 status int32 45 readyCh chan struct{} 46 47 value T 48 err error 49 } 50 ) 51 52 func NewFuture[T any]() *FutureImpl[T] { 53 var value T 54 return &FutureImpl[T]{ 55 status: pending, 56 readyCh: make(chan struct{}), 57 58 value: value, 59 err: nil, 60 } 61 } 62 63 func (f *FutureImpl[T]) Get( 64 ctx context.Context, 65 ) (T, error) { 66 if f.Ready() { 67 return f.value, f.err 68 } 69 70 select { 71 case <-f.readyCh: 72 return f.value, f.err 73 case <-ctx.Done(): 74 var value T 75 return value, ctx.Err() 76 } 77 } 78 79 func (f *FutureImpl[T]) Set( 80 value T, 81 err error, 82 ) { 83 // cannot directly set status to `ready`, to prevent data race in case multiple `Get` occurs 84 // instead set status to `setting` to prevent concurrent completion of this future 85 if !atomic.CompareAndSwapInt32( 86 &f.status, 87 pending, 88 setting, 89 ) { 90 panic("future has already been completed") 91 } 92 93 f.value = value 94 f.err = err 95 atomic.CompareAndSwapInt32(&f.status, setting, ready) 96 close(f.readyCh) 97 } 98 99 func (f *FutureImpl[T]) Ready() bool { 100 return atomic.LoadInt32(&f.status) == ready 101 }