62 lines
1.7 KiB
Go
62 lines
1.7 KiB
Go
|
// Copyright (C) 2019 Storj Labs, Inc.
|
||
|
// See LICENSE for copying information.
|
||
|
|
||
|
package currency
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
|
||
|
"github.com/shopspring/decimal"
|
||
|
"github.com/zeebo/errs"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
maxInt64 = decimal.NewFromInt(math.MaxInt64)
|
||
|
|
||
|
// Zero is a MicroUnit representing 0.
|
||
|
Zero MicroUnit
|
||
|
)
|
||
|
|
||
|
// NewMicroUnit returns a MicroUnit with v. Much like a time.Duration, a value
|
||
|
// of 1 means 1e-6 or one millionth of a unit of currency.
|
||
|
func NewMicroUnit(v int64) MicroUnit {
|
||
|
return MicroUnit{v: v}
|
||
|
}
|
||
|
|
||
|
// MicroUnit represents 1e-6 or one millionth of a unit of currency (e.g. one
|
||
|
// millionth of a dollar). It is used instead of a floating point type to
|
||
|
// prevent rounding errors.
|
||
|
type MicroUnit struct{ v int64 }
|
||
|
|
||
|
// Value returns the underlying MicroUnit value.
|
||
|
func (m MicroUnit) Value() int64 { return m.v }
|
||
|
|
||
|
// Decimal returns the a decimal form of the MicroUnit.
|
||
|
func (m MicroUnit) Decimal() decimal.Decimal {
|
||
|
return decimal.New(m.v, -6)
|
||
|
}
|
||
|
|
||
|
// FloatString returns a string fixed to 6 decimal places.
|
||
|
func (m MicroUnit) FloatString() string {
|
||
|
return m.Decimal().StringFixed(6)
|
||
|
}
|
||
|
|
||
|
// MicroUnitFromFloatString parses the string from FloatString into a MicroUnit.
|
||
|
func MicroUnitFromFloatString(s string) (MicroUnit, error) {
|
||
|
d, err := decimal.NewFromString(s)
|
||
|
if err != nil {
|
||
|
return MicroUnit{}, errs.Wrap(err)
|
||
|
}
|
||
|
return MicroUnitFromDecimal(d)
|
||
|
}
|
||
|
|
||
|
// MicroUnitFromDecimal returns a MicroUnit from a decimal value and returns an
|
||
|
// error if there is not enough precision.
|
||
|
func MicroUnitFromDecimal(d decimal.Decimal) (MicroUnit, error) {
|
||
|
m := d.Shift(6).Truncate(0)
|
||
|
if m.GreaterThan(maxInt64) {
|
||
|
return MicroUnit{}, errs.New("%s overflows micro-unit", d)
|
||
|
}
|
||
|
return MicroUnit{v: m.IntPart()}, nil
|
||
|
}
|