diff --git a/msgp/number.go b/msgp/number.go index ad07ef99..28651530 100644 --- a/msgp/number.go +++ b/msgp/number.go @@ -91,6 +91,70 @@ func (n *Number) Float() (float64, bool) { } } +// CoerceInt attempts to coerce the value of +// the number into a signed integer, and returns +// whether or not it was successful. "Success" +// implies that no precision in the value of +// the number was lost, which means that the +// type of the number was an integer or +// a floating point 0. +func (n *Number) CoerceInt() (int64, bool) { + switch n.typ { + case InvalidType, IntType: + return int64(n.bits), true + case UintType: + return int64(n.bits), n.bits <= math.MaxInt64 + case Float32Type: + return 0, n.bits == 0 || n.bits == 1<<31 + case Float64Type: + return 0, n.bits == 0 || n.bits == 1<<63 + } + return 0, false +} + +// CoerceUint attempts to coerce the value of +// the number into an unsigned integer, and +// returns whether or not it was successful. +// "Success" implies that no precision in the +// value of the number was lost (see CoerceInt()). +func (n *Number) CoerceUint() (uint64, bool) { + switch n.typ { + case InvalidType: + return 0, true + case IntType: + return n.bits, int64(n.bits) >= 0 + case UintType: + return n.bits, true + case Float32Type: + return 0, n.bits == 0 || n.bits == 1<<31 + case Float64Type: + return 0, n.bits == 0 || n.bits == 1<<63 + } + return 0, false +} + +// CoerceFloat coerces the value of the +// number to a float64. Some precision may +// be lost in the conversion if the type +// of the number was not originally a +// float64. (However, zero is always +// converted precisely.) +func (n *Number) CoerceFloat() float64 { + switch n.typ { + case InvalidType: + return 0 + case IntType: + return float64(int64(n.bits)) + case UintType: + return float64(uint64(n.bits)) + case Float32Type: + return float64(math.Float32frombits(uint32(n.bits))) + case Float64Type: + return math.Float64frombits(n.bits) + } + return 0 +} + // Type will return one of: // Float64Type, Float32Type, UintType, or IntType. func (n *Number) Type() Type { diff --git a/msgp/number_test.go b/msgp/number_test.go index 3490647c..6cb972cc 100644 --- a/msgp/number_test.go +++ b/msgp/number_test.go @@ -23,18 +23,33 @@ func TestNumber(t *testing.T) { t.Errorf("%d in; %d out!", 248, i) } + u, ok := n.CoerceUint() + if !ok || u != 248 { + t.Errorf("%d in, %d out!", 248, u) + } + n.AsFloat64(3.141) f, ok := n.Float() if !ok || f != 3.141 || n.Type() != Float64Type || n.String() != "3.141" { t.Errorf("%f in; %f out!", 3.141, f) } + f = n.CoerceFloat() + if f != 3.141 { + t.Errorf("%f in; %f out", 3.141, f) + } + n.AsUint(40000) - u, ok := n.Uint() + u, ok = n.Uint() if !ok || u != 40000 || n.Type() != UintType || n.String() != "40000" { t.Errorf("%d in; %d out!", 40000, u) } + i, ok = n.CoerceInt() + if !ok || i != 40000 { + t.Errorf("%d in; %d out!", 40000, i) + } + nums := []interface{}{ float64(3.14159), int64(-29081),