diff --git a/decoder.go b/decoder.go index 8f405d1..23565d8 100644 --- a/decoder.go +++ b/decoder.go @@ -77,39 +77,13 @@ func NewDecoder(data []byte) *Decoder { } } -func (d *Decoder) DecodeP2PMessage(decode bool) { - d.decodeP2PMessage = decode -} - -func (d *Decoder) DecodeActions(decode bool) { - d.decodeActions = decode -} - -type DecodeOption struct { - optionalField bool - sizeOfSlice *int -} - -func (o *DecodeOption) isOptional() bool { - return o.optionalField -} -func (o *DecodeOption) hasSizeOfSlice() bool { - return o.sizeOfSlice != nil -} -func (o *DecodeOption) getSizeOfSlice() int { - return *o.sizeOfSlice -} -func (o *DecodeOption) setSizeOfSlice(size int) { - o.sizeOfSlice = &size -} - func (d *Decoder) Decode(v interface{}) (err error) { return d.DecodeWithOption(v, nil) } -func (d *Decoder) DecodeWithOption(v interface{}, option *DecodeOption) (err error) { +func (d *Decoder) DecodeWithOption(v interface{}, option *Option) (err error) { if option == nil { - option = &DecodeOption{} + option = &Option{} } rv := reflect.Indirect(reflect.ValueOf(v)) @@ -207,12 +181,6 @@ func (d *Decoder) DecodeWithOption(v interface{}, option *DecodeOption) (err err n, err = d.ReadInt64() rv.SetInt(int64(n)) return - case *Int64: - var n int64 - n, err = d.ReadInt64() - rv.SetInt(int64(n)) - return - // This is so hackish, doing it right now, but the decoder needs to handle those // case (a struct field that is itself a pointer) by itself. case **Uint64: @@ -222,31 +190,6 @@ func (d *Decoder) DecodeWithOption(v interface{}, option *DecodeOption) (err err rv.Set(reflect.ValueOf((Uint64)(n))) } return - case *Uint64: - var n uint64 - n, err = d.ReadUint64() - rv.SetUint(uint64(n)) - return - case *JSONFloat64: - var n float64 - n, err = d.ReadFloat64() - rv.SetFloat(n) - return - case *Uint128: - var n Uint128 - n, err = d.ReadUint128("uint128") - rv.Set(reflect.ValueOf(n)) - return - case *Int128: - var n Uint128 - n, err = d.ReadUint128("int128") - rv.Set(reflect.ValueOf(Int128(n))) - return - case *Float128: - var n Uint128 - n, err = d.ReadUint128("float128") - rv.Set(reflect.ValueOf(Float128(n))) - return case *uint16: var n uint16 n, err = d.ReadUint16() @@ -277,17 +220,17 @@ func (d *Decoder) DecodeWithOption(v interface{}, option *DecodeOption) (err err r, err = d.ReadUvarint16() rv.SetUint(uint64(r)) return - case *Varuint32: - var r uint64 - r, err = d.ReadUvarint64() - rv.SetUint(r) + case *float32: + var n float32 + n, err = d.ReadFloat32() + rv.SetFloat(float64(n)) return - case *bool: - var r bool - r, err = d.ReadBool() - rv.SetBool(r) + case *float64: + var n float64 + n, err = d.ReadFloat64() + rv.SetFloat(n) return - case *Bool: + case *bool: var r bool r, err = d.ReadBool() rv.SetBool(r) @@ -341,7 +284,7 @@ func (d *Decoder) DecodeWithOption(v interface{}, option *DecodeOption) (err err } default: - return errors.New("decode, unsupported type " + t.String()) + return errors.New("decode: unsupported type " + t.String()) } return @@ -355,7 +298,7 @@ func (d *Decoder) decodeStruct(v interface{}, t reflect.Type, rv reflect.Value) sizeOfMap := map[string]int{} seenBinaryExtensionField := false for i := 0; i < l; i++ { - option := &DecodeOption{} + option := &Option{} structField := t.Field(i) tag := structField.Tag.Get("eos") if tag == "-" { @@ -686,21 +629,6 @@ func (d *Decoder) ReadFloat32() (out float32, err error) { return } -func (d *Decoder) ReadNodeosFloat32() (out float32, err error) { - if d.remaining() < TypeSize.Float32 { - err = fmt.Errorf("float32 required [%d] bytes, remaining [%d]", TypeSize.Float32, d.remaining()) - return - } - - n := binary.LittleEndian.Uint32(d.data[d.pos:]) - out = math.Float32frombits(n) - d.pos += TypeSize.Float32 - if traceEnabled { - zlog.Debug("read float32", zap.Float32("val", out)) - } - return -} - func (d *Decoder) ReadFloat64() (out float64, err error) { if d.remaining() < TypeSize.Float64 { err = fmt.Errorf("float64 required [%d] bytes, remaining [%d]", TypeSize.Float64, d.remaining()) @@ -716,6 +644,15 @@ func (d *Decoder) ReadFloat64() (out float64, err error) { return } +func (d *Decoder) ReadFloat128() (out Float128, err error) { + value, err := d.ReadUint128("float128") + if err != nil { + return out, fmt.Errorf("float128: %s", err) + } + + return Float128(value), nil +} + func (d *Decoder) SafeReadUTF8String() (out string, err error) { data, err := d.ReadByteArray() out = strings.Map(fixUtf, string(data)) diff --git a/decoder_test.go b/decoder_test.go index 46c2c85..a0ec7a0 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -1,7 +1,6 @@ package bin import ( - "bytes" "encoding/binary" "encoding/hex" "math" @@ -30,192 +29,221 @@ func TestDecoder_Remaining(t *testing.T) { assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Byte(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeByte(0) - enc.writeByte(1) +func TestDecoder_int8(t *testing.T) { + buf := []byte{ + 0x9d, // -99 + 0x64, // 100 + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - n, err := d.ReadByte() + n, err := d.ReadInt8() assert.NoError(t, err) - assert.Equal(t, byte(0), n) + assert.Equal(t, int8(-99), n) assert.Equal(t, 1, d.remaining()) - n, err = d.ReadByte() + n, err = d.ReadInt8() assert.NoError(t, err) - assert.Equal(t, byte(1), n) + assert.Equal(t, int8(100), n) assert.Equal(t, 0, d.remaining()) +} + +func TestDecoder_int16(t *testing.T) { + buf := []byte{ + 0xae, 0xff, // -82 + 0x49, 0x00, // 73 + } + + d := NewDecoder(buf) + n, err := d.ReadInt16() + assert.NoError(t, err) + assert.Equal(t, int16(-82), n) + assert.Equal(t, 2, d.remaining()) + + n, err = d.ReadInt16() + assert.NoError(t, err) + assert.Equal(t, int16(73), n) + assert.Equal(t, 0, d.remaining()) } -func TestDecoder_ByteArray(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeByteArray([]byte{1, 2, 3}) - enc.writeByteArray([]byte{4, 5, 6}) +func TestDecoder_int32(t *testing.T) { + buf := []byte{ + 0xd8, 0x8d, 0x8a, 0xef, // -276132392 + 0x4f, 0x9f, 0x3, 0x00, // 237391 + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - data, err := d.ReadByteArray() + n, err := d.ReadInt32() assert.NoError(t, err) - assert.Equal(t, []byte{1, 2, 3}, data) + assert.Equal(t, int32(-276132392), n) assert.Equal(t, 4, d.remaining()) - data, err = d.ReadByteArray() - assert.Equal(t, []byte{4, 5, 6}, data) + n, err = d.ReadInt32() + assert.NoError(t, err) + assert.Equal(t, int32(237391), n) assert.Equal(t, 0, d.remaining()) - } -func TestDecoder_ByteArray_MissingData(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeUVarInt(10) +func TestDecoder_int64(t *testing.T) { + buf := []byte{ + 0x91, 0x7d, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, //-819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - _, err := d.ReadByteArray() - assert.EqualError(t, err, "byte array: varlen=10, missing 10 bytes") + n, err := d.ReadInt64() + assert.NoError(t, err) + assert.Equal(t, int64(-819823), n) + assert.Equal(t, 8, d.remaining()) + n, err = d.ReadInt64() + assert.NoError(t, err) + assert.Equal(t, int64(72931), n) + assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Uint16(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeUint16(uint16(99)) - enc.writeUint16(uint16(100)) +func TestDecoder_uint8(t *testing.T) { + buf := []byte{ + 0x63, // 99 + 0x64, // 100 + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - n, err := d.ReadUint16() + n, err := d.ReadUint8() assert.NoError(t, err) - assert.Equal(t, uint16(99), n) - assert.Equal(t, 2, d.remaining()) + assert.Equal(t, uint8(99), n) + assert.Equal(t, 1, d.remaining()) - n, err = d.ReadUint16() + n, err = d.ReadUint8() assert.NoError(t, err) - assert.Equal(t, uint16(100), n) + assert.Equal(t, uint8(100), n) assert.Equal(t, 0, d.remaining()) } -func TestDecoder_int16(t *testing.T) { - - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeInt16(int16(-99)) - enc.writeInt16(int16(100)) +func TestDecoder_uint16(t *testing.T) { + buf := []byte{ + 0x52, 0x00, // 82 + 0x49, 0x00, // 73 + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - n, err := d.ReadInt16() + n, err := d.ReadUint16() assert.NoError(t, err) - assert.Equal(t, int16(-99), n) + assert.Equal(t, uint16(82), n) assert.Equal(t, 2, d.remaining()) - n, err = d.ReadInt16() + n, err = d.ReadUint16() assert.NoError(t, err) - assert.Equal(t, int16(100), n) + assert.Equal(t, uint16(73), n) assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Uint32(t *testing.T) { - - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.WriteUint32(uint32(342)) - enc.WriteUint32(uint32(100)) +func TestDecoder_uint32(t *testing.T) { + buf := []byte{ + 0x28, 0x72, 0x75, 0x10, // 276132392 as LE + 0x4f, 0x9f, 0x03, 0x00, // 237391 as LE + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) n, err := d.ReadUint32() assert.NoError(t, err) - assert.Equal(t, uint32(342), n) + assert.Equal(t, uint32(276132392), n) assert.Equal(t, 4, d.remaining()) n, err = d.ReadUint32() assert.NoError(t, err) - assert.Equal(t, uint32(100), n) + assert.Equal(t, uint32(237391), n) assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Float64(t *testing.T) { - b, err := hex.DecodeString("000000000000f07f") - require.NoError(t, err) - d := NewDecoder(b) - - f, err := d.ReadFloat64() - assert.NoError(t, err) - assert.Equal(t, math.Inf(1), f) +func TestDecoder_uint64(t *testing.T) { + buf := []byte{ + 0x6f, 0x82, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 + } - b, err = hex.DecodeString("000000000000f0ff") - require.NoError(t, err) - d = NewDecoder(b) + d := NewDecoder(buf) - f, err = d.ReadFloat64() + n, err := d.ReadUint64() assert.NoError(t, err) - assert.Equal(t, math.Inf(-1), f) - - b, err = hex.DecodeString("010000000000f87f") - require.NoError(t, err) - d = NewDecoder(b) + assert.Equal(t, uint64(819823), n) + assert.Equal(t, 8, d.remaining()) - f, err = d.ReadFloat64() + n, err = d.ReadUint64() assert.NoError(t, err) - assert.True(t, math.IsNaN(f)) - + assert.Equal(t, uint64(72931), n) + assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Int32(t *testing.T) { - - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeInt32(int32(-342)) - enc.writeInt32(int32(100)) +func TestDecoder_float32(t *testing.T) { + buf := []byte{ + 0xc3, 0xf5, 0xa8, 0x3f, + 0xa4, 0x70, 0x4d, 0xc0, + } - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) - n, err := d.ReadInt32() + n, err := d.ReadFloat32() assert.NoError(t, err) - assert.Equal(t, int32(-342), n) + assert.Equal(t, float32(1.32), n) assert.Equal(t, 4, d.remaining()) - n, err = d.ReadInt32() + n, err = d.ReadFloat32() assert.NoError(t, err) - assert.Equal(t, int32(100), n) + assert.Equal(t, float32(-3.21), n) assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Uint64(t *testing.T) { +func TestDecoder_float64(t *testing.T) { + buf := []byte{ + 0x3d, 0x0a, 0xd7, 0xa3, 0x70, 0x1d, 0x4f, 0xc0, + 0x77, 0xbe, 0x9f, 0x1a, 0x2f, 0x3d, 0x37, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, + } - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeUint64(uint64(99)) - enc.writeUint64(uint64(100)) + d := NewDecoder(buf) - d := NewDecoder(buf.Bytes()) + n, err := d.ReadFloat64() + assert.NoError(t, err) + assert.Equal(t, float64(-62.23), n) + assert.Equal(t, 32, d.remaining()) - n, err := d.ReadUint64() + n, err = d.ReadFloat64() assert.NoError(t, err) - assert.Equal(t, uint64(99), n) + assert.Equal(t, float64(23.239), n) + assert.Equal(t, 24, d.remaining()) + + n, err = d.ReadFloat64() + assert.NoError(t, err) + assert.Equal(t, math.Inf(1), n) + assert.Equal(t, 16, d.remaining()) + + n, err = d.ReadFloat64() + assert.NoError(t, err) + assert.Equal(t, math.Inf(-1), n) assert.Equal(t, 8, d.remaining()) - n, err = d.ReadUint64() + n, err = d.ReadFloat64() assert.NoError(t, err) - assert.Equal(t, uint64(100), n) - assert.Equal(t, 0, d.remaining()) + assert.True(t, math.IsNaN(n)) } func TestDecoder_string(t *testing.T) { + buf := []byte{ + 0x03, 0x31, 0x32, 0x33, // "123" + 0x00, // "" + 0x03, 0x61, 0x62, 0x63, // "abc + } - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeString("123") - enc.writeString("") - enc.writeString("abc") - - d := NewDecoder(buf.Bytes()) + d := NewDecoder(buf) s, err := d.ReadString() assert.NoError(t, err) @@ -233,158 +261,220 @@ func TestDecoder_string(t *testing.T) { assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Decode_No_Ptr(t *testing.T) { - decoder := NewDecoder([]byte{}) - err := decoder.Decode(1) - assert.EqualError(t, err, "can only decode to pointer type, got int") -} - func TestDecoder_Decode_String_Err(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.writeUVarInt(10) + buf := []byte{ + 0x0a, + } + + decoder := NewDecoder(buf) - decoder := NewDecoder(buf.Bytes()) var s string err := decoder.Decode(&s) assert.EqualError(t, err, "byte array: varlen=10, missing 10 bytes") } -func TestDecoder_Decode_Array(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - enc.Encode([3]byte{1, 2, 4}) +func TestDecoder_Byte(t *testing.T) { + buf := []byte{ + 0x00, 0x01, + } - assert.Equal(t, []byte{1, 2, 4}, buf.Bytes()) + d := NewDecoder(buf) - decoder := NewDecoder(buf.Bytes()) - var decoded [3]byte - decoder.Decode(&decoded) - assert.Equal(t, [3]byte{1, 2, 4}, decoded) + n, err := d.ReadByte() + assert.NoError(t, err) + assert.Equal(t, byte(0), n) + assert.Equal(t, 1, d.remaining()) + + n, err = d.ReadByte() + assert.NoError(t, err) + assert.Equal(t, byte(1), n) + assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Decode_Slice_Err(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) +func TestDecoder_Bool(t *testing.T) { + buf := []byte{ + 0x01, 0x00, + } - decoder := NewDecoder(buf.Bytes()) - var s []string - err := decoder.Decode(&s) - assert.Equal(t, err, ErrVarIntBufferSize) + d := NewDecoder(buf) - enc.writeUVarInt(1) - decoder = NewDecoder(buf.Bytes()) - err = decoder.Decode(&s) - assert.Equal(t, err, ErrVarIntBufferSize) -} + n, err := d.ReadBool() + assert.NoError(t, err) + assert.Equal(t, true, n) + assert.Equal(t, 1, d.remaining()) -type structWithInvalidType struct { - F1 time.Duration + n, err = d.ReadBool() + assert.NoError(t, err) + assert.Equal(t, false, n) + assert.Equal(t, 0, d.remaining()) } -func TestDecoder_Decode_Struct_Err(t *testing.T) { - s := structWithInvalidType{} - decoder := NewDecoder([]byte{}) - err := decoder.Decode(&s) - assert.EqualError(t, err, "decode, unsupported type time.Duration") +func TestDecoder_ByteArray(t *testing.T) { + buf := []byte{ + 0x03, 0x01, 0x02, 0x03, + 0x03, 0x04, 0x05, 0x06, + } -} + d := NewDecoder(buf) -func TestEncoder_Encode_array_error(t *testing.T) { + data, err := d.ReadByteArray() + assert.NoError(t, err) + assert.Equal(t, []byte{1, 2, 3}, data) + assert.Equal(t, 4, d.remaining()) - decoder := NewDecoder([]byte{1}) + data, err = d.ReadByteArray() + assert.Equal(t, []byte{4, 5, 6}, data) + assert.Equal(t, 0, d.remaining()) +} - toDecode := [1]time.Duration{} - err := decoder.Decode(&toDecode) +func TestDecoder_ByteArray_MissingData(t *testing.T) { + buf := []byte{ + 0x0a, + } - assert.EqualError(t, err, "decode, unsupported type time.Duration") + d := NewDecoder(buf) + _, err := d.ReadByteArray() + assert.EqualError(t, err, "byte array: varlen=10, missing 10 bytes") } -func TestEncoder_Decode_array_error(t *testing.T) { +func TestDecoder_Array(t *testing.T) { + buf := []byte{1, 2, 4} - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - err := enc.Encode([1]time.Duration{time.Duration(0)}) - assert.EqualError(t, err, "Encode: unsupported type time.Duration") + decoder := NewDecoder(buf) + var decoded [3]byte + decoder.Decode(&decoded) + assert.Equal(t, [3]byte{1, 2, 4}, decoded) } -func TestEncoder_Encode_slide_error(t *testing.T) { +func TestDecoder_Array_Err(t *testing.T) { - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - err := enc.Encode([]time.Duration{time.Duration(0)}) - assert.EqualError(t, err, "Encode: unsupported type time.Duration") + decoder := NewDecoder([]byte{1}) + toDecode := [1]time.Duration{} + err := decoder.Decode(&toDecode) + + assert.EqualError(t, err, "decode: unsupported type time.Duration") } -func TestEncoder_Encode_struct_error(t *testing.T) { +func TestDecoder_Slice_Err(t *testing.T) { + buf := []byte{} + + decoder := NewDecoder(buf) + var s []string + err := decoder.Decode(&s) + assert.Equal(t, err, ErrVarIntBufferSize) + + buf = []byte{0x01} + + decoder = NewDecoder(buf) + err = decoder.Decode(&s) + assert.Equal(t, err, ErrVarIntBufferSize) +} - s := struct { - F time.Duration - }{ - F: time.Duration(0), +func TestDecoder_Int64(t *testing.T) { + buf := []byte{ + 0x91, 0x7d, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, //-819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 } - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - err := enc.Encode(&s) - assert.EqualError(t, err, "Encode: unsupported type time.Duration") + d := NewDecoder(buf) + n, err := d.ReadInt64() + assert.NoError(t, err) + assert.Equal(t, int64(-819823), n) + assert.Equal(t, 8, d.remaining()) + + n, err = d.ReadInt64() + assert.NoError(t, err) + assert.Equal(t, int64(72931), n) + assert.Equal(t, 0, d.remaining()) } -type DecodeTestStruct struct { +type binaryTestStruct struct { F1 string F2 int16 F3 uint16 - F4 uint32 - F5 []string - F6 [2]string - F7 byte - F8 uint64 - F9 []byte - F10 Varuint32 - F11 bool + F4 int32 + F5 uint32 + F6 int64 + F7 uint64 + F8 float32 + F9 float64 + F10 []string + F11 [2]string + F12 byte + F13 []byte + F14 bool + F15 Int64 + F16 Uint64 + F17 JSONFloat64 + F18 Uint128 + F19 Int128 + F20 Float128 + F21 Varuint32 + F22 Varint32 + F23 Bool + F24 HexBytes } -func TestDecoder_Decode(t *testing.T) { - //EnableDecoderLogging() - //EnableEncoderLogging() - - s := &DecodeTestStruct{ - F1: "abc", - F2: -75, - F3: 99, - F4: 999, - F5: []string{"def", "789"}, - F6: [2]string{"foo", "bar"}, - F7: byte(1), - F8: uint64(87), - F9: []byte{1, 2, 3, 4, 5}, - F10: Varuint32(999), - F11: true, - } - - buf := new(bytes.Buffer) - enc := NewEncoder(buf) - assert.NoError(t, enc.Encode(s)) - - assert.Equal(t, "03616263b5ff6300e7030000000000000000000000000000000000000000000000000000000000000000000002036465660337383903666f6f036261720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001570000000000000005010203040504ae0f517acd5715162e7b46e70701a08601000000000004454f5300000000", hex.EncodeToString(buf.Bytes())) +func TestDecoder_BinaryStruct(t *testing.T) { + cnt, err := hex.DecodeString("03616263b5ff630019ffffffe703000051ccffffffffffff9f860100000000003d0ab9c15c8fc2f5285c0f4002036465660337383903666f6f03626172ff05010203040501e9ffffffffffffff17000000000000001f85eb51b81e09400a000000000000005200000000000000070000000000000003000000000000000a000000000000005200000000000000e707cd0f01050102030405") + require.NoError(t, err) - decoder := NewDecoder(buf.Bytes()) + s := &binaryTestStruct{} + decoder := NewDecoder(cnt) assert.NoError(t, decoder.Decode(s)) assert.Equal(t, "abc", s.F1) assert.Equal(t, int16(-75), s.F2) assert.Equal(t, uint16(99), s.F3) - assert.Equal(t, uint32(999), s.F4) - assert.Equal(t, []string{"def", "789"}, s.F5) - assert.Equal(t, [2]string{"foo", "bar"}, s.F6) - assert.Equal(t, byte(1), s.F7) - assert.Equal(t, uint64(87), s.F8) - assert.Equal(t, []byte{1, 2, 3, 4, 5}, s.F9) - assert.Equal(t, Varuint32(999), s.F10) - assert.Equal(t, true, s.F11) + assert.Equal(t, int32(-231), s.F4) + assert.Equal(t, uint32(999), s.F5) + assert.Equal(t, int64(-13231), s.F6) + assert.Equal(t, uint64(99999), s.F7) + assert.Equal(t, float32(-23.13), s.F8) + assert.Equal(t, float64(3.92), s.F9) + assert.Equal(t, []string{"def", "789"}, s.F10) + assert.Equal(t, [2]string{"foo", "bar"}, s.F11) + assert.Equal(t, uint8(0xff), s.F12) + assert.Equal(t, []byte{1, 2, 3, 4, 5}, s.F13) + assert.Equal(t, true, s.F14) + assert.Equal(t, Int64(-23), s.F15) + assert.Equal(t, Uint64(23), s.F16) + assert.Equal(t, JSONFloat64(3.14), s.F17) + assert.Equal(t, Uint128{ + Lo: 10, + Hi: 82, + }, s.F18) + assert.Equal(t, Int128{ + Lo: 7, + Hi: 3, + }, s.F19) + assert.Equal(t, Float128{ + Lo: 10, + Hi: 82, + }, s.F20) + assert.Equal(t, Varuint32(999), s.F21) + assert.Equal(t, Varint32(-999), s.F22) + assert.Equal(t, Bool(true), s.F23) + assert.Equal(t, HexBytes([]byte{1, 2, 3, 4, 5}), s.F24) +} +type binaryInvalidTestStruct struct { + F1 time.Duration +} + +func TestDecoder_BinaryStruct_Err(t *testing.T) { + s := binaryInvalidTestStruct{} + decoder := NewDecoder([]byte{}) + err := decoder.Decode(&s) + assert.EqualError(t, err, "decode: unsupported type time.Duration") +} + +func TestDecoder_Decode_No_Ptr(t *testing.T) { + decoder := NewDecoder([]byte{}) + err := decoder.Decode(1) + assert.EqualError(t, err, "can only decode to pointer type, got int") } diff --git a/encoder.go b/encoder.go index 88b1909..677fa02 100644 --- a/encoder.go +++ b/encoder.go @@ -1,7 +1,6 @@ package bin import ( - "bytes" "encoding/binary" "errors" "io" @@ -12,24 +11,6 @@ import ( "go.uber.org/zap" ) -// MarshalerBinary is the interface implemented by types -// that can marshal to an EOSIO binary description of themselves. -// -// **Warning** This is experimental, exposed only for internal usage for now. -type MarshalerBinary interface { - MarshalBinary(encoder *Encoder) error -} - -func MarshalBinary(v interface{}) ([]byte, error) { - buf := new(bytes.Buffer) - encoder := NewEncoder(buf) - err := encoder.Encode(v) - return buf.Bytes(), err -} - -// -------------------------------------------------------------- -// Encoder implements the EOS packing, similar to FC_BUFFER -// -------------------------------------------------------------- type Encoder struct { output io.Writer Order binary.ByteOrder @@ -44,23 +25,12 @@ func NewEncoder(w io.Writer) *Encoder { } } -type EncodeOption struct { - sizeOfSlice *int -} - -func (o *EncodeOption) setSizeOfSlice(size int) { - o.sizeOfSlice = &size -} - -func (o *EncodeOption) hasSizeOfSlice() bool { - return o.sizeOfSlice != nil -} func (e *Encoder) Encode(v interface{}) (err error) { return e.EncodeWithOption(v, nil) } -func (e *Encoder) EncodeWithOption(v interface{}, option *EncodeOption) (err error) { +func (e *Encoder) EncodeWithOption(v interface{}, option *Option) (err error) { if option == nil { - option = &EncodeOption{} + option = &Option{} } switch cv := v.(type) { @@ -91,34 +61,14 @@ func (e *Encoder) EncodeWithOption(v interface{}, option *EncodeOption) (err err return e.WriteUint32(cv) case uint64: return e.writeUint64(cv) - case Int64: - return e.writeUint64(uint64(cv)) case int64: return e.writeInt64(cv) case float32: return e.writeFloat32(cv) case float64: return e.writeFloat64(cv) - case Varint16: - return e.writeVarInt(int(cv)) - case Varint32: - return e.writeVarInt(int(cv)) - case Uint128: - return e.writeUint128(cv) - case Int128: - return e.writeUint128(Uint128(cv)) - case Float128: - return e.writeUint128(Uint128(cv)) - case Varuint16: - return e.writeUVarInt(int(cv)) - case Varuint32: - return e.writeUVarInt(int(cv)) case bool: return e.writeBool(cv) - case Bool: - return e.writeBool(bool(cv)) - case HexBytes: - return e.writeByteArray(cv) case []byte: return e.writeByteArray(cv) case nil: @@ -237,7 +187,7 @@ func (e *Encoder) EncodeWithOption(v interface{}, option *EncodeOption) (err err } default: - return errors.New("Encode: unsupported type " + t.String()) + return errors.New("encode: unsupported type " + t.String()) } } @@ -361,6 +311,16 @@ func (e *Encoder) writeUint128(i Uint128) (err error) { return e.toWriter(buf) } +func (e *Encoder) writeInt128(i Int128) (err error) { + if traceEnabled { + zlog.Debug("write int128", zap.Stringer("hex", i), zap.Uint64("lo", i.Lo), zap.Uint64("hi", i.Hi)) + } + buf := make([]byte, TypeSize.Uint128) + binary.LittleEndian.PutUint64(buf, i.Lo) + binary.LittleEndian.PutUint64(buf[TypeSize.Uint64:], i.Hi) + return e.toWriter(buf) +} + func (e *Encoder) writeFloat32(f float32) (err error) { if traceEnabled { zlog.Debug("write float32", zap.Float32("val", f)) diff --git a/encoder_test.go b/encoder_test.go index 3087aa8..bfa704a 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -5,67 +5,228 @@ import ( "encoding/hex" "math" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func TestEncoder_Float64Inf(t *testing.T) { - buffer := bytes.NewBuffer(nil) - encoder := NewEncoder(buffer) - err := encoder.Encode(math.Inf(-1)) - require.NoError(t, err) +func TestEncoder_int8(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + v := int8(-99) + enc.writeByte(byte(v)) + enc.writeByte(byte(int8(100))) - out := hex.EncodeToString(buffer.Bytes()) - require.Equal(t, "000000000000f0ff", out) + assert.Equal(t, []byte{ + 0x9d, // -99 + 0x64, // 100 + }, buf.Bytes()) } -func TestEncoder_Float64NaN(t *testing.T) { - buffer := bytes.NewBuffer(nil) - encoder := NewEncoder(buffer) - err := encoder.Encode(math.NaN()) - require.NoError(t, err) +func TestEncoder_int16(t *testing.T) { + buf := new(bytes.Buffer) - out := hex.EncodeToString(buffer.Bytes()) - require.Equal(t, "010000000000f87f", out) + enc := NewEncoder(buf) + enc.writeInt16(int16(-82)) + enc.writeInt16(int16(73)) + + assert.Equal(t, []byte{ + 0xae, 0xff, // -82 + 0x49, 0x00, // 73 + }, buf.Bytes()) } -func TestEncoder_MapStringString(t *testing.T) { - buffer := bytes.NewBuffer(nil) - encoder := NewEncoder(buffer) - data := map[string]string{ - "a": "1", - "b": "2", - } +func TestEncoder_int32(t *testing.T) { + buf := new(bytes.Buffer) - err := encoder.Encode(data) - require.NoError(t, err) + enc := NewEncoder(buf) + enc.writeInt32(int32(-276132392)) + enc.writeInt32(int32(237391)) + + assert.Equal(t, []byte{ + 0xd8, 0x8d, 0x8a, 0xef, + 0x4f, 0x9f, 0x3, 0x00, + }, buf.Bytes()) +} - out := hex.EncodeToString(buffer.Bytes()) +func TestEncoder_int64(t *testing.T) { + buf := new(bytes.Buffer) - // Sadly, we cannot do much for map not ordered here, so let's check that it's either one or the other - expected1 := "020162013201610131" - expected2 := "020161013101620132" + enc := NewEncoder(buf) + enc.writeInt64(int64(-819823)) + enc.writeInt64(int64(72931)) - if out != expected1 && out != expected2 { - require.Fail(t, "encoded map is invalid", "must be either %q or %q, got %q", expected1, expected2, out) - } + assert.Equal(t, []byte{ + 0x91, 0x7d, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, //-819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 + }, buf.Bytes()) } -func Test_OptionalPrimitiveType(t *testing.T) { - type test struct { - ID uint64 `eos:"optional"` - } +func TestEncoder_uint8(t *testing.T) { + buf := new(bytes.Buffer) - out, err := MarshalBinary(test{ID: 0}) - require.NoError(t, err) + enc := NewEncoder(buf) + enc.writeByte(uint8(99)) + enc.writeByte(uint8(100)) - assert.Equal(t, []byte{0x0}, out) + assert.Equal(t, []byte{ + 0x63, // 99 + 0x64, // 100 + }, buf.Bytes()) +} - out, err = MarshalBinary(test{ID: 10}) - require.NoError(t, err) +func TestEncoder_uint16(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeUint16(uint16(82)) + enc.writeUint16(uint16(73)) + + assert.Equal(t, []byte{ + 0x52, 0x00, // 82 + 0x49, 0x00, // 73 + }, buf.Bytes()) +} + +func TestEncoder_uint32(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeUint32(uint32(276132392)) + enc.writeUint32(uint32(237391)) + + assert.Equal(t, []byte{ + 0x28, 0x72, 0x75, 0x10, // 276132392 as LE + 0x4f, 0x9f, 0x03, 0x00, // 237391 as LE + }, buf.Bytes()) +} + +func TestEncoder_uint64(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeUint64(uint64(819823)) + enc.writeUint64(uint64(72931)) + + assert.Equal(t, []byte{ + 0x6f, 0x82, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, //819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 + }, buf.Bytes()) +} + +func TestEncoder_float32(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeFloat32(float32(1.32)) + enc.writeFloat32(float32(-3.21)) + + assert.Equal(t, []byte{ + 0xc3, 0xf5, 0xa8, 0x3f, + 0xa4, 0x70, 0x4d, 0xc0, + }, buf.Bytes()) +} + +func TestEncoder_float64(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeFloat64(float64(-62.23)) + enc.writeFloat64(float64(23.239)) + enc.writeFloat64(float64(math.Inf(1))) + enc.writeFloat64(float64(math.Inf(-1))) + + assert.Equal(t, []byte{ + 0x3d, 0x0a, 0xd7, 0xa3, 0x70, 0x1d, 0x4f, 0xc0, + 0x77, 0xbe, 0x9f, 0x1a, 0x2f, 0x3d, 0x37, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + }, buf.Bytes()) +} + +func TestEncoder_string(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeString("123") + enc.writeString("") + enc.writeString("abc") + + assert.Equal(t, []byte{ + 0x03, 0x31, 0x32, 0x33, // "123" + 0x00, // "" + 0x03, 0x61, 0x62, 0x63, // "abc + }, buf.Bytes()) +} + +func TestEncoder_byte(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeByte(0) + enc.writeByte(1) + + assert.Equal(t, []byte{ + 0x00, 0x01, + }, buf.Bytes()) +} + +func TestEncoder_bool(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeBool(true) + enc.writeBool(false) + + assert.Equal(t, []byte{ + 0x01, 0x00, + }, buf.Bytes()) +} + +func TestEncoder_ByteArray(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.writeByteArray([]byte{1, 2, 3}) + enc.writeByteArray([]byte{4, 5, 6}) + + assert.Equal(t, []byte{ + 0x03, 0x01, 0x02, 0x03, + 0x03, 0x04, 0x05, 0x06, + }, buf.Bytes()) +} + +func TestEncode_Array(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.Encode([3]byte{1, 2, 4}) + + assert.Equal(t, + []byte{1, 2, 4}, + buf.Bytes(), + ) +} + +func TestEncode_Array_Err(t *testing.T) { + buf := new(bytes.Buffer) + + toEncode := [1]time.Duration{} + + enc := NewEncoder(buf) + err := enc.Encode(toEncode) + assert.EqualError(t, err, "encode: unsupported type time.Duration") +} + +func TestEncoder_Slide_Err(t *testing.T) { + + buf := new(bytes.Buffer) + enc := NewEncoder(buf) + err := enc.Encode([]time.Duration{time.Duration(0)}) + assert.EqualError(t, err, "encode: unsupported type time.Duration") - assert.Equal(t, []byte{0x1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, out) } func Test_OptionalPointerToPrimitiveType(t *testing.T) { @@ -88,3 +249,71 @@ func Test_OptionalPointerToPrimitiveType(t *testing.T) { assert.Equal(t, []byte{0x1, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, out) } + +func TestEncoder_Int64(t *testing.T) { + buf := new(bytes.Buffer) + + enc := NewEncoder(buf) + enc.Encode(Int64(-819823)) + enc.Encode(Int64(72931)) + + assert.Equal(t, []byte{ + 0x91, 0x7d, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff, //-819823 + 0xe3, 0x1c, 0x1, 0x00, 0x00, 0x00, 0x00, 0x00, //72931 + }, buf.Bytes()) +} + +func TestEncoder_BinaryStruct(t *testing.T) { + s := &binaryTestStruct{ + F1: "abc", + F2: -75, + F3: 99, + F4: -231, + F5: 999, + F6: -13231, + F7: 99999, + F8: -23.13, + F9: 3.92, + F10: []string{"def", "789"}, + F11: [2]string{"foo", "bar"}, + F12: 0xff, + F13: []byte{1, 2, 3, 4, 5}, + F14: true, + F15: Int64(-23), + F16: Uint64(23), + F17: JSONFloat64(3.14), + F18: Uint128{ + Lo: 10, + Hi: 82, + }, + F19: Int128{ + Lo: 7, + Hi: 3, + }, + F20: Float128{ + Lo: 10, + Hi: 82, + }, + F21: Varuint32(999), + F22: Varint32(-999), + F23: Bool(true), + F24: HexBytes([]byte{1, 2, 3, 4, 5}), + } + buf := new(bytes.Buffer) + enc := NewEncoder(buf) + assert.NoError(t, enc.Encode(s)) + + assert.Equal(t, + "03616263b5ff630019ffffffe703000051ccffffffffffff9f860100000000003d0ab9c15c8fc2f5285c0f4002036465660337383903666f6f03626172ff05010203040501e9ffffffffffffff17000000000000001f85eb51b81e09400a000000000000005200000000000000070000000000000003000000000000000a000000000000005200000000000000e707cd0f01050102030405", + hex.EncodeToString(buf.Bytes()), + ) +} + +func TestEncoder_BinaryStruct_Err(t *testing.T) { + s := binaryInvalidTestStruct{} + + buf := new(bytes.Buffer) + enc := NewEncoder(buf) + err := enc.Encode(s) + assert.EqualError(t, err, "encode: unsupported type time.Duration") +} diff --git a/init_test.go b/init_test.go index 1407345..7be2741 100644 --- a/init_test.go +++ b/init_test.go @@ -1,10 +1,7 @@ package bin -import ( - "go.uber.org/zap" -) +import "github.com/dfuse-io/logging" func init() { - //traceEnabled = true - zlog, _ = zap.NewDevelopment() + logging.TestingOverride() } diff --git a/interface.go b/interface.go new file mode 100644 index 0000000..25e81db --- /dev/null +++ b/interface.go @@ -0,0 +1,19 @@ +package bin + +import "bytes" + +// MarshalerBinary is the interface implemented by types +// that can marshal to an EOSIO binary description of themselves. +// +// **Warning** This is experimental, exposed only for internal usage for now. +type MarshalerBinary interface { + MarshalBinary(encoder *Encoder) error +} + +func MarshalBinary(v interface{}) ([]byte, error) { + buf := new(bytes.Buffer) + encoder := NewEncoder(buf) + err := encoder.Encode(v) + return buf.Bytes(), err +} + diff --git a/options.go b/options.go new file mode 100644 index 0000000..6a94a3e --- /dev/null +++ b/options.go @@ -0,0 +1,25 @@ +package bin + + + +type Option struct { + optionalField bool + sizeOfSlice *int +} + +func (o *Option) isOptional() bool { + return o.optionalField +} + +func (o *Option) hasSizeOfSlice() bool { + return o.sizeOfSlice != nil +} + +func (o *Option) getSizeOfSlice() int { + return *o.sizeOfSlice +} + +func (o *Option) setSizeOfSlice(size int) { + o.sizeOfSlice = &size +} + diff --git a/parse.go b/parse.go new file mode 100644 index 0000000..8b12d50 --- /dev/null +++ b/parse.go @@ -0,0 +1,37 @@ +package bin + +import ( + "encoding/binary" + "reflect" + "strings" +) + +type filedTag struct { + Sizeof string + Skip bool + Order binary.ByteOrder + +} + + +func parseFieldTag(tag reflect.StructTag) *filedTag { + t := &filedTag{ + Order: binary.LittleEndian, + } + if tag == "-" { + t.Skip = true + return t + } + tagStr := tag.Get("bin") + for _, s := range strings.Split(tagStr, ",") { + if strings.HasPrefix(s, "sizeof=") { + tmp := strings.SplitN(s, "=", 2) + t.Sizeof = tmp[1] + } else if s == "big" { + t.Order = binary.BigEndian + } else if s == "little" { + t.Order = binary.LittleEndian + } + } + return t +} \ No newline at end of file diff --git a/parse_test.go b/parse_test.go new file mode 100644 index 0000000..aa7d182 --- /dev/null +++ b/parse_test.go @@ -0,0 +1,47 @@ +package bin + +import ( + "encoding/binary" + "github.com/stretchr/testify/assert" + "reflect" + "testing" +) + +func Test_parseFieldTag(t *testing.T) { + tests := []struct{ + name string + tag string + expectValue *filedTag + }{ + { + name: "no tags", + tag: "", + expectValue: &filedTag{ + Order: binary.LittleEndian, + }, + }, + { + name: "with a skip", + tag: "-", + expectValue: &filedTag{ + Order: binary.LittleEndian, + Skip: true, + }, + }, + { + name: "with a sizeof", + tag: `bin:"sizeof=Tokens"`, + expectValue: &filedTag{ + Order: binary.LittleEndian, + Sizeof: "Tokens", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expectValue, parseFieldTag(reflect.StructTag(test.tag))) + }) + } + +} \ No newline at end of file diff --git a/types.go b/types.go index 60c42e4..adc72e0 100644 --- a/types.go +++ b/types.go @@ -43,7 +43,19 @@ func (b *Bool) UnmarshalJSON(data []byte) error { return nil } -// HexBytes +func (b *Bool) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadBool() + if err != nil { + return err + } + + *b = Bool(value) + return nil +} + +func (b Bool) MarshalBinary(encoder *Encoder) error { + return encoder.writeBool(bool(b)) +} type HexBytes []byte @@ -66,11 +78,54 @@ func (t HexBytes) String() string { return hex.EncodeToString(t) } +func (o *HexBytes) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadByteArray() + if err != nil { + return fmt.Errorf("hex bytes: %s", err) + } + + *o = HexBytes(value) + return nil +} + +func (o HexBytes) MarshalBinary(encoder *Encoder) error { + return encoder.writeByteArray([]byte(o)) +} + type Varint16 int16 type Varuint16 uint16 type Varuint32 uint32 + +func (o *Varuint32) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadUvarint64() + if err != nil { + return fmt.Errorf("varuint32: %s", err) + } + + *o = Varuint32(value) + return nil +} + +func (o Varuint32) MarshalBinary(encoder *Encoder) error { + return encoder.writeUVarInt(int(o)) +} + type Varint32 int32 +func (o *Varint32) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadVarint32() + if err != nil { + return err + } + + *o = Varint32(value) + return nil +} + +func (o Varint32) MarshalBinary(encoder *Encoder) error { + return encoder.writeVarInt(int(o)) +} + type JSONFloat64 float64 func (f *JSONFloat64) UnmarshalJSON(data []byte) error { @@ -104,6 +159,20 @@ func (f *JSONFloat64) UnmarshalJSON(data []byte) error { return nil } +func (f *JSONFloat64) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadFloat64() + if err != nil { + return err + } + + *f = JSONFloat64(value) + return nil +} + +func (f JSONFloat64) MarshalBinary(encoder *Encoder) error { + return encoder.writeFloat64(float64(f)) +} + type Int64 int64 func (i Int64) MarshalJSON() (data []byte, err error) { @@ -150,6 +219,20 @@ func (i *Int64) UnmarshalJSON(data []byte) error { return nil } +func (i *Int64) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadInt64() + if err != nil { + return err + } + + *i = Int64(value) + return nil +} + +func (i Int64) MarshalBinary(encoder *Encoder) error { + return encoder.writeInt64(int64(i)) +} + type Uint64 uint64 func (i Uint64) MarshalJSON() (data []byte, err error) { @@ -196,6 +279,16 @@ func (i *Uint64) UnmarshalJSON(data []byte) error { return nil } +func (i *Uint64) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadUint64() + if err != nil { + return err + } + + *i = Uint64(value) + return nil +} + func (i Uint64) MarshalBinary(encoder *Encoder) error { return encoder.writeUint64(uint64(i)) } @@ -271,6 +364,20 @@ func (i *Uint128) UnmarshalJSON(data []byte) error { return nil } +func (i *Uint128) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadUint128("uint128") + if err != nil { + return err + } + + *i = value + return nil +} + +func (i Uint128) MarshalBinary(encoder *Encoder) error { + return encoder.writeUint128(i) +} + // Int128 type Int128 Uint128 @@ -291,6 +398,10 @@ func (i Int128) BigInt() *big.Int { return value } +func (i Int128) String() string { + return Uint128(i).String() +} + func (i Int128) DecimalString() string { return i.BigInt().String() } @@ -311,6 +422,20 @@ func (i *Int128) UnmarshalJSON(data []byte) error { return nil } +func (i *Int128) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadInt128() + if err != nil { + return err + } + + *i = value + return nil +} + +func (i Int128) MarshalBinary(encoder *Encoder) error { + return encoder.writeInt128(i) +} + type Float128 Uint128 func (i Float128) MarshalJSON() (data []byte, err error) { @@ -329,6 +454,20 @@ func (i *Float128) UnmarshalJSON(data []byte) error { return nil } +func (i *Float128) UnmarshalBinary(decoder *Decoder) error { + value, err := decoder.ReadFloat128() + if err != nil { + return err + } + + *i = Float128(value) + return nil +} + +func (i Float128) MarshalBinary(encoder *Encoder) error { + return encoder.writeUint128(Uint128(i)) +} + // Blob // Blob is base64 encoded data