From 5fd37375532e3875ad440741cabb6d86bcc2bfce Mon Sep 17 00:00:00 2001 From: shamaton Date: Tue, 26 Aug 2025 21:30:00 +0900 Subject: [PATCH 1/6] add comments to interfaces and functions in ext package --- ext/decode.go | 21 +++++++++++++++++++++ ext/decoder_stream.go | 11 +++++++++++ ext/encode.go | 41 +++++++++++++++++++++++++++++++++++++++++ ext/encode_stream.go | 27 +++++++++++++++++++++++---- 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/ext/decode.go b/ext/decode.go index ddc7829..6cae0eb 100644 --- a/ext/decode.go +++ b/ext/decode.go @@ -6,35 +6,56 @@ import ( "github.com/shamaton/msgpack/v2/def" ) +// Decoder defines an interface for decoding values from bytes. +// It provides methods to get the decoder type, check if the data matches the type, +// and convert the data into a Go value. type Decoder interface { + // Code returns the unique code representing the decoder type. Code() int8 + + // IsType checks if the data at the given offset matches the expected type. + // Returns true if the type matches, false otherwise. IsType(offset int, d *[]byte) bool + + // AsValue decodes the data at the given offset into a Go value of the specified kind. + // Returns the decoded value, the new offset, and an error if decoding fails. AsValue(offset int, k reflect.Kind, d *[]byte) (interface{}, int, error) } +// DecoderCommon provides common utility methods for decoding data from bytes. type DecoderCommon struct { } +// ReadSize1 reads a single byte from the given index in the byte slice. +// Returns the byte and the new index after reading. func (cd *DecoderCommon) ReadSize1(index int, d *[]byte) (byte, int) { rb := def.Byte1 return (*d)[index], index + rb } +// ReadSize2 reads two bytes from the given index in the byte slice. +// Returns the bytes as a slice and the new index after reading. func (cd *DecoderCommon) ReadSize2(index int, d *[]byte) ([]byte, int) { rb := def.Byte2 return (*d)[index : index+rb], index + rb } +// ReadSize4 reads four bytes from the given index in the byte slice. +// Returns the bytes as a slice and the new index after reading. func (cd *DecoderCommon) ReadSize4(index int, d *[]byte) ([]byte, int) { rb := def.Byte4 return (*d)[index : index+rb], index + rb } +// ReadSize8 reads eight bytes from the given index in the byte slice. +// Returns the bytes as a slice and the new index after reading. func (cd *DecoderCommon) ReadSize8(index int, d *[]byte) ([]byte, int) { rb := def.Byte8 return (*d)[index : index+rb], index + rb } +// ReadSizeN reads a specified number of bytes (n) from the given index in the byte slice. +// Returns the bytes as a slice and the new index after reading. func (cd *DecoderCommon) ReadSizeN(index, n int, d *[]byte) ([]byte, int) { return (*d)[index : index+n], index + n } diff --git a/ext/decoder_stream.go b/ext/decoder_stream.go index b7a8a30..719469e 100644 --- a/ext/decoder_stream.go +++ b/ext/decoder_stream.go @@ -4,8 +4,19 @@ import ( "reflect" ) +// StreamDecoder defines an interface for decoding streams of data. +// It provides methods to retrieve the decoder's code, check type compatibility, +// and convert raw data into a Go value of a specified kind. type StreamDecoder interface { + // Code returns the unique identifier for the decoder. Code() int8 + + // IsType checks if the provided code, inner type, and data length match the expected type. + // Returns true if the type matches, otherwise false. IsType(code byte, innerType int8, dataLength int) bool + + // ToValue converts the raw data into a Go value of the specified kind. + // Takes the code, raw data, and the target kind as input. + // Returns the decoded value or an error if the conversion fails. ToValue(code byte, data []byte, k reflect.Kind) (any, error) } diff --git a/ext/encode.go b/ext/encode.go index 56f5cd0..38afeef 100644 --- a/ext/encode.go +++ b/ext/encode.go @@ -4,27 +4,48 @@ import ( "reflect" ) +// Encoder defines an interface for encoding values into bytes. +// It provides methods to get the encoding type, calculate the byte size of a value, +// and write the encoded value into a byte slice. type Encoder interface { + // Code returns the unique code representing the encoder type. Code() int8 + + // Type returns the reflect.Type of the value that the encoder handles. Type() reflect.Type + + // CalcByteSize calculates the number of bytes required to encode the given value. + // Returns the size and an error if the calculation fails. CalcByteSize(value reflect.Value) (int, error) + + // WriteToBytes encodes the given value into a byte slice starting at the specified offset. + // Returns the new offset after writing the bytes. WriteToBytes(value reflect.Value, offset int, bytes *[]byte) int } +// EncoderCommon provides utility methods for encoding various types of values into bytes. +// It includes methods to encode integers and unsigned integers of different sizes, +// as well as methods to write raw byte slices into a target byte slice. type EncoderCommon struct { } +// SetByte1Int64 encodes a single byte from the given int64 value into the byte slice at the specified offset. +// Returns the new offset after writing the byte. func (c *EncoderCommon) SetByte1Int64(value int64, offset int, d *[]byte) int { (*d)[offset] = byte(value) return offset + 1 } +// SetByte2Int64 encodes the lower two bytes of the given int64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte2Int64(value int64, offset int, d *[]byte) int { (*d)[offset+0] = byte(value >> 8) (*d)[offset+1] = byte(value) return offset + 2 } +// SetByte4Int64 encodes the lower four bytes of the given int64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte4Int64(value int64, offset int, d *[]byte) int { (*d)[offset+0] = byte(value >> 24) (*d)[offset+1] = byte(value >> 16) @@ -33,6 +54,8 @@ func (c *EncoderCommon) SetByte4Int64(value int64, offset int, d *[]byte) int { return offset + 4 } +// SetByte8Int64 encodes all eight bytes of the given int64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte8Int64(value int64, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 56) (*d)[offset+1] = byte(value >> 48) @@ -45,17 +68,23 @@ func (c *EncoderCommon) SetByte8Int64(value int64, offset int, d *[]byte) int { return offset + 8 } +// SetByte1Uint64 encodes a single byte from the given uint64 value into the byte slice at the specified offset. +// Returns the new offset after writing the byte. func (c *EncoderCommon) SetByte1Uint64(value uint64, offset int, d *[]byte) int { (*d)[offset] = byte(value) return offset + 1 } +// SetByte2Uint64 encodes the lower two bytes of the given uint64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte2Uint64(value uint64, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 8) (*d)[offset+1] = byte(value) return offset + 2 } +// SetByte4Uint64 encodes the lower four bytes of the given uint64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte4Uint64(value uint64, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 24) (*d)[offset+1] = byte(value >> 16) @@ -64,6 +93,8 @@ func (c *EncoderCommon) SetByte4Uint64(value uint64, offset int, d *[]byte) int return offset + 4 } +// SetByte8Uint64 encodes all eight bytes of the given uint64 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte8Uint64(value uint64, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 56) (*d)[offset+1] = byte(value >> 48) @@ -76,17 +107,23 @@ func (c *EncoderCommon) SetByte8Uint64(value uint64, offset int, d *[]byte) int return offset + 8 } +// SetByte1Int encodes a single byte from the given int value into the byte slice at the specified offset. +// Returns the new offset after writing the byte. func (c *EncoderCommon) SetByte1Int(code, offset int, d *[]byte) int { (*d)[offset] = byte(code) return offset + 1 } +// SetByte2Int encodes the lower two bytes of the given int value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte2Int(value int, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 8) (*d)[offset+1] = byte(value) return offset + 2 } +// SetByte4Int encodes the lower four bytes of the given int value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte4Int(value int, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 24) (*d)[offset+1] = byte(value >> 16) @@ -95,6 +132,8 @@ func (c *EncoderCommon) SetByte4Int(value int, offset int, d *[]byte) int { return offset + 4 } +// SetByte4Uint32 encodes the lower four bytes of the given uint32 value into the byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetByte4Uint32(value uint32, offset int, d *[]byte) int { (*d)[offset] = byte(value >> 24) (*d)[offset+1] = byte(value >> 16) @@ -103,6 +142,8 @@ func (c *EncoderCommon) SetByte4Uint32(value uint32, offset int, d *[]byte) int return offset + 4 } +// SetBytes writes the given byte slice `bs` into the target byte slice at the specified offset. +// Returns the new offset after writing the bytes. func (c *EncoderCommon) SetBytes(bs []byte, offset int, d *[]byte) int { for i := range bs { (*d)[offset+i] = bs[i] diff --git a/ext/encode_stream.go b/ext/encode_stream.go index a284e62..0172792 100644 --- a/ext/encode_stream.go +++ b/ext/encode_stream.go @@ -7,29 +7,37 @@ import ( "github.com/shamaton/msgpack/v2/internal/common" ) -// StreamEncoder is interface that extended encoder should implement +// StreamEncoder is an interface that extended encoders should implement. +// It defines methods for encoding data into a stream. type StreamEncoder interface { + // Code returns the unique code for the encoder. Code() int8 + // Type returns the reflect.Type of the value being encoded. Type() reflect.Type + // Write encodes the given value and writes it to the provided StreamWriter. Write(w StreamWriter, value reflect.Value) error } -// StreamWriter is provided some writing functions for extended format by user +// StreamWriter provides methods for writing data in extended formats. +// It wraps an io.Writer and a buffer for efficient writing. type StreamWriter struct { - w io.Writer - buf *common.Buffer + w io.Writer // The underlying writer to write data to. + buf *common.Buffer // A buffer used for temporary storage during writing. } +// CreateStreamWriter creates and returns a new StreamWriter instance. func CreateStreamWriter(w io.Writer, buf *common.Buffer) StreamWriter { return StreamWriter{w, buf} } +// WriteByte1Int64 writes a single byte representation of an int64 value. func (w *StreamWriter) WriteByte1Int64(value int64) error { return w.buf.Write(w.w, byte(value), ) } +// WriteByte2Int64 writes a two-byte representation of an int64 value. func (w *StreamWriter) WriteByte2Int64(value int64) error { return w.buf.Write(w.w, byte(value>>8), @@ -37,6 +45,7 @@ func (w *StreamWriter) WriteByte2Int64(value int64) error { ) } +// WriteByte4Int64 writes a four-byte representation of an int64 value. func (w *StreamWriter) WriteByte4Int64(value int64) error { return w.buf.Write(w.w, byte(value>>24), @@ -46,6 +55,7 @@ func (w *StreamWriter) WriteByte4Int64(value int64) error { ) } +// WriteByte8Int64 writes an eight-byte representation of an int64 value. func (w *StreamWriter) WriteByte8Int64(value int64) error { return w.buf.Write(w.w, byte(value>>56), @@ -59,12 +69,14 @@ func (w *StreamWriter) WriteByte8Int64(value int64) error { ) } +// WriteByte1Uint64 writes a single byte representation of a uint64 value. func (w *StreamWriter) WriteByte1Uint64(value uint64) error { return w.buf.Write(w.w, byte(value), ) } +// WriteByte2Uint64 writes a two-byte representation of a uint64 value. func (w *StreamWriter) WriteByte2Uint64(value uint64) error { return w.buf.Write(w.w, byte(value>>8), @@ -72,6 +84,7 @@ func (w *StreamWriter) WriteByte2Uint64(value uint64) error { ) } +// WriteByte4Uint64 writes a four-byte representation of a uint64 value. func (w *StreamWriter) WriteByte4Uint64(value uint64) error { return w.buf.Write(w.w, byte(value>>24), @@ -81,6 +94,7 @@ func (w *StreamWriter) WriteByte4Uint64(value uint64) error { ) } +// WriteByte8Uint64 writes an eight-byte representation of a uint64 value. func (w *StreamWriter) WriteByte8Uint64(value uint64) error { return w.buf.Write(w.w, byte(value>>56), @@ -94,12 +108,14 @@ func (w *StreamWriter) WriteByte8Uint64(value uint64) error { ) } +// WriteByte1Int writes a single byte representation of an int value. func (w *StreamWriter) WriteByte1Int(value int) error { return w.buf.Write(w.w, byte(value), ) } +// WriteByte2Int writes a two-byte representation of an int value. func (w *StreamWriter) WriteByte2Int(value int) error { return w.buf.Write(w.w, byte(value>>8), @@ -107,6 +123,7 @@ func (w *StreamWriter) WriteByte2Int(value int) error { ) } +// WriteByte4Int writes a four-byte representation of an int value. func (w *StreamWriter) WriteByte4Int(value int) error { return w.buf.Write(w.w, byte(value>>24), @@ -116,6 +133,7 @@ func (w *StreamWriter) WriteByte4Int(value int) error { ) } +// WriteByte4Uint32 writes a four-byte representation of a uint32 value. func (w *StreamWriter) WriteByte4Uint32(value uint32) error { return w.buf.Write(w.w, byte(value>>24), @@ -125,6 +143,7 @@ func (w *StreamWriter) WriteByte4Uint32(value uint32) error { ) } +// WriteBytes writes a slice of bytes to the underlying writer. func (w *StreamWriter) WriteBytes(bs []byte) error { return w.buf.Write(w.w, bs...) } From d3b0a8f8f53b8f098672aec2cca05e71a47ecf3e Mon Sep 17 00:00:00 2001 From: shamaton Date: Wed, 27 Aug 2025 07:34:51 +0900 Subject: [PATCH 2/6] refine size calcuration logics in all types --- internal/encoding/byte.go | 6 +- internal/encoding/byte_test.go | 6 +- internal/encoding/complex.go | 4 +- internal/encoding/encoding.go | 141 +++++++-------- internal/encoding/encoding_test.go | 43 +++++ internal/encoding/float.go | 8 +- internal/encoding/int.go | 10 +- internal/encoding/map.go | 282 ++++++++++++++++++++++------- internal/encoding/slice.go | 100 ++++++++-- internal/encoding/slice_test.go | 28 +-- internal/encoding/string.go | 8 +- internal/encoding/struct.go | 30 +-- internal/encoding/struct_test.go | 16 +- internal/encoding/uint.go | 10 +- msgpack_test.go | 2 +- time/encode.go | 6 +- 16 files changed, 466 insertions(+), 234 deletions(-) diff --git a/internal/encoding/byte.go b/internal/encoding/byte.go index c1bb107..cbd5a7d 100644 --- a/internal/encoding/byte.go +++ b/internal/encoding/byte.go @@ -16,11 +16,11 @@ func (e *encoder) isByteSlice(rv reflect.Value) bool { func (e *encoder) calcByteSlice(l int) (int, error) { if l <= math.MaxUint8 { - return def.Byte1 + l, nil + return def.Byte1 + def.Byte1 + l, nil } else if l <= math.MaxUint16 { - return def.Byte2 + l, nil + return def.Byte1 + def.Byte2 + l, nil } else if uint(l) <= math.MaxUint32 { - return def.Byte4 + l, nil + return def.Byte1 + def.Byte4 + l, nil } // not supported error return 0, fmt.Errorf("%w slice length : %d", def.ErrUnsupportedType, l) diff --git a/internal/encoding/byte_test.go b/internal/encoding/byte_test.go index 1c9400c..b629b00 100644 --- a/internal/encoding/byte_test.go +++ b/internal/encoding/byte_test.go @@ -19,17 +19,17 @@ func Test_calcByteSlice(t *testing.T) { { name: "u8", value: math.MaxUint8, - result: def.Byte1 + math.MaxUint8, + result: def.Byte1 + def.Byte1 + math.MaxUint8, }, { name: "u16", value: math.MaxUint16, - result: def.Byte2 + math.MaxUint16, + result: def.Byte1 + def.Byte2 + math.MaxUint16, }, { name: "u32", value: math.MaxUint32, - result: def.Byte4 + math.MaxUint32, + result: def.Byte1 + def.Byte4 + math.MaxUint32, }, { name: "u32over", diff --git a/internal/encoding/complex.go b/internal/encoding/complex.go index 4a5f045..be640c0 100644 --- a/internal/encoding/complex.go +++ b/internal/encoding/complex.go @@ -7,11 +7,11 @@ import ( ) func (e *encoder) calcComplex64() int { - return def.Byte1 + def.Byte8 + return def.Byte1 + def.Byte1 + def.Byte8 } func (e *encoder) calcComplex128() int { - return def.Byte1 + def.Byte16 + return def.Byte1 + def.Byte1 + def.Byte16 } func (e *encoder) writeComplex64(v complex64, offset int) int { diff --git a/internal/encoding/encoding.go b/internal/encoding/encoding.go index 1d39310..62081b5 100644 --- a/internal/encoding/encoding.go +++ b/internal/encoding/encoding.go @@ -63,65 +63,48 @@ func Encode(v interface{}, asArray bool) (b []byte, err error) { //} func (e *encoder) calcSize(rv reflect.Value) (int, error) { - ret := def.Byte1 - switch rv.Kind() { case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: v := rv.Uint() - ret += e.calcUint(v) + return e.calcUint(v), nil case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: v := rv.Int() - ret += e.calcInt(int64(v)) + return e.calcInt(int64(v)), nil case reflect.Float32: - ret += e.calcFloat32(0) + return e.calcFloat32(0), nil case reflect.Float64: - ret += e.calcFloat64(0) + return e.calcFloat64(0), nil case reflect.String: - ret += e.calcString(rv.String()) + return e.calcString(rv.String()), nil case reflect.Bool: - // do nothing + return def.Byte1, nil case reflect.Complex64: - ret += e.calcComplex64() + return e.calcComplex64(), nil case reflect.Complex128: - ret += e.calcComplex128() + return e.calcComplex128(), nil case reflect.Slice: if rv.IsNil() { - return ret, nil + return def.Byte1, nil } - l := rv.Len() // bin format if e.isByteSlice(rv) { - r, err := e.calcByteSlice(l) + size, err := e.calcByteSlice(rv.Len()) if err != nil { return 0, err } - ret += r - return ret, nil - } - - // format size - if l <= 0x0f { - // format code only - } else if l <= math.MaxUint16 { - ret += def.Byte2 - } else if uint(l) <= math.MaxUint32 { - ret += def.Byte4 - } else { - // not supported error - return 0, fmt.Errorf("%w array length : %d", def.ErrUnsupportedType, l) + return size, nil } if size, find := e.calcFixedSlice(rv); find { - ret += size - return ret, nil + return size, nil } // func @@ -129,42 +112,34 @@ func (e *encoder) calcSize(rv reflect.Value) (int, error) { var f structCalcFunc if elem.Kind() == reflect.Struct { f = e.getStructCalc(elem) - ret += def.Byte1 * l } else { f = e.calcSize } + l := rv.Len() + size, err := e.calcLength(l) + if err != nil { + return 0, err + } + // objects size for i := 0; i < l; i++ { - size, err := f(rv.Index(i)) + s, err := f(rv.Index(i)) if err != nil { return 0, err } - ret += size + size += s } + return size, nil case reflect.Array: - l := rv.Len() // bin format if e.isByteSlice(rv) { - r, err := e.calcByteSlice(l) + size, err := e.calcByteSlice(rv.Len()) if err != nil { return 0, err } - ret += r - return ret, nil - } - - // format size - if l <= 0x0f { - // format code only - } else if l <= math.MaxUint16 { - ret += def.Byte2 - } else if uint(l) <= math.MaxUint32 { - ret += def.Byte4 - } else { - // not supported error - return 0, fmt.Errorf("array length %d is %w", l, def.ErrUnsupportedLength) + return size, nil } // func @@ -172,41 +147,33 @@ func (e *encoder) calcSize(rv reflect.Value) (int, error) { var f structCalcFunc if elem.Kind() == reflect.Struct { f = e.getStructCalc(elem) - ret += def.Byte1 * l } else { f = e.calcSize } + l := rv.Len() + size, err := e.calcLength(l) + if err != nil { + return 0, err + } + // objects size for i := 0; i < l; i++ { - size, err := f(rv.Index(i)) + s, err := f(rv.Index(i)) if err != nil { return 0, err } - ret += size + size += s } + return size, nil case reflect.Map: if rv.IsNil() { - return ret, nil - } - - l := rv.Len() - // format - if l <= 0x0f { - // do nothing - } else if l <= math.MaxUint16 { - ret += def.Byte2 - } else if uint(l) <= math.MaxUint32 { - ret += def.Byte4 - } else { - // not supported error - return 0, fmt.Errorf("map length %d is %w", l, def.ErrUnsupportedLength) + return def.Byte1, nil } if size, find := e.calcFixedMap(rv); find { - ret += size - return ret, nil + return size, nil } if e.mk == nil { @@ -214,8 +181,13 @@ func (e *encoder) calcSize(rv reflect.Value) (int, error) { e.mv = map[uintptr][]reflect.Value{} } - // key-value keys := rv.MapKeys() + size, err := e.calcLength(len(keys)) + if err != nil { + return 0, err + } + + // key-value mv := make([]reflect.Value, len(keys)) i := 0 for _, k := range keys { @@ -228,44 +200,56 @@ func (e *encoder) calcSize(rv reflect.Value) (int, error) { if err != nil { return 0, err } - ret += keySize + valueSize + size += keySize + valueSize mv[i] = value i++ } e.mk[rv.Pointer()], e.mv[rv.Pointer()] = keys, mv + return size, nil case reflect.Struct: size, err := e.calcStruct(rv) if err != nil { return 0, err } - ret += size + return size, nil case reflect.Ptr: if rv.IsNil() { - return ret, nil + return def.Byte1, nil } size, err := e.calcSize(rv.Elem()) if err != nil { return 0, err } - ret = size + return size, nil case reflect.Interface: size, err := e.calcSize(rv.Elem()) if err != nil { return 0, err } - ret = size + return size, nil case reflect.Invalid: // do nothing (return nil) + return def.Byte1, nil default: return 0, fmt.Errorf("%v is %w type", rv.Kind(), def.ErrUnsupportedType) } +} - return ret, nil +func (e *encoder) calcLength(l int) (int, error) { + if l <= 0x0f { + return def.Byte1, nil + } else if l <= math.MaxUint16 { + return def.Byte1 + def.Byte2, nil + } else if uint(l) <= math.MaxUint32 { + return def.Byte1 + def.Byte4, nil + } + // not supported error + return 0, fmt.Errorf("array length %d is %w", l, def.ErrUnsupportedLength) } func (e *encoder) create(rv reflect.Value, offset int) int { @@ -301,17 +285,14 @@ func (e *encoder) create(rv reflect.Value, offset int) int { if rv.IsNil() { return e.writeNil(offset) } - l := rv.Len() + // bin format if e.isByteSlice(rv) { - offset = e.writeByteSliceLength(l, offset) + offset = e.writeByteSliceLength(rv.Len(), offset) offset = e.setBytes(rv.Bytes(), offset) return offset } - // format - offset = e.writeSliceLength(l, offset) - if offset, find := e.writeFixedSlice(rv, offset); find { return offset } @@ -326,6 +307,8 @@ func (e *encoder) create(rv reflect.Value, offset int) int { } // objects + l := rv.Len() + offset = e.writeSliceLength(l, offset) for i := 0; i < l; i++ { offset = f(rv.Index(i), offset) } diff --git a/internal/encoding/encoding_test.go b/internal/encoding/encoding_test.go index f0942c6..1dc59e8 100644 --- a/internal/encoding/encoding_test.go +++ b/internal/encoding/encoding_test.go @@ -223,3 +223,46 @@ func Test_encode(t *testing.T) { f(testcases, t) }) } + +func Test_calcLength(t *testing.T) { + e := encoder{} + + testcases := []struct { + name string + length int + size int + err error + }{ + { + name: "0x0f", + length: 0x0f, + size: def.Byte1, + err: nil, + }, + { + name: "MaxUint16", + length: math.MaxUint16, + size: def.Byte1 + def.Byte2, + err: nil, + }, + { + name: "MaxUint32", + length: math.MaxUint32, + size: def.Byte1 + def.Byte4, + err: nil, + }, + { + name: "error", + length: math.MaxUint32 + 1, + size: 0, + err: def.ErrUnsupportedLength, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + size, err := e.calcLength(tc.length) + tu.IsError(t, err, tc.err) + tu.Equal(t, size, tc.size) + }) + } +} diff --git a/internal/encoding/float.go b/internal/encoding/float.go index 5f67f1f..34eef06 100644 --- a/internal/encoding/float.go +++ b/internal/encoding/float.go @@ -6,12 +6,12 @@ import ( "github.com/shamaton/msgpack/v2/def" ) -func (e *encoder) calcFloat32(v float64) int { - return def.Byte4 +func (e *encoder) calcFloat32(_ float64) int { + return def.Byte1 + def.Byte4 } -func (e *encoder) calcFloat64(v float64) int { - return def.Byte8 +func (e *encoder) calcFloat64(_ float64) int { + return def.Byte1 + def.Byte8 } func (e *encoder) writeFloat32(v float64, offset int) int { diff --git a/internal/encoding/int.go b/internal/encoding/int.go index aac761d..d5c7fd9 100644 --- a/internal/encoding/int.go +++ b/internal/encoding/int.go @@ -15,15 +15,15 @@ func (e *encoder) calcInt(v int64) int { return e.calcUint(uint64(v)) } else if e.isNegativeFixInt64(v) { // format code only - return 0 - } else if v >= math.MinInt8 { return def.Byte1 + } else if v >= math.MinInt8 { + return def.Byte1 + def.Byte1 } else if v >= math.MinInt16 { - return def.Byte2 + return def.Byte1 + def.Byte2 } else if v >= math.MinInt32 { - return def.Byte4 + return def.Byte1 + def.Byte4 } - return def.Byte8 + return def.Byte1 + def.Byte8 } func (e *encoder) writeInt(v int64, offset int) int { diff --git a/internal/encoding/map.go b/internal/encoding/map.go index da359fa..0cb9c80 100644 --- a/internal/encoding/map.go +++ b/internal/encoding/map.go @@ -8,252 +8,402 @@ import ( ) func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { - size := 0 - switch m := rv.Interface().(type) { case map[string]int: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcString(k) + size += e.calcInt(int64(v)) } return size, true case map[string]uint: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcString(k) + size += e.calcUint(uint64(v)) } return size, true case map[string]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcString(v) + size += e.calcString(k) + size += e.calcString(v) } return size, true case map[string]float32: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcFloat32(0) + size += e.calcString(k) + size += e.calcFloat32(0) } return size, true case map[string]float64: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcFloat64(0) + size += e.calcString(k) + size += e.calcFloat64(0) } return size, true case map[string]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcString(k) + size += e.calcString(k) size += def.Byte1 /*+ e.calcBool()*/ } return size, true case map[string]int8: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcString(k) + size += e.calcInt(int64(v)) } return size, true case map[string]int16: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcString(k) + size += e.calcInt(int64(v)) } return size, true case map[string]int32: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcString(k) + size += e.calcInt(int64(v)) } return size, true case map[string]int64: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcInt(v) + size += e.calcString(k) + size += e.calcInt(v) } return size, true case map[string]uint8: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcString(k) + size += e.calcUint(uint64(v)) } return size, true case map[string]uint16: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcString(k) + size += e.calcUint(uint64(v)) } return size, true case map[string]uint32: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcString(k) + size += e.calcUint(uint64(v)) } return size, true case map[string]uint64: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcString(k) - size += def.Byte1 + e.calcUint(v) + size += e.calcString(k) + size += e.calcUint(v) } return size, true case map[int]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcInt(int64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcInt(int64(k)) + size += e.calcString(v) } return size, true case map[int]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcInt(int64(k)) + size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcUint(uint64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcUint(uint64(k)) + size += e.calcString(v) } return size, true case map[uint]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcUint(uint64(k)) + size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[float32]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcFloat32(float64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcFloat32(float64(k)) + size += e.calcString(v) } return size, true case map[float32]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcFloat32(float64(k)) + size += e.calcFloat32(float64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[float64]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcFloat64(k) - size += def.Byte1 + e.calcString(v) + size += e.calcFloat64(k) + size += e.calcString(v) } return size, true case map[float64]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcFloat64(k) + size += e.calcFloat64(k) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int8]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcInt(int64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcInt(int64(k)) + size += e.calcString(v) } return size, true case map[int8]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcInt(int64(k)) + size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int16]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcInt(int64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcInt(int64(k)) + size += e.calcString(v) } return size, true case map[int16]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcInt(int64(k)) + size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int32]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcInt(int64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcInt(int64(k)) + size += e.calcString(v) } return size, true case map[int32]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcInt(int64(k)) + size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int64]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcInt(k) - size += def.Byte1 + e.calcString(v) + size += e.calcInt(k) + size += e.calcString(v) } return size, true case map[int64]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcInt(k) + size += e.calcInt(k) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint8]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcUint(uint64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcUint(uint64(k)) + size += e.calcString(v) } return size, true case map[uint8]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcUint(uint64(k)) + size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint16]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcUint(uint64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcUint(uint64(k)) + size += e.calcString(v) } return size, true case map[uint16]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcUint(uint64(k)) + size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint32]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcUint(uint64(k)) - size += def.Byte1 + e.calcString(v) + size += e.calcUint(uint64(k)) + size += e.calcString(v) } return size, true case map[uint32]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcUint(uint64(k)) + size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint64]string: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k, v := range m { - size += def.Byte1 + e.calcUint(k) - size += def.Byte1 + e.calcString(v) + size += e.calcUint(k) + size += e.calcString(v) } return size, true case map[uint64]bool: + size, err := e.calcLength(len(m)) + if err != nil { + return 0, false + } for k := range m { - size += def.Byte1 + e.calcUint(k) + size += e.calcUint(k) size += def.Byte1 /* + e.calcBool()*/ } return size, true } - return size, false + return 0, false } func (e *encoder) writeMapLength(l int, offset int) int { diff --git a/internal/encoding/slice.go b/internal/encoding/slice.go index a18b8c9..a16a765 100644 --- a/internal/encoding/slice.go +++ b/internal/encoding/slice.go @@ -8,93 +8,147 @@ import ( ) func (e *encoder) calcFixedSlice(rv reflect.Value) (int, bool) { - size := 0 - switch sli := rv.Interface().(type) { case []int: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcInt(int64(v)) } return size, true case []uint: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcUint(uint64(v)) } return size, true case []string: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcString(v) + size += e.calcString(v) } return size, true case []float32: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcFloat32(float64(v)) + size += e.calcFloat32(float64(v)) } return size, true case []float64: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcFloat64(v) + size += e.calcFloat64(v) } return size, true case []bool: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } size += def.Byte1 * len(sli) return size, true case []int8: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcInt(int64(v)) } return size, true case []int16: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcInt(int64(v)) } return size, true case []int32: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcInt(int64(v)) + size += e.calcInt(int64(v)) } return size, true case []int64: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcInt(v) + size += e.calcInt(v) } return size, true case []uint8: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcUint(uint64(v)) } return size, true case []uint16: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcUint(uint64(v)) } return size, true case []uint32: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcUint(uint64(v)) + size += e.calcUint(uint64(v)) } return size, true case []uint64: + size, err := e.calcLength(len(sli)) + if err != nil { + return 0, false + } for _, v := range sli { - size += def.Byte1 + e.calcUint(v) + size += e.calcUint(v) } return size, true } - return size, false + return 0, false } func (e *encoder) writeSliceLength(l int, offset int) int { @@ -115,84 +169,98 @@ func (e *encoder) writeFixedSlice(rv reflect.Value, offset int) (int, bool) { switch sli := rv.Interface().(type) { case []int: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeInt(int64(v), offset) } return offset, true case []uint: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeUint(uint64(v), offset) } return offset, true case []string: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeString(v, offset) } return offset, true case []float32: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeFloat32(float64(v), offset) } return offset, true case []float64: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeFloat64(float64(v), offset) } return offset, true case []bool: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeBool(v, offset) } return offset, true case []int8: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeInt(int64(v), offset) } return offset, true case []int16: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeInt(int64(v), offset) } return offset, true case []int32: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeInt(int64(v), offset) } return offset, true case []int64: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeInt(v, offset) } return offset, true case []uint8: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeUint(uint64(v), offset) } return offset, true case []uint16: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeUint(uint64(v), offset) } return offset, true case []uint32: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeUint(uint64(v), offset) } return offset, true case []uint64: + offset = e.writeSliceLength(len(sli), offset) for _, v := range sli { offset = e.writeUint(v, offset) } diff --git a/internal/encoding/slice_test.go b/internal/encoding/slice_test.go index b30d6a5..3eb6e94 100644 --- a/internal/encoding/slice_test.go +++ b/internal/encoding/slice_test.go @@ -14,59 +14,59 @@ func Test_FixedSlice(t *testing.T) { }{ { value: []int{-1}, - size: 1, + size: 2, }, { value: []uint{1}, - size: 1, + size: 2, }, { value: []string{"a"}, - size: 2, + size: 3, }, { value: []float32{1.23}, - size: 5, + size: 6, }, { value: []float64{1.23}, - size: 9, + size: 10, }, { value: []bool{true}, - size: 1, + size: 2, }, { value: []int8{1}, - size: 1, + size: 2, }, { value: []int16{1}, - size: 1, + size: 2, }, { value: []int32{1}, - size: 1, + size: 2, }, { value: []int64{1}, - size: 1, + size: 2, }, { value: []uint8{1}, - size: 1, + size: 2, }, { value: []uint16{1}, - size: 1, + size: 2, }, { value: []uint32{1}, - size: 1, + size: 2, }, { value: []uint64{1}, - size: 1, + size: 2, }, } for _, tc := range testcases { diff --git a/internal/encoding/string.go b/internal/encoding/string.go index df23d9d..34cff10 100644 --- a/internal/encoding/string.go +++ b/internal/encoding/string.go @@ -12,13 +12,13 @@ func (e *encoder) calcString(v string) int { strBytes := *(*[]byte)(unsafe.Pointer(&v)) l := len(strBytes) if l < 32 { - return l - } else if l <= math.MaxUint8 { return def.Byte1 + l + } else if l <= math.MaxUint8 { + return def.Byte1 + def.Byte1 + l } else if l <= math.MaxUint16 { - return def.Byte2 + l + return def.Byte1 + def.Byte2 + l } - return def.Byte4 + l + return def.Byte1 + def.Byte4 + l // NOTE : length over uint32 } diff --git a/internal/encoding/struct.go b/internal/encoding/struct.go index 20caa21..3b6ed30 100644 --- a/internal/encoding/struct.go +++ b/internal/encoding/struct.go @@ -1,7 +1,6 @@ package encoding import ( - "fmt" "math" "reflect" "sync" @@ -99,17 +98,11 @@ func (e *encoder) calcStructArray(rv reflect.Value) (int, error) { } // format size - l := len(c.indexes) - if l <= 0x0f { - // format code only - } else if l <= math.MaxUint16 { - ret += def.Byte2 - } else if uint(l) <= math.MaxUint32 { - ret += def.Byte4 - } else { - // not supported error - return 0, fmt.Errorf("array length %d is %w", l, def.ErrUnsupportedLength) + size, err := e.calcLength(len(c.indexes)) + if err != nil { + return 0, err } + ret += size return ret, nil } @@ -162,16 +155,11 @@ func (e *encoder) calcStructMap(rv reflect.Value) (int, error) { } // format size - if l <= 0x0f { - // format code only - } else if l <= math.MaxUint16 { - ret += def.Byte2 - } else if uint(l) <= math.MaxUint32 { - ret += def.Byte4 - } else { - // not supported error - return 0, fmt.Errorf("map length %d is %w", l, def.ErrUnsupportedLength) + size, err := e.calcLength(len(c.indexes)) + if err != nil { + return 0, err } + ret += size return ret, nil } @@ -179,7 +167,7 @@ func (e *encoder) calcSizeWithOmitEmpty(rv reflect.Value, name string, omit bool keySize := 0 valueSize := 0 if !omit || !rv.IsZero() { - keySize = def.Byte1 + e.calcString(name) + keySize = e.calcString(name) vSize, err := e.calcSize(rv) if err != nil { return 0, err diff --git a/internal/encoding/struct_test.go b/internal/encoding/struct_test.go index 77195d4..cc01b34 100644 --- a/internal/encoding/struct_test.go +++ b/internal/encoding/struct_test.go @@ -43,17 +43,17 @@ func Test_calcStructArray(t *testing.T) { { name: "0x0f", value: 0x0f, - result: 0, + result: def.Byte1, }, { name: "u16", value: math.MaxUint16, - result: def.Byte2, + result: def.Byte1 + def.Byte2, }, { name: "u32", value: math.MaxUint16 + 1, - result: def.Byte4, + result: def.Byte1 + def.Byte4, }, // can not run by out of memory //{ @@ -108,17 +108,17 @@ func Test_calcStructMap(t *testing.T) { { name: "0x0f", value: 0x0f, - result: 0, + result: def.Byte1, }, { name: "u16", value: math.MaxUint16, - result: def.Byte2, + result: def.Byte1 + def.Byte2, }, { name: "u32", value: math.MaxUint16 + 1, - result: def.Byte4, + result: def.Byte1 + def.Byte4, }, // can not run by out of memory //{ @@ -169,7 +169,7 @@ func Test_writeStructArray(t *testing.T) { size, err := e.calcStructArray(rv) tu.NoError(t, err) - e.d = make([]byte, size+def.Byte1) + e.d = make([]byte, size) result := e.writeStructArray(rv, 0) tu.Equal(t, len(e.d), result) tu.Equal(t, e.d[0], tc.code) @@ -207,7 +207,7 @@ func Test_writeStructMap(t *testing.T) { size, err := e.calcStructMap(rv) tu.NoError(t, err) - e.d = make([]byte, size+def.Byte1) + e.d = make([]byte, size) result := e.writeStructMap(rv, 0) tu.Equal(t, len(e.d), result) tu.Equal(t, e.d[0], tc.code) diff --git a/internal/encoding/uint.go b/internal/encoding/uint.go index d0780e6..4c093b7 100644 --- a/internal/encoding/uint.go +++ b/internal/encoding/uint.go @@ -9,15 +9,15 @@ import ( func (e *encoder) calcUint(v uint64) int { if v <= math.MaxInt8 { // format code only - return 0 - } else if v <= math.MaxUint8 { return def.Byte1 + } else if v <= math.MaxUint8 { + return def.Byte1 + def.Byte1 } else if v <= math.MaxUint16 { - return def.Byte2 + return def.Byte1 + def.Byte2 } else if v <= math.MaxUint32 { - return def.Byte4 + return def.Byte1 + def.Byte4 } - return def.Byte8 + return def.Byte1 + def.Byte8 } func (e *encoder) writeUint(v uint64, offset int) int { diff --git a/msgpack_test.go b/msgpack_test.go index 02cdf82..e68d096 100644 --- a/msgpack_test.go +++ b/msgpack_test.go @@ -2223,7 +2223,7 @@ func (s *testEncoder) Type() reflect.Type { func (s *testEncoder) CalcByteSize(value reflect.Value) (int, error) { t := value.Interface().(ExtInt) - return def.Byte1 + def.Byte1 + 15 + 15 + 10 + len(t.Bytes), nil + return def.Byte1 + def.Byte1 + def.Byte1 + 15 + 15 + 10 + len(t.Bytes), nil } func (s *testEncoder) WriteToBytes(value reflect.Value, offset int, bytes *[]byte) int { diff --git a/time/encode.go b/time/encode.go index ada5b9b..b8ec582 100644 --- a/time/encode.go +++ b/time/encode.go @@ -30,12 +30,12 @@ func (s *timeEncoder) CalcByteSize(value reflect.Value) (int, error) { if secs>>34 == 0 { data := uint64(t.Nanosecond())<<34 | secs if data&0xffffffff00000000 == 0 { - return def.Byte1 + def.Byte4, nil + return def.Byte1 + def.Byte1 + def.Byte4, nil } - return def.Byte1 + def.Byte8, nil + return def.Byte1 + def.Byte1 + def.Byte8, nil } - return def.Byte1 + def.Byte1 + def.Byte4 + def.Byte8, nil + return def.Byte1 + def.Byte1 + def.Byte1 + def.Byte4 + def.Byte8, nil } func (s *timeEncoder) WriteToBytes(value reflect.Value, offset int, bytes *[]byte) int { From dbfb61b22712fdc857c4d99fc988ce0255ec0329 Mon Sep 17 00:00:00 2001 From: shamaton Date: Wed, 27 Aug 2025 07:36:56 +0900 Subject: [PATCH 3/6] add examples for ext encoders --- README.md | 2 +- msgpack_example_test.go | 199 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 msgpack_example_test.go diff --git a/README.md b/README.md index ec9a8a6..97f5b7d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ * Renaming fields via `msgpack:"field_name"` * Omitting fields via `msgpack:"-"` * Omitting empty fields via `msgpack:"field_name,omitempty"` -* Supports extend encoder / decoder +* Supports extend encoder / decoder [(example)](./msgpack_example_test.go) * Can also Encoding / Decoding struct as array ## Installation diff --git a/msgpack_example_test.go b/msgpack_example_test.go new file mode 100644 index 0000000..0ae5f46 --- /dev/null +++ b/msgpack_example_test.go @@ -0,0 +1,199 @@ +package msgpack_test + +import ( + "bytes" + "fmt" + "net" + "reflect" + + "github.com/shamaton/msgpack/v2" + "github.com/shamaton/msgpack/v2/def" + "github.com/shamaton/msgpack/v2/ext" +) + +func ExampleAddExtCoder() { + err := msgpack.AddExtCoder(&IPNetEncoder{}, &IPNetDecoder{}) + if err != nil { + panic(err) + } + + v1 := net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.IPMask{255, 255, 255, 0}} + r1, err := msgpack.Marshal(v1) + if err != nil { + panic(err) + } + fmt.Printf("% 02x\n", r1) + // Output: + // c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + + var v2 net.IPNet + err = msgpack.Unmarshal(r1, &v2) + if err != nil { + panic(err) + } + fmt.Println(v2) + // Output: + // {127.0.0.0 ffffff00} +} + +func ExampleAddExtStreamCoder() { + err := msgpack.AddExtStreamCoder(&IPNetStreamEncoder{}, &IPNetStreamDecoder{}) + if err != nil { + panic(err) + } + + v1 := net.IPNet{IP: net.IP{127, 0, 0, 1}, Mask: net.IPMask{255, 255, 255, 0}} + + buf := bytes.Buffer{} + err = msgpack.MarshalWrite(&buf, v1) + if err != nil { + panic(err) + } + fmt.Printf("% 02x\n", buf.Bytes()) + // Output: + // c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + + var v2 net.IPNet + err = msgpack.UnmarshalRead(&buf, &v2) + if err != nil { + panic(err) + } + fmt.Println(v2) + // Output: + // {127.0.0.0 ffffff00} +} + +const ipNetCode = 50 + +type IPNetDecoder struct { + ext.DecoderCommon +} + +var _ ext.Decoder = (*IPNetDecoder)(nil) + +func (td *IPNetDecoder) Code() int8 { + return ipNetCode +} + +func (td *IPNetDecoder) IsType(offset int, d *[]byte) bool { + code, offset := td.ReadSize1(offset, d) + if code == def.Ext8 { + _, offset = td.ReadSize1(offset, d) + t, _ := td.ReadSize1(offset, d) + return int8(t) == td.Code() + } + return false +} + +func (td *IPNetDecoder) AsValue(offset int, k reflect.Kind, d *[]byte) (any, int, error) { + code, offset := td.ReadSize1(offset, d) + + switch code { + case def.Ext8: + // size + size, offset := td.ReadSize1(offset, d) + // code + _, offset = td.ReadSize1(offset, d) + // value + data, offset := td.ReadSizeN(offset, int(size), d) + + _, v, err := net.ParseCIDR(string(data)) + if err != nil { + return net.IPNet{}, 0, fmt.Errorf("failed to parse CIDR: %w", err) + } + if v == nil { + return net.IPNet{}, 0, fmt.Errorf("parsed CIDR is nil") + } + return *v, offset, nil + } + return net.IPNet{}, 0, fmt.Errorf("should not reach this line!! code %x decoding %v", td.Code(), k) +} + +type IPNetStreamDecoder struct{} + +var _ ext.StreamDecoder = (*IPNetStreamDecoder)(nil) + +func (td *IPNetStreamDecoder) Code() int8 { + return ipNetCode +} + +func (td *IPNetStreamDecoder) IsType(code byte, innerType int8, _ int) bool { + return code == def.Ext8 && innerType == td.Code() +} + +func (td *IPNetStreamDecoder) ToValue(code byte, data []byte, k reflect.Kind) (any, error) { + if code == def.Ext8 { + _, v, err := net.ParseCIDR(string(data)) + if err != nil { + return net.IPNet{}, fmt.Errorf("failed to parse CIDR: %w", err) + } + if v == nil { + return net.IPNet{}, fmt.Errorf("parsed CIDR is nil") + } + return *v, nil + } + return net.IPNet{}, fmt.Errorf("should not reach this line!! code %x decoding %v", td.Code(), k) +} + +type IPNetEncoder struct { + ext.EncoderCommon +} + +var _ ext.Encoder = (*IPNetEncoder)(nil) + +func (s *IPNetEncoder) Code() int8 { + return ipNetCode +} + +func (s *IPNetEncoder) Type() reflect.Type { + return reflect.TypeOf(net.IPNet{}) +} + +func (s *IPNetEncoder) CalcByteSize(value reflect.Value) (int, error) { + v := value.Interface().(net.IPNet) + fmt.Println(def.Byte1 + def.Byte1 + len([]byte(v.String()))) + return def.Byte1 + def.Byte1 + def.Byte1 + len(v.String()), nil +} + +func (s *IPNetEncoder) WriteToBytes(value reflect.Value, offset int, bytes *[]byte) int { + v := value.Interface().(net.IPNet) + data := v.String() + + offset = s.SetByte1Int(def.Ext8, offset, bytes) + offset = s.SetByte1Int(len(data), offset, bytes) + offset = s.SetByte1Int(int(s.Code()), offset, bytes) + offset = s.SetBytes([]byte(data), offset, bytes) + return offset +} + +type IPNetStreamEncoder struct{} + +var _ ext.StreamEncoder = (*IPNetStreamEncoder)(nil) + +func (s *IPNetStreamEncoder) Code() int8 { + return ipNetCode +} + +func (s *IPNetStreamEncoder) Type() reflect.Type { + return reflect.TypeOf(net.IPNet{}) +} + +func (s *IPNetStreamEncoder) Write(w ext.StreamWriter, value reflect.Value) error { + v := value.Interface().(net.IPNet) + data := v.String() + + if err := w.WriteByte1Int(def.Ext8); err != nil { + return err + } + if err := w.WriteByte1Int(len(data)); err != nil { + return err + } + if err := w.WriteByte1Int(int(s.Code())); err != nil { + return err + } + if err := w.WriteBytes([]byte(data)); err != nil { + return err + } + + return nil +} From e411c4923a83639ed781b05a200e19d9773c4c17 Mon Sep 17 00:00:00 2001 From: shamaton Date: Wed, 27 Aug 2025 07:38:32 +0900 Subject: [PATCH 4/6] update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index a5810ed..5593a58 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Masayuki Shamoto +Copyright (c) 2025 Masayuki Shamoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From fa8ef58e906ce2b01d816cf72877d4bd74cf3a6d Mon Sep 17 00:00:00 2001 From: shamaton Date: Wed, 27 Aug 2025 07:46:52 +0900 Subject: [PATCH 5/6] fix example tests --- msgpack_example_test.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/msgpack_example_test.go b/msgpack_example_test.go index 0ae5f46..9bae30c 100644 --- a/msgpack_example_test.go +++ b/msgpack_example_test.go @@ -22,18 +22,18 @@ func ExampleAddExtCoder() { if err != nil { panic(err) } - fmt.Printf("% 02x\n", r1) - // Output: - // c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + fmt.Printf("encode: % 02x\n", r1) var v2 net.IPNet err = msgpack.Unmarshal(r1, &v2) if err != nil { panic(err) } - fmt.Println(v2) + fmt.Println("decode:", v2) + // Output: - // {127.0.0.0 ffffff00} + // encode: c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + // decode: {127.0.0.0 ffffff00} } func ExampleAddExtStreamCoder() { @@ -49,18 +49,18 @@ func ExampleAddExtStreamCoder() { if err != nil { panic(err) } - fmt.Printf("% 02x\n", buf.Bytes()) - // Output: - // c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + fmt.Printf("encode: % 02x\n", buf.Bytes()) var v2 net.IPNet err = msgpack.UnmarshalRead(&buf, &v2) if err != nil { panic(err) } - fmt.Println(v2) + fmt.Println("decode:", v2) + // Output: - // {127.0.0.0 ffffff00} + // encode: c7 0c 32 31 32 37 2e 30 2e 30 2e 31 2f 32 34 + // decode: {127.0.0.0 ffffff00} } const ipNetCode = 50 @@ -151,7 +151,6 @@ func (s *IPNetEncoder) Type() reflect.Type { func (s *IPNetEncoder) CalcByteSize(value reflect.Value) (int, error) { v := value.Interface().(net.IPNet) - fmt.Println(def.Byte1 + def.Byte1 + len([]byte(v.String()))) return def.Byte1 + def.Byte1 + def.Byte1 + len(v.String()), nil } From af3ecf28435a17ff6b9954c250089955491bf206 Mon Sep 17 00:00:00 2001 From: shamaton Date: Thu, 28 Aug 2025 21:43:12 +0900 Subject: [PATCH 6/6] ignore error because of unreachable case --- internal/encoding/map.go | 193 ++++++++----------------------------- internal/encoding/slice.go | 73 ++++---------- 2 files changed, 58 insertions(+), 208 deletions(-) diff --git a/internal/encoding/map.go b/internal/encoding/map.go index 0cb9c80..78ac977 100644 --- a/internal/encoding/map.go +++ b/internal/encoding/map.go @@ -8,12 +8,12 @@ import ( ) func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { + // calcLength formally returns (int, error), but for map lengths in Go + // the error case is unreachable. The error value is always nil and is + // intentionally ignored with `_`. switch m := rv.Interface().(type) { case map[string]int: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcInt(int64(v)) @@ -21,10 +21,7 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]uint: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcUint(uint64(v)) @@ -32,10 +29,7 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcString(v) @@ -43,10 +37,7 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]float32: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcString(k) size += e.calcFloat32(0) @@ -54,10 +45,7 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]float64: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcString(k) size += e.calcFloat64(0) @@ -65,10 +53,7 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcString(k) size += def.Byte1 /*+ e.calcBool()*/ @@ -76,80 +61,56 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[string]int8: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcInt(int64(v)) } return size, true case map[string]int16: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcInt(int64(v)) } return size, true case map[string]int32: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcInt(int64(v)) } return size, true case map[string]int64: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcInt(v) } return size, true case map[string]uint8: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcUint(uint64(v)) } return size, true case map[string]uint16: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcUint(uint64(v)) } return size, true case map[string]uint32: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcUint(uint64(v)) } return size, true case map[string]uint64: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcString(k) size += e.calcUint(v) @@ -157,20 +118,14 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[int]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcInt(int64(k)) size += e.calcString(v) } return size, true case map[int]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ @@ -178,20 +133,14 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[uint]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcUint(uint64(k)) size += e.calcString(v) } return size, true case map[uint]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ @@ -199,20 +148,14 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[float32]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcFloat32(float64(k)) size += e.calcString(v) } return size, true case map[float32]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcFloat32(float64(k)) size += def.Byte1 /* + e.calcBool()*/ @@ -220,20 +163,14 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[float64]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcFloat64(k) size += e.calcString(v) } return size, true case map[float64]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcFloat64(k) size += def.Byte1 /* + e.calcBool()*/ @@ -241,80 +178,56 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[int8]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcInt(int64(k)) size += e.calcString(v) } return size, true case map[int8]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int16]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcInt(int64(k)) size += e.calcString(v) } return size, true case map[int16]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int32]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcInt(int64(k)) size += e.calcString(v) } return size, true case map[int32]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcInt(int64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[int64]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcInt(k) size += e.calcString(v) } return size, true case map[int64]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcInt(k) size += def.Byte1 /* + e.calcBool()*/ @@ -322,80 +235,56 @@ func (e *encoder) calcFixedMap(rv reflect.Value) (int, bool) { return size, true case map[uint8]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcUint(uint64(k)) size += e.calcString(v) } return size, true case map[uint8]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint16]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcUint(uint64(k)) size += e.calcString(v) } return size, true case map[uint16]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint32]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcUint(uint64(k)) size += e.calcString(v) } return size, true case map[uint32]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcUint(uint64(k)) size += def.Byte1 /* + e.calcBool()*/ } return size, true case map[uint64]string: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k, v := range m { size += e.calcUint(k) size += e.calcString(v) } return size, true case map[uint64]bool: - size, err := e.calcLength(len(m)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(m)) for k := range m { size += e.calcUint(k) size += def.Byte1 /* + e.calcBool()*/ diff --git a/internal/encoding/slice.go b/internal/encoding/slice.go index a16a765..bae88c4 100644 --- a/internal/encoding/slice.go +++ b/internal/encoding/slice.go @@ -8,140 +8,101 @@ import ( ) func (e *encoder) calcFixedSlice(rv reflect.Value) (int, bool) { + // calcLength formally returns (int, error), but for map lengths in Go + // the error case is unreachable. The error value is always nil and is + // intentionally ignored with `_`. switch sli := rv.Interface().(type) { case []int: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcInt(int64(v)) } return size, true case []uint: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcUint(uint64(v)) } return size, true case []string: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcString(v) } return size, true case []float32: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcFloat32(float64(v)) } return size, true case []float64: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcFloat64(v) } return size, true case []bool: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) size += def.Byte1 * len(sli) return size, true case []int8: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcInt(int64(v)) } return size, true case []int16: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcInt(int64(v)) } return size, true case []int32: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcInt(int64(v)) } return size, true case []int64: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcInt(v) } return size, true case []uint8: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcUint(uint64(v)) } return size, true case []uint16: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcUint(uint64(v)) } return size, true case []uint32: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcUint(uint64(v)) } return size, true case []uint64: - size, err := e.calcLength(len(sli)) - if err != nil { - return 0, false - } + size, _ := e.calcLength(len(sli)) for _, v := range sli { size += e.calcUint(v) }