github.com/mavryk-network/mvgo@v1.19.9/contract/bind/option.go (about) 1 package bind 2 3 import ( 4 "fmt" 5 6 "github.com/mavryk-network/mvgo/micheline" 7 8 "github.com/pkg/errors" 9 ) 10 11 // Option is a type that can either contain a value T, or be None. 12 type Option[T any] struct { 13 v T 14 isSome bool 15 } 16 17 // Some returns a Some option with v as a value. 18 func Some[T any](v T) Option[T] { 19 return Option[T]{v: v, isSome: true} 20 } 21 22 // None returns a None option for type T. 23 func None[T any]() Option[T] { 24 return Option[T]{isSome: false} 25 } 26 27 // Get returns the inner value of the Option and a boolean 28 // indicating if the Option is Some. 29 // 30 // If it is none, the returned value is the default value for T. 31 func (o Option[T]) Get() (v T, isSome bool) { 32 return o.v, o.isSome 33 } 34 35 // Unwrap returns the inner value of the Option, expecting 36 // that it is Some. 37 // 38 // Panics if the option is None. 39 func (o Option[T]) Unwrap() T { 40 if o.IsNone() { 41 panic("Unwrap() called on a `None` Option") 42 } 43 return o.v 44 } 45 46 // UnwrapOr returns the inner value of the Option if it is Some, 47 // or the provided default value if it is None. 48 func (o Option[T]) UnwrapOr(defaultValue T) T { 49 if o.IsNone() { 50 return defaultValue 51 } 52 return o.v 53 } 54 55 // UnwrapOrZero returns the inner value of the Option if it is Some, 56 // or T's zero value if it is None. 57 func (o Option[T]) UnwrapOrZero() T { 58 // o.v == zero value if o is none 59 return o.v 60 } 61 62 // SetSome replaces o's value with Some(v). 63 func (o *Option[T]) SetSome(v T) { 64 o.v = v 65 o.isSome = true 66 } 67 68 // SetNone replaces o's value with None. 69 func (o *Option[T]) SetNone() { 70 var zeroVal T 71 o.v = zeroVal 72 o.isSome = false 73 } 74 75 func (o Option[T]) IsSome() bool { 76 return o.isSome 77 } 78 79 func (o Option[T]) IsNone() bool { 80 return !o.isSome 81 } 82 83 // GetUntyped is the equivalent of Get, but it returns v as an empty interface 84 // instead of T. 85 // 86 // This method is useful when generic parameters cannot be used, for example with reflection. 87 func (o Option[T]) GetUntyped() (v any, isSome bool) { 88 return o.Get() 89 } 90 91 // SetUntyped is the equivalent of SetSome or SetNone, but uses v as an empty interface 92 // instead of T. 93 // 94 // If v is nil, then the Option will be set to None. 95 // Else, it will cast v to T and set the Option to Some. 96 // 97 // Returns an error if the cast failed. 98 // 99 // This method is useful when generic parameters cannot be used, for example with reflection. 100 func (o *Option[T]) SetUntyped(v any) error { 101 if v == nil { 102 o.SetNone() 103 return nil 104 } 105 casted, ok := v.(T) 106 if !ok { 107 return errors.Errorf("bad type (want %T, got %T)", o.v, v) 108 } 109 o.SetSome(casted) 110 return nil 111 } 112 113 func (o Option[T]) String() string { 114 if o.isSome { 115 return fmt.Sprintf("Some(%v)", o.v) 116 } 117 return "None" 118 } 119 120 func (o Option[T]) MarshalPrim(optimized bool) (micheline.Prim, error) { 121 if o.isSome { 122 inner, err := MarshalPrim(o.v, optimized) 123 if err != nil { 124 return micheline.Prim{}, err 125 } 126 return micheline.NewCode(micheline.D_SOME, inner), nil 127 } 128 return micheline.NewCode(micheline.D_NONE), nil 129 } 130 131 func (o *Option[T]) UnmarshalPrim(prim micheline.Prim) error { 132 switch prim.OpCode { 133 case micheline.D_SOME: 134 if len(prim.Args) != 1 { 135 return errors.New("prim Some should have 1 arg") 136 } 137 o.isSome = true 138 return UnmarshalPrim(prim.Args[0], &o.v) 139 case micheline.D_NONE: 140 *o = None[T]() 141 return nil 142 default: 143 return errors.Errorf("unexpected opCode when unmarshalling Option: %s", prim.OpCode) 144 } 145 } 146 147 func (o Option[T]) keyHash() hashType { 148 if v, ok := o.Get(); ok { 149 return hashFunc(zero[T]())(v) 150 } else { 151 return hashType{0} 152 } 153 }