package types import ( "fmt" "math" "strconv" "golang.org/x/xerrors" ) // Percent stores a signed percentage as an int64. When converted to a string (or json), it's stored // as a decimal with two places (e.g., 100% -> 1.00). type Percent int64 func (p Percent) String() string { abs := p sign := "" if abs < 0 { abs = -abs sign = "-" } return fmt.Sprintf(`%s%d.%d`, sign, abs/100, abs%100) } func (p Percent) MarshalJSON() ([]byte, error) { return []byte(p.String()), nil } func (p *Percent) UnmarshalJSON(b []byte) error { flt, err := strconv.ParseFloat(string(b)+"e2", 64) if err != nil { return xerrors.Errorf("unable to parse ratio %s: %w", string(b), err) } if math.Trunc(flt) != flt { return xerrors.Errorf("ratio may only have two decimals: %s", string(b)) } *p = Percent(flt) return nil }