| package msgp |
| |
| import ( |
| "math" |
| "strconv" |
| ) |
| |
| // The portable parts of the Number implementation |
| |
| // Number can be |
| // an int64, uint64, float32, |
| // or float64 internally. |
| // It can decode itself |
| // from any of the native |
| // messagepack number types. |
| // The zero-value of Number |
| // is Int(0). Using the equality |
| // operator with Number compares |
| // both the type and the value |
| // of the number. |
| type Number struct { |
| // internally, this |
| // is just a tagged union. |
| // the raw bits of the number |
| // are stored the same way regardless. |
| bits uint64 |
| typ Type |
| } |
| |
| // AsInt sets the number to an int64. |
| func (n *Number) AsInt(i int64) { |
| |
| // we always store int(0) |
| // as {0, InvalidType} in |
| // order to preserve |
| // the behavior of the == operator |
| if i == 0 { |
| n.typ = InvalidType |
| n.bits = 0 |
| return |
| } |
| |
| n.typ = IntType |
| n.bits = uint64(i) |
| } |
| |
| // AsUint sets the number to a uint64. |
| func (n *Number) AsUint(u uint64) { |
| n.typ = UintType |
| n.bits = u |
| } |
| |
| // AsFloat32 sets the value of the number |
| // to a float32. |
| func (n *Number) AsFloat32(f float32) { |
| n.typ = Float32Type |
| n.bits = uint64(math.Float32bits(f)) |
| } |
| |
| // AsFloat64 sets the value of the |
| // number to a float64. |
| func (n *Number) AsFloat64(f float64) { |
| n.typ = Float64Type |
| n.bits = math.Float64bits(f) |
| } |
| |
| // Int casts the number as an int64, and |
| // returns whether or not that was the |
| // underlying type. |
| func (n *Number) Int() (int64, bool) { |
| return int64(n.bits), n.typ == IntType || n.typ == InvalidType |
| } |
| |
| // Uint casts the number as a uint64, and returns |
| // whether or not that was the underlying type. |
| func (n *Number) Uint() (uint64, bool) { |
| return n.bits, n.typ == UintType |
| } |
| |
| // Float casts the number to a float64, and |
| // returns whether or not that was the underlying |
| // type (either a float64 or a float32). |
| func (n *Number) Float() (float64, bool) { |
| switch n.typ { |
| case Float32Type: |
| return float64(math.Float32frombits(uint32(n.bits))), true |
| case Float64Type: |
| return math.Float64frombits(n.bits), true |
| default: |
| return 0.0, false |
| } |
| } |
| |
| // Type will return one of: |
| // Float64Type, Float32Type, UintType, or IntType. |
| func (n *Number) Type() Type { |
| if n.typ == InvalidType { |
| return IntType |
| } |
| return n.typ |
| } |
| |
| // DecodeMsg implements msgp.Decodable |
| func (n *Number) DecodeMsg(r *Reader) error { |
| typ, err := r.NextType() |
| if err != nil { |
| return err |
| } |
| switch typ { |
| case Float32Type: |
| f, err := r.ReadFloat32() |
| if err != nil { |
| return err |
| } |
| n.AsFloat32(f) |
| return nil |
| case Float64Type: |
| f, err := r.ReadFloat64() |
| if err != nil { |
| return err |
| } |
| n.AsFloat64(f) |
| return nil |
| case IntType: |
| i, err := r.ReadInt64() |
| if err != nil { |
| return err |
| } |
| n.AsInt(i) |
| return nil |
| case UintType: |
| u, err := r.ReadUint64() |
| if err != nil { |
| return err |
| } |
| n.AsUint(u) |
| return nil |
| default: |
| return TypeError{Encoded: typ, Method: IntType} |
| } |
| } |
| |
| // UnmarshalMsg implements msgp.Unmarshaler |
| func (n *Number) UnmarshalMsg(b []byte) ([]byte, error) { |
| typ := NextType(b) |
| switch typ { |
| case IntType: |
| i, o, err := ReadInt64Bytes(b) |
| if err != nil { |
| return b, err |
| } |
| n.AsInt(i) |
| return o, nil |
| case UintType: |
| u, o, err := ReadUint64Bytes(b) |
| if err != nil { |
| return b, err |
| } |
| n.AsUint(u) |
| return o, nil |
| case Float64Type: |
| f, o, err := ReadFloat64Bytes(b) |
| if err != nil { |
| return b, err |
| } |
| n.AsFloat64(f) |
| return o, nil |
| case Float32Type: |
| f, o, err := ReadFloat32Bytes(b) |
| if err != nil { |
| return b, err |
| } |
| n.AsFloat32(f) |
| return o, nil |
| default: |
| return b, TypeError{Method: IntType, Encoded: typ} |
| } |
| } |
| |
| // MarshalMsg implements msgp.Marshaler |
| func (n *Number) MarshalMsg(b []byte) ([]byte, error) { |
| switch n.typ { |
| case IntType: |
| return AppendInt64(b, int64(n.bits)), nil |
| case UintType: |
| return AppendUint64(b, uint64(n.bits)), nil |
| case Float64Type: |
| return AppendFloat64(b, math.Float64frombits(n.bits)), nil |
| case Float32Type: |
| return AppendFloat32(b, math.Float32frombits(uint32(n.bits))), nil |
| default: |
| return AppendInt64(b, 0), nil |
| } |
| } |
| |
| // EncodeMsg implements msgp.Encodable |
| func (n *Number) EncodeMsg(w *Writer) error { |
| switch n.typ { |
| case IntType: |
| return w.WriteInt64(int64(n.bits)) |
| case UintType: |
| return w.WriteUint64(n.bits) |
| case Float64Type: |
| return w.WriteFloat64(math.Float64frombits(n.bits)) |
| case Float32Type: |
| return w.WriteFloat32(math.Float32frombits(uint32(n.bits))) |
| default: |
| return w.WriteInt64(0) |
| } |
| } |
| |
| // Msgsize implements msgp.Sizer |
| func (n *Number) Msgsize() int { |
| switch n.typ { |
| case Float32Type: |
| return Float32Size |
| case Float64Type: |
| return Float64Size |
| case IntType: |
| return Int64Size |
| case UintType: |
| return Uint64Size |
| default: |
| return 1 // fixint(0) |
| } |
| } |
| |
| // MarshalJSON implements json.Marshaler |
| func (n *Number) MarshalJSON() ([]byte, error) { |
| t := n.Type() |
| if t == InvalidType { |
| return []byte{'0'}, nil |
| } |
| out := make([]byte, 0, 32) |
| switch t { |
| case Float32Type, Float64Type: |
| f, _ := n.Float() |
| return strconv.AppendFloat(out, f, 'f', -1, 64), nil |
| case IntType: |
| i, _ := n.Int() |
| return strconv.AppendInt(out, i, 10), nil |
| case UintType: |
| u, _ := n.Uint() |
| return strconv.AppendUint(out, u, 10), nil |
| default: |
| panic("(*Number).typ is invalid") |
| } |
| } |
| |
| // String implements fmt.Stringer |
| func (n *Number) String() string { |
| switch n.typ { |
| case InvalidType: |
| return "0" |
| case Float32Type, Float64Type: |
| f, _ := n.Float() |
| return strconv.FormatFloat(f, 'f', -1, 64) |
| case IntType: |
| i, _ := n.Int() |
| return strconv.FormatInt(i, 10) |
| case UintType: |
| u, _ := n.Uint() |
| return strconv.FormatUint(u, 10) |
| default: |
| panic("(*Number).typ is invalid") |
| } |
| } |