atom.go raw

   1  package atom
   2  
   3  import (
   4  	"github.com/p9c/p9/pkg/btcaddr"
   5  	"github.com/p9c/p9/pkg/chaincfg"
   6  	"time"
   7  	
   8  	"go.uber.org/atomic"
   9  	
  10  	"github.com/p9c/p9/pkg/btcjson"
  11  	"github.com/p9c/p9/pkg/chainhash"
  12  )
  13  
  14  // import all the atomics from uber atomic
  15  type (
  16  	Int32    struct{ *atomic.Int32 }
  17  	Int64    struct{ *atomic.Int64 }
  18  	Uint32   struct{ *atomic.Uint32 }
  19  	Uint64   struct{ *atomic.Uint64 }
  20  	Bool     struct{ *atomic.Bool }
  21  	Float64  struct{ *atomic.Float64 }
  22  	Duration struct{ *atomic.Duration }
  23  	Value    struct{ *atomic.Value }
  24  )
  25  
  26  // The following are types added for handling cryptocurrency data for
  27  // ParallelCoin
  28  
  29  // Time is an atomic wrapper around time.Time
  30  // https://godoc.org/time#Time
  31  type Time struct {
  32  	v *Int64
  33  }
  34  
  35  // NewTime creates a Time.
  36  func NewTime(tt time.Time) *Time {
  37  	t := &Int64{atomic.NewInt64(tt.UnixNano())}
  38  	return &Time{v: t}
  39  }
  40  
  41  // Load atomically loads the wrapped value.
  42  func (at *Time) Load() time.Time {
  43  	return time.Unix(0, at.v.Load())
  44  }
  45  
  46  // Store atomically stores the passed value.
  47  func (at *Time) Store(n time.Time) {
  48  	at.v.Store(n.UnixNano())
  49  }
  50  
  51  // Add atomically adds to the wrapped time.Duration and returns the new value.
  52  func (at *Time) Add(n time.Time) time.Time {
  53  	return time.Unix(0, at.v.Add(n.UnixNano()))
  54  }
  55  
  56  // Sub atomically subtracts from the wrapped time.Duration and returns the new value.
  57  func (at *Time) Sub(n time.Time) time.Time {
  58  	return time.Unix(0, at.v.Sub(n.UnixNano()))
  59  }
  60  
  61  // Swap atomically swaps the wrapped time.Duration and returns the old value.
  62  func (at *Time) Swap(n time.Time) time.Time {
  63  	return time.Unix(0, at.v.Swap(n.UnixNano()))
  64  }
  65  
  66  // CAS is an atomic compare-and-swap.
  67  func (at *Time) CAS(old, new time.Time) bool {
  68  	return at.v.CAS(old.UnixNano(), new.UnixNano())
  69  }
  70  
  71  // Hash is an atomic wrapper around chainhash.Hash
  72  // Note that there isn't really any reason to have CAS or arithmetic or
  73  // comparisons as it is fine to do these non-atomically between Load / Store and
  74  // they are (slightly) long operations)
  75  type Hash struct {
  76  	*Value
  77  }
  78  
  79  // NewHash creates a Hash.
  80  func NewHash(tt chainhash.Hash) *Hash {
  81  	t := &Value{
  82  		Value: &atomic.Value{},
  83  	}
  84  	t.Store(tt)
  85  	return &Hash{Value: t}
  86  }
  87  
  88  // Load atomically loads the wrapped value.
  89  // The returned value copied so as to prevent mutation by concurrent users
  90  // of the atomic, as arrays, slices and maps are pass-by-reference variables
  91  func (at *Hash) Load() chainhash.Hash {
  92  	o := at.Value.Load().(chainhash.Hash)
  93  	var v chainhash.Hash
  94  	copy(v[:], o[:])
  95  	return v
  96  }
  97  
  98  // Store atomically stores the passed value.
  99  // The passed value is copied so further mutations are not propagated.
 100  func (at *Hash) Store(h chainhash.Hash) {
 101  	var v chainhash.Hash
 102  	copy(v[:], h[:])
 103  	at.Value.Store(v)
 104  }
 105  
 106  // Swap atomically swaps the wrapped chainhash.Hash and returns the old value.
 107  func (at *Hash) Swap(n chainhash.Hash) chainhash.Hash {
 108  	o := at.Value.Load().(chainhash.Hash)
 109  	at.Value.Store(n)
 110  	return o
 111  }
 112  
 113  // Address is an atomic wrapper around util.Address
 114  type Address struct {
 115  	*atomic.String
 116  	ForNet *chaincfg.Params
 117  }
 118  
 119  // NewAddress creates a Hash.
 120  func NewAddress(tt btcaddr.Address, forNet *chaincfg.Params) *Address {
 121  	t := atomic.NewString(tt.EncodeAddress())
 122  	return &Address{String: t, ForNet: forNet}
 123  }
 124  
 125  // Load atomically loads the wrapped value.
 126  func (at *Address) Load() btcaddr.Address {
 127  	addr, e := btcaddr.Decode(at.String.Load(), at.ForNet)
 128  	if e != nil {
 129  		return nil
 130  	}
 131  	return addr
 132  }
 133  
 134  // Store atomically stores the passed value.
 135  // The passed value is copied so further mutations are not propagated.
 136  func (at *Address) Store(h btcaddr.Address) {
 137  	at.String.Store(h.EncodeAddress())
 138  }
 139  
 140  // Swap atomically swaps the wrapped util.Address and returns the old value.
 141  func (at *Address) Swap(n btcaddr.Address) btcaddr.Address {
 142  	o := at.Load()
 143  	at.Store(n)
 144  	return o
 145  }
 146  
 147  // ListTransactionsResult is an atomic wrapper around
 148  // []btcjson.ListTransactionsResult
 149  type ListTransactionsResult struct {
 150  	v *Value
 151  }
 152  
 153  // NewListTransactionsResult creates a btcjson.ListTransactionsResult.
 154  func NewListTransactionsResult(ltr []btcjson.ListTransactionsResult) *ListTransactionsResult {
 155  	t := &Value{
 156  		Value: &atomic.Value{},
 157  	}
 158  	v := make([]btcjson.ListTransactionsResult, len(ltr))
 159  	copy(v, ltr)
 160  	t.Store(v)
 161  	return &ListTransactionsResult{v: t}
 162  }
 163  
 164  // Load atomically loads the wrapped value.
 165  // Note that it is copied and the stored value remains as it is
 166  func (at *ListTransactionsResult) Load() []btcjson.ListTransactionsResult {
 167  	ltr := at.v.Load().([]btcjson.ListTransactionsResult)
 168  	v := make([]btcjson.ListTransactionsResult, len(ltr))
 169  	copy(v, ltr)
 170  	return v
 171  }
 172  
 173  // Store atomically stores the passed value.
 174  // Note that it is copied and the passed value remains as it is
 175  func (at *ListTransactionsResult) Store(ltr []btcjson.ListTransactionsResult) {
 176  	v := make([]btcjson.ListTransactionsResult, len(ltr))
 177  	copy(v, ltr)
 178  	at.v.Store(v)
 179  }
 180  
 181  // Swap atomically swaps the wrapped chainhash.ListTransactionsResult and
 182  // returns the old value.
 183  func (at *ListTransactionsResult) Swap(
 184  	n []btcjson.ListTransactionsResult,
 185  ) []btcjson.ListTransactionsResult {
 186  	o := at.v.Load().([]btcjson.ListTransactionsResult)
 187  	at.v.Store(n)
 188  	return o
 189  }
 190  
 191  // Len returns the length of the []btcjson.ListTransactionsResult
 192  func (at *ListTransactionsResult) Len() int {
 193  	return len(at.v.Load().([]btcjson.ListTransactionsResult))
 194  }
 195