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

     1  package gg
     2  
     3  import (
     4  	"time"
     5  )
     6  
     7  /*
     8  Shortcut for creating a `Timed` with the given value, using the current
     9  timestamp.
    10  */
    11  func TimedVal[A any](val A) (out Timed[A]) {
    12  	out.Set(val)
    13  	return
    14  }
    15  
    16  /*
    17  Describes an arbitrary value with a timestamp. The timestamp indicates when the
    18  value was obtained. In JSON encoding and decoding, acts as a transparent
    19  proxy/reference/pointer to the inner value.
    20  */
    21  type Timed[A any] struct {
    22  	Val  A `role:"ref"`
    23  	Inst time.Time
    24  }
    25  
    26  // True if timestamp is unset.
    27  func (self Timed[_]) IsNull() bool { return self.Inst.IsZero() }
    28  
    29  // Inverse of `.IsNull`.
    30  func (self Timed[_]) IsNotNull() bool { return !self.Inst.IsZero() }
    31  
    32  // Implement `Clearer`. Zeroes the receiver.
    33  func (self *Timed[_]) Clear() { PtrClear(self) }
    34  
    35  // Implement `Getter`, returning the underlying value as-is.
    36  func (self Timed[A]) Get() A { return self.Val }
    37  
    38  /*
    39  Implement `Setter`. Modifies the underlying value and sets the current
    40  timestamp. The resulting state is considered non-null even if the value
    41  is "zero".
    42  */
    43  func (self *Timed[A]) Set(val A) {
    44  	self.Val = val
    45  	self.Inst = time.Now()
    46  }
    47  
    48  // Implement `Ptrer`, returning a pointer to the underlying value.
    49  func (self *Timed[A]) Ptr() *A {
    50  	if self == nil {
    51  		return nil
    52  	}
    53  	return &self.Val
    54  }
    55  
    56  /*
    57  Implement `json.Marshaler`. If `.IsNull`, returns a representation of JSON null.
    58  Otherwise uses `json.Marshal` to encode the underlying value.
    59  */
    60  func (self Timed[A]) MarshalJSON() ([]byte, error) {
    61  	return JsonBytesNullCatch[A](self)
    62  }
    63  
    64  /*
    65  Implement `json.Unmarshaler`. If the input is empty or represents JSON null,
    66  clears the receiver via `.Clear`. Otherwise uses `JsonParseCatch` to decode
    67  into the underlying value, and sets the current timestamp on success.
    68  */
    69  func (self *Timed[_]) UnmarshalJSON(src []byte) error {
    70  	if IsJsonEmpty(src) {
    71  		self.Clear()
    72  		return nil
    73  	}
    74  	return self.with(JsonParseCatch(src, &self.Val))
    75  }
    76  
    77  // True if the timestamp is unset, or if timestamp + duration > now.
    78  func (self Timed[_]) IsExpired(dur time.Duration) bool {
    79  	return self.Inst.IsZero() || self.Inst.Add(dur).Before(time.Now())
    80  }
    81  
    82  // Inverse of `.IsExpired`.
    83  func (self Timed[_]) IsLive(dur time.Duration) bool {
    84  	return !self.IsExpired(dur)
    85  }
    86  
    87  func (self *Timed[_]) with(err error) error {
    88  	if err != nil {
    89  		PtrClear(&self.Inst)
    90  	} else {
    91  		self.Inst = time.Now()
    92  	}
    93  	return err
    94  }