tstime/rate: implement Value.{Marshal,Unmarshal}JSON (#8481)

Implement support for marshaling and unmarshaling a Value.

Updates tailscale/corp#8427

Signed-off-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
Joe Tsai
2024-01-16 13:48:34 -08:00
committed by GitHub
parent 1c3c3d6752
commit 7732377cd7
2 changed files with 64 additions and 0 deletions

View File

@@ -4,6 +4,7 @@
package rate
import (
"encoding/json"
"fmt"
"math"
"sync"
@@ -181,3 +182,41 @@ func (r *Value) rateNow(now mono.Time) float64 {
func (r *Value) normalizedIntegral() float64 {
return r.halfLife() / math.Ln2
}
type jsonValue struct {
// TODO: Use v2 "encoding/json" for native time.Duration formatting.
HalfLife string `json:"halfLife,omitempty,omitzero"`
Value float64 `json:"value,omitempty,omitzero"`
Updated mono.Time `json:"updated,omitempty,omitzero"`
}
func (r *Value) MarshalJSON() ([]byte, error) {
if r == nil {
return []byte("null"), nil
}
r.mu.Lock()
defer r.mu.Unlock()
v := jsonValue{Value: r.value, Updated: r.updated}
if r.HalfLife > 0 {
v.HalfLife = r.HalfLife.String()
}
return json.Marshal(v)
}
func (r *Value) UnmarshalJSON(b []byte) error {
var v jsonValue
if err := json.Unmarshal(b, &v); err != nil {
return err
}
halfLife, err := time.ParseDuration(v.HalfLife)
if err != nil && v.HalfLife != "" {
return fmt.Errorf("invalid halfLife: %w", err)
}
r.mu.Lock()
defer r.mu.Unlock()
r.HalfLife = halfLife
r.value = v.Value
r.updated = v.Updated
return nil
}