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 }