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  }