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  }