github.com/mitranim/gg@v0.1.17/zop.go (about)

     1  package gg
     2  
     3  /*
     4  Short for "zero optional value". Workaround for the lack of type inference in
     5  struct literals.
     6  */
     7  func ZopVal[A any](val A) Zop[A] { return Zop[A]{val} }
     8  
     9  /*
    10  Short for "zero optional". The zero value is considered empty/null in JSON. Note
    11  that "encoding/json" doesn't support ",omitempty" for structs. This wrapper
    12  allows empty structs to become "null". This type doesn't implement any other
    13  encoding or decoding methods, and is intended only for non-scalar values such
    14  as "models" / "data classes".
    15  */
    16  type Zop[A any] struct {
    17  	/**
    18  	Annotation `role:"ref"` indicates that this field is a reference/pointer to
    19  	the inner type/value. Reflection-based code may use this to treat this type
    20  	like a pointer.
    21  	*/
    22  	Val A `role:"ref"`
    23  }
    24  
    25  // Implement `Nullable`. True if zero value of its type.
    26  func (self Zop[_]) IsNull() bool { return IsZero(self.Val) }
    27  
    28  // Inverse of `.IsNull`.
    29  func (self Zop[_]) IsNotNull() bool { return !IsZero(self.Val) }
    30  
    31  // Implement `Clearer`. Zeroes the receiver.
    32  func (self *Zop[_]) Clear() { PtrClear(&self.Val) }
    33  
    34  // Implement `Getter`, returning the underlying value as-is.
    35  func (self Zop[A]) Get() A { return self.Val }
    36  
    37  // Implement `Setter`, modifying the underlying value.
    38  func (self *Zop[A]) Set(val A) { self.Val = val }
    39  
    40  // Implement `Ptrer`, returning a pointer to the underlying value.
    41  func (self *Zop[A]) Ptr() *A {
    42  	if self == nil {
    43  		return nil
    44  	}
    45  	return &self.Val
    46  }
    47  
    48  /*
    49  Implement `json.Marshaler`. If `.IsNull`, returns a representation of JSON null.
    50  Otherwise uses `json.Marshal` to encode the underlying value.
    51  */
    52  func (self Zop[A]) MarshalJSON() ([]byte, error) {
    53  	return JsonBytesNullCatch[A](self)
    54  }
    55  
    56  /*
    57  Implement `json.Unmarshaler`. If the input is empty or represents JSON null,
    58  clears the receiver via `.Clear`. Otherwise uses `JsonParseCatch` to decode
    59  into the underlying value.
    60  */
    61  func (self *Zop[A]) UnmarshalJSON(src []byte) error {
    62  	if IsJsonEmpty(src) {
    63  		self.Clear()
    64  		return nil
    65  	}
    66  	return JsonParseCatch(src, &self.Val)
    67  }
    68  
    69  /*
    70  FP-style "mapping". If the original value is zero, or if the function is nil,
    71  the output is zero. Otherwise the output is the result of calling the function
    72  with the previous value.
    73  */
    74  func ZopMap[A, B any](src Zop[A], fun func(A) B) (out Zop[B]) {
    75  	if src.IsNotNull() && fun != nil {
    76  		out.Val = fun(src.Val)
    77  	}
    78  	return
    79  }