Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# coverage
*.coverprofile
.DS_Store
.idea
.vscode
+21
View File
@@ -0,0 +1,21 @@
MIT License
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
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+120
View File
@@ -0,0 +1,120 @@
# MessagePack for Golang
[![Go Reference](https://pkg.go.dev/badge/github.com/shamaton/msgpack.svg)](https://pkg.go.dev/github.com/shamaton/msgpack)
![test](https://github.com/shamaton/msgpack/workflows/test/badge.svg)
[![Go Report Card](https://goreportcard.com/badge/github.com/shamaton/msgpack)](https://goreportcard.com/report/github.com/shamaton/msgpack)
[![codecov](https://codecov.io/gh/shamaton/msgpack/branch/master/graph/badge.svg?token=9PD2JUK5V3)](https://codecov.io/gh/shamaton/msgpack)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fshamaton%2Fmsgpack.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fshamaton%2Fmsgpack?ref=badge_shield)
## 📣 Announcement: `time.Time` decoding defaults to **UTC** in v3
Starting with **v3.0.0**, when decoding MessagePack **Timestamp** into Gos `time.Time`,
the default `Location` will be **UTC** (previously `Local`). The instant is unchanged.
To keep the old behavior, use `SetDecodedTimeAsLocal()`.
## Features
* Supported types : primitive / array / slice / struct / map / interface{} and time.Time
* Renaming fields via `msgpack:"field_name"`
* Omitting fields via `msgpack:"-"`
* Omitting empty fields via `msgpack:"field_name,omitempty"`
* Supports extend encoder / decoder [(example)](./msgpack_example_test.go)
* Can also Encoding / Decoding struct as array
## Installation
Current version is **msgpack/v2**.
```sh
go get -u github.com/shamaton/msgpack/v2
```
## Quick Start
```go
package main
import (
"github.com/shamaton/msgpack/v2"
"net/http"
)
type Struct struct {
String string
}
// simple
func main() {
v := Struct{String: "msgpack"}
d, err := msgpack.Marshal(v)
if err != nil {
panic(err)
}
r := Struct{}
if err = msgpack.Unmarshal(d, &r); err != nil {
panic(err)
}
}
// streaming
func handle(w http.ResponseWriter, r *http.Request) {
var body Struct
if err := msgpack.UnmarshalRead(r, &body); err != nil {
panic(err)
}
if err := msgpack.MarshalWrite(w, body); err != nil {
panic(err)
}
}
```
## 📣 Announcement: `time.Time` decoding defaults to **UTC** in v3
**TL;DR:** Starting with **v3.0.0**, when decoding MessagePack **Timestamp** into Gos `time.Time`, the default `Location` will be **UTC** (previously `Local`). The **instant** is unchanged—only the display/location changes. This avoids host-dependent differences and aligns with common distributed systems practice.
### What is changing?
* **Before (v2.x):** Decoded `time.Time` defaults to `Local`.
* **After (v3.0.0):** Decoded `time.Time` defaults to **UTC**.
MessagePacks Timestamp encodes an **instant** (epoch seconds + nanoseconds) and does **not** carry timezone info. Your datas point in time is the same; only `time.Time.Location()` differs.
### Why?
* Eliminate environment-dependent behavior (e.g., different hosts showing different local zones).
* Make “UTC by default” the safe, predictable baseline for logs, APIs, and distributed apps.
### Who is affected?
* Apps that **display local time** without explicitly converting from UTC.
* If your code already normalizes to UTC or explicitly sets a location, youre likely unaffected.
### Keep the old behavior (Local)
If you want the v2 behavior on v3:
```go
msgpack.SetDecodedTimeAsLocal()
```
Or convert after the fact:
```go
var t time.Time
_ = msgpack.Unmarshal(data, &t)
t = t.In(time.Local)
```
### Preview the new behavior on v2 (optional)
You can opt into UTC today on v2.x:
```go
msgpack.SetDecodedTimeAsUTC()
```
## Benchmark
This result made from [shamaton/msgpack_bench](https://github.com/shamaton/msgpack_bench)
![msgpack_bench](https://github.com/user-attachments/assets/ed5bc4c5-a149-4083-98b8-ee6820c00eae)
## License
This library is under the MIT License.
+4
View File
@@ -0,0 +1,4 @@
coverage:
status:
project: off
patch: off
+32
View File
@@ -0,0 +1,32 @@
package msgpack
import (
"io"
"github.com/shamaton/msgpack/v2/internal/decoding"
streamdecoding "github.com/shamaton/msgpack/v2/internal/stream/decoding"
)
// UnmarshalAsMap decodes data that is encoded as map format.
// This is the same thing that StructAsArray sets false.
func UnmarshalAsMap(data []byte, v interface{}) error {
return decoding.Decode(data, v, false)
}
// UnmarshalAsArray decodes data that is encoded as array format.
// This is the same thing that StructAsArray sets true.
func UnmarshalAsArray(data []byte, v interface{}) error {
return decoding.Decode(data, v, true)
}
// UnmarshalReadAsMap decodes from stream. stream data expects map format.
// This is the same thing that StructAsArray sets false.
func UnmarshalReadAsMap(r io.Reader, v interface{}) error {
return streamdecoding.Decode(r, v, false)
}
// UnmarshalReadAsArray decodes from stream. stream data expects array format.
// This is the same thing that StructAsArray sets true.
func UnmarshalReadAsArray(r io.Reader, v interface{}) error {
return streamdecoding.Decode(r, v, true)
}
+87
View File
@@ -0,0 +1,87 @@
package def
// IntSize : 32 or 64
const IntSize = 32 << (^uint(0) >> 63)
var IsIntSize32 = IntSize == 32
// message pack format
const (
PositiveFixIntMin = 0x00
PositiveFixIntMax = 0x7f
FixMap = 0x80
FixArray = 0x90
FixStr = 0xa0
Nil = 0xc0
False = 0xc2
True = 0xc3
Bin8 = 0xc4
Bin16 = 0xc5
Bin32 = 0xc6
Ext8 = 0xc7
Ext16 = 0xc8
Ext32 = 0xc9
Float32 = 0xca
Float64 = 0xcb
Uint8 = 0xcc
Uint16 = 0xcd
Uint32 = 0xce
Uint64 = 0xcf
Int8 = 0xd0
Int16 = 0xd1
Int32 = 0xd2
Int64 = 0xd3
Fixext1 = 0xd4
Fixext2 = 0xd5
Fixext4 = 0xd6
Fixext8 = 0xd7
Fixext16 = 0xd8
Str8 = 0xd9
Str16 = 0xda
Str32 = 0xdb
Array16 = 0xdc
Array32 = 0xdd
Map16 = 0xde
Map32 = 0xdf
NegativeFixintMin = -32 // 0xe0
NegativeFixintMax = -1 // 0xff
)
// byte
const (
Byte1 = 1 << iota
Byte2
Byte4
Byte8
Byte16
Byte32
)
// ext type
const (
TimeStamp = -1
)
// ext type complex
var complexTypeCode = int8(-128)
// ComplexTypeCode gets complexTypeCode
func ComplexTypeCode() int8 { return complexTypeCode }
// SetComplexTypeCode sets complexTypeCode
func SetComplexTypeCode(code int8) {
complexTypeCode = code
}
+31
View File
@@ -0,0 +1,31 @@
package def
import (
"errors"
"fmt"
)
var (
// base errors
ErrMsgpack = errors.New("")
// decoding errors
ErrNoData = fmt.Errorf("%wno data", ErrMsgpack)
ErrHasLeftOver = fmt.Errorf("%wdata has left over", ErrMsgpack)
ErrReceiverNotPointer = fmt.Errorf("%wreceiver not pointer", ErrMsgpack)
ErrNotMatchArrayElement = fmt.Errorf("%wnot match array element", ErrMsgpack)
ErrCanNotDecode = fmt.Errorf("%winvalid code", ErrMsgpack)
ErrCanNotSetSliceAsMapKey = fmt.Errorf("%wcan not set slice as map key", ErrMsgpack)
ErrCanNotSetMapAsMapKey = fmt.Errorf("%wcan not set map as map key", ErrMsgpack)
// encoding errors
ErrTooShortBytes = fmt.Errorf("%wtoo short bytes", ErrMsgpack)
ErrLackDataLengthToSlice = fmt.Errorf("%wdata length lacks to create slice", ErrMsgpack)
ErrLackDataLengthToMap = fmt.Errorf("%wdata length lacks to create map", ErrMsgpack)
ErrUnsupportedType = fmt.Errorf("%wunsupported type", ErrMsgpack)
ErrUnsupportedLength = fmt.Errorf("%wunsupported length", ErrMsgpack)
ErrNotMatchLastIndex = fmt.Errorf("%wnot match last index", ErrMsgpack)
)
+32
View File
@@ -0,0 +1,32 @@
package msgpack
import (
"io"
"github.com/shamaton/msgpack/v2/internal/encoding"
streamencoding "github.com/shamaton/msgpack/v2/internal/stream/encoding"
)
// MarshalAsMap encodes data as map format.
// This is the same thing that StructAsArray sets false.
func MarshalAsMap(v interface{}) ([]byte, error) {
return encoding.Encode(v, false)
}
// MarshalAsArray encodes data as array format.
// This is the same thing that StructAsArray sets true.
func MarshalAsArray(v interface{}) ([]byte, error) {
return encoding.Encode(v, true)
}
// MarshalWriteAsMap writes map format encoded data to writer.
// This is the same thing that StructAsArray sets false.
func MarshalWriteAsMap(w io.Writer, v interface{}) error {
return streamencoding.Encode(w, v, false)
}
// MarshalWriteAsArray writes array format encoded data to writer.
// This is the same thing that StructAsArray sets true.
func MarshalWriteAsArray(w io.Writer, v interface{}) error {
return streamencoding.Encode(w, v, true)
}
+8
View File
@@ -0,0 +1,8 @@
package msgpack
import (
"github.com/shamaton/msgpack/v2/def"
)
// Error is used in all msgpack error as the based error.
var Error = def.ErrMsgpack
+61
View File
@@ -0,0 +1,61 @@
package ext
import (
"reflect"
"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
}
+22
View File
@@ -0,0 +1,22 @@
package ext
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)
}
+152
View File
@@ -0,0 +1,152 @@
package ext
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)
(*d)[offset+2] = byte(value >> 8)
(*d)[offset+3] = byte(value)
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)
(*d)[offset+2] = byte(value >> 40)
(*d)[offset+3] = byte(value >> 32)
(*d)[offset+4] = byte(value >> 24)
(*d)[offset+5] = byte(value >> 16)
(*d)[offset+6] = byte(value >> 8)
(*d)[offset+7] = byte(value)
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)
(*d)[offset+2] = byte(value >> 8)
(*d)[offset+3] = byte(value)
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)
(*d)[offset+2] = byte(value >> 40)
(*d)[offset+3] = byte(value >> 32)
(*d)[offset+4] = byte(value >> 24)
(*d)[offset+5] = byte(value >> 16)
(*d)[offset+6] = byte(value >> 8)
(*d)[offset+7] = byte(value)
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)
(*d)[offset+2] = byte(value >> 8)
(*d)[offset+3] = byte(value)
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)
(*d)[offset+2] = byte(value >> 8)
(*d)[offset+3] = byte(value)
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]
}
return offset + len(bs)
}
+149
View File
@@ -0,0 +1,149 @@
package ext
import (
"io"
"reflect"
"github.com/shamaton/msgpack/v2/internal/common"
)
// 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 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 // 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),
byte(value),
)
}
// 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),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// 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),
byte(value>>48),
byte(value>>40),
byte(value>>32),
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// 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),
byte(value),
)
}
// 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),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// 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),
byte(value>>48),
byte(value>>40),
byte(value>>32),
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// 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),
byte(value),
)
}
// 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),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// 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),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
// WriteBytes writes a slice of bytes to the underlying writer.
func (w *StreamWriter) WriteBytes(bs []byte) error {
return w.buf.Write(w.w, bs...)
}
+63
View File
@@ -0,0 +1,63 @@
package common
import (
"io"
"sync"
)
type Buffer struct {
Data []byte
B1 []byte
B2 []byte
B4 []byte
B8 []byte
B16 []byte
offset int
}
func (b *Buffer) Write(w io.Writer, vs ...byte) error {
if len(b.Data) < b.offset+len(vs) {
_, err := w.Write(b.Data[:b.offset])
b.offset = 0
if err != nil {
return err
}
if len(b.Data) < len(vs) {
b.Data = append(b.Data, make([]byte, len(vs)-len(b.Data))...)
}
}
for i := range vs {
b.Data[b.offset+i] = vs[i]
}
b.offset += len(vs)
return nil
}
func (b *Buffer) Flush(w io.Writer) error {
_, err := w.Write(b.Data[:b.offset])
return err
}
var bufPool = sync.Pool{
New: func() interface{} {
data := make([]byte, 64)
return &Buffer{
Data: data,
B1: data[:1],
B2: data[:2],
B4: data[:4],
B8: data[:8],
B16: data[:16],
}
},
}
func GetBuffer() *Buffer {
buf := bufPool.Get().(*Buffer)
buf.offset = 0
return buf
}
func PutBuffer(buf *Buffer) {
bufPool.Put(buf)
}
+44
View File
@@ -0,0 +1,44 @@
package common
import (
"reflect"
"strings"
)
// Common is used encoding/decoding
type Common struct {
}
// CheckField returns flag whether should encode/decode or not and field name
func (c *Common) CheckField(field reflect.StructField) (public, omit bool, name string) {
// A to Z
if !c.isPublic(field.Name) {
return false, false, ""
}
tag := field.Tag.Get("msgpack")
if tag == "" {
return true, false, field.Name
}
parts := strings.Split(tag, ",")
// check ignore
if parts[0] == "-" {
return false, false, ""
}
// check omitempty
for _, part := range parts[1:] {
if part == "omitempty" {
omit = true
}
}
// check name
name = field.Name
if parts[0] != "" {
name = parts[0]
}
return true, omit, name
}
func (c *Common) isPublic(name string) bool {
return 0x41 <= name[0] && name[0] <= 0x5a
}
+64
View File
@@ -0,0 +1,64 @@
package decoding
import (
"encoding/binary"
"reflect"
"unsafe"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) isCodeBin(v byte) bool {
switch v {
case def.Bin8, def.Bin16, def.Bin32:
return true
}
return false
}
func (d *decoder) asBin(offset int, k reflect.Kind) ([]byte, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return emptyBytes, 0, err
}
switch code {
case def.Bin8:
l, offset, err := d.readSize1(offset)
if err != nil {
return emptyBytes, 0, err
}
v, offset, err := d.readSizeN(offset, int(uint8(l)))
if err != nil {
return emptyBytes, 0, err
}
return v, offset, nil
case def.Bin16:
bs, offset, err := d.readSize2(offset)
if err != nil {
return emptyBytes, 0, err
}
v, offset, err := d.readSizeN(offset, int(binary.BigEndian.Uint16(bs)))
if err != nil {
return emptyBytes, 0, err
}
return v, offset, nil
case def.Bin32:
bs, offset, err := d.readSize4(offset)
if err != nil {
return emptyBytes, 0, err
}
v, offset, err := d.readSizeN(offset, int(binary.BigEndian.Uint32(bs)))
if err != nil {
return emptyBytes, 0, err
}
return v, offset, nil
}
return emptyBytes, 0, d.errorTemplate(code, k)
}
func (d *decoder) asBinString(offset int, k reflect.Kind) (string, int, error) {
bs, offset, err := d.asBin(offset, k)
return *(*string)(unsafe.Pointer(&bs)), offset, err
}
+22
View File
@@ -0,0 +1,22 @@
package decoding
import (
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asBool(offset int, k reflect.Kind) (bool, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return false, 0, err
}
switch code {
case def.True:
return true, offset, nil
case def.False:
return false, offset, nil
}
return false, 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,114 @@
package decoding
import (
"encoding/binary"
"fmt"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asComplex64(offset int, k reflect.Kind) (complex64, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
switch code {
case def.Fixext8:
t, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), 0, fmt.Errorf("fixext8. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, offset, err := d.readSize4(offset)
if err != nil {
return complex(0, 0), 0, err
}
ib, offset, err := d.readSize4(offset)
if err != nil {
return complex(0, 0), 0, err
}
r := math.Float32frombits(binary.BigEndian.Uint32(rb))
i := math.Float32frombits(binary.BigEndian.Uint32(ib))
return complex(r, i), offset, nil
case def.Fixext16:
t, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), 0, fmt.Errorf("fixext16. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, offset, err := d.readSize8(offset)
if err != nil {
return complex(0, 0), 0, err
}
ib, offset, err := d.readSize8(offset)
if err != nil {
return complex(0, 0), 0, err
}
r := math.Float64frombits(binary.BigEndian.Uint64(rb))
i := math.Float64frombits(binary.BigEndian.Uint64(ib))
return complex64(complex(r, i)), offset, nil
}
return complex(0, 0), 0, d.errorTemplate(code, k)
}
func (d *decoder) asComplex128(offset int, k reflect.Kind) (complex128, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
switch code {
case def.Fixext8:
t, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), 0, fmt.Errorf("fixext8. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, offset, err := d.readSize4(offset)
if err != nil {
return complex(0, 0), 0, err
}
ib, offset, err := d.readSize4(offset)
if err != nil {
return complex(0, 0), 0, err
}
r := math.Float32frombits(binary.BigEndian.Uint32(rb))
i := math.Float32frombits(binary.BigEndian.Uint32(ib))
return complex128(complex(r, i)), offset, nil
case def.Fixext16:
t, offset, err := d.readSize1(offset)
if err != nil {
return complex(0, 0), 0, err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), 0, fmt.Errorf("fixext16. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, offset, err := d.readSize8(offset)
if err != nil {
return complex(0, 0), 0, err
}
ib, offset, err := d.readSize8(offset)
if err != nil {
return complex(0, 0), 0, err
}
r := math.Float64frombits(binary.BigEndian.Uint64(rb))
i := math.Float64frombits(binary.BigEndian.Uint64(ib))
return complex(r, i), offset, nil
}
return complex(0, 0), 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,343 @@
package decoding
import (
"fmt"
"reflect"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/internal/common"
)
type decoder struct {
data []byte
asArray bool
common.Common
}
// Decode analyzes the MessagePack-encoded data and stores
// the result into the pointer of v.
func Decode(data []byte, v interface{}, asArray bool) error {
d := decoder{data: data, asArray: asArray}
if d.data == nil || len(d.data) < 1 {
return def.ErrNoData
}
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
return fmt.Errorf("%w. v.(type): %T", def.ErrReceiverNotPointer, v)
}
rv = rv.Elem()
last, err := d.decode(rv, 0)
if err != nil {
return err
}
if len(data) != last {
return fmt.Errorf("%w size=%d, last=%d", def.ErrHasLeftOver, len(data), last)
}
return err
}
func (d *decoder) decode(rv reflect.Value, offset int) (int, error) {
k := rv.Kind()
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, err
}
rv.SetInt(v)
offset = o
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, err
}
rv.SetUint(v)
offset = o
case reflect.Float32:
v, o, err := d.asFloat32(offset, k)
if err != nil {
return 0, err
}
rv.SetFloat(float64(v))
offset = o
case reflect.Float64:
v, o, err := d.asFloat64(offset, k)
if err != nil {
return 0, err
}
rv.SetFloat(v)
offset = o
case reflect.String:
// byte slice
if d.isCodeBin(d.data[offset]) {
v, offset, err := d.asBinString(offset, k)
if err != nil {
return 0, err
}
rv.SetString(v)
return offset, nil
}
v, o, err := d.asString(offset, k)
if err != nil {
return 0, err
}
rv.SetString(v)
offset = o
case reflect.Bool:
v, o, err := d.asBool(offset, k)
if err != nil {
return 0, err
}
rv.SetBool(v)
offset = o
case reflect.Slice:
// nil
if d.isCodeNil(d.data[offset]) {
offset++
return offset, nil
}
// byte slice
if d.isCodeBin(d.data[offset]) {
bs, offset, err := d.asBin(offset, k)
if err != nil {
return 0, err
}
rv.SetBytes(bs)
return offset, nil
}
// string to bytes
if d.isCodeString(d.data[offset]) {
l, offset, err := d.stringByteLength(offset, k)
if err != nil {
return 0, err
}
bs, offset, err := d.asStringByteByLength(offset, l, k)
if err != nil {
return 0, err
}
rv.SetBytes(bs)
return offset, nil
}
// get slice length
l, o, err := d.sliceLength(offset, k)
if err != nil {
return 0, err
}
if err = d.hasRequiredLeastSliceSize(o, l); err != nil {
return 0, err
}
// check fixed type
fixedOffset, found, err := d.asFixedSlice(rv, o, l)
if err != nil {
return 0, err
}
if found {
return fixedOffset, nil
}
// create slice dynamically
tmpSlice := reflect.MakeSlice(rv.Type(), l, l)
for i := 0; i < l; i++ {
v := tmpSlice.Index(i)
if v.Kind() == reflect.Struct {
o, err = d.setStruct(v, o, k)
} else {
o, err = d.decode(v, o)
}
if err != nil {
return 0, err
}
}
rv.Set(tmpSlice)
offset = o
case reflect.Complex64:
v, o, err := d.asComplex64(offset, k)
if err != nil {
return 0, err
}
rv.SetComplex(complex128(v))
offset = o
case reflect.Complex128:
v, o, err := d.asComplex128(offset, k)
if err != nil {
return 0, err
}
rv.SetComplex(v)
offset = o
case reflect.Array:
// nil
if d.isCodeNil(d.data[offset]) {
offset++
return offset, nil
}
// byte slice
if d.isCodeBin(d.data[offset]) {
bs, offset, err := d.asBin(offset, k)
if err != nil {
return 0, err
}
if len(bs) > rv.Len() {
return 0, fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), len(bs), def.ErrNotMatchArrayElement)
}
for i, b := range bs {
rv.Index(i).SetUint(uint64(b))
}
return offset, nil
}
// string to bytes
if d.isCodeString(d.data[offset]) {
l, offset, err := d.stringByteLength(offset, k)
if err != nil {
return 0, err
}
if l > rv.Len() {
return 0, fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), l, def.ErrNotMatchArrayElement)
}
bs, offset, err := d.asStringByteByLength(offset, l, k)
if err != nil {
return 0, err
}
for i, b := range bs {
rv.Index(i).SetUint(uint64(b))
}
return offset, nil
}
// get slice length
l, o, err := d.sliceLength(offset, k)
if err != nil {
return 0, err
}
if l > rv.Len() {
return 0, fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), l, def.ErrNotMatchArrayElement)
}
if err = d.hasRequiredLeastSliceSize(o, l); err != nil {
return 0, err
}
// create array dynamically
for i := 0; i < l; i++ {
o, err = d.decode(rv.Index(i), o)
if err != nil {
return 0, err
}
}
offset = o
case reflect.Map:
// nil
if d.isCodeNil(d.data[offset]) {
offset++
return offset, nil
}
// get map length
l, o, err := d.mapLength(offset, k)
if err != nil {
return 0, err
}
if err = d.hasRequiredLeastMapSize(o, l); err != nil {
return 0, err
}
// check fixed type
fixedOffset, found, err := d.asFixedMap(rv, o, l)
if err != nil {
return 0, err
}
if found {
return fixedOffset, nil
}
// create dynamically
key := rv.Type().Key()
value := rv.Type().Elem()
if rv.IsNil() {
rv.Set(reflect.MakeMapWithSize(rv.Type(), l))
}
for i := 0; i < l; i++ {
k := reflect.New(key).Elem()
v := reflect.New(value).Elem()
o, err = d.decode(k, o)
if err != nil {
return 0, err
}
o, err = d.decode(v, o)
if err != nil {
return 0, err
}
rv.SetMapIndex(k, v)
}
offset = o
case reflect.Struct:
o, err := d.setStruct(rv, offset, k)
if err != nil {
return 0, err
}
offset = o
case reflect.Ptr:
// nil
if d.isCodeNil(d.data[offset]) {
offset++
return offset, nil
}
if rv.Elem().Kind() == reflect.Invalid {
n := reflect.New(rv.Type().Elem())
rv.Set(n)
}
o, err := d.decode(rv.Elem(), offset)
if err != nil {
return 0, err
}
offset = o
case reflect.Interface:
if rv.Elem().Kind() == reflect.Ptr {
o, err := d.decode(rv.Elem(), offset)
if err != nil {
return 0, err
}
offset = o
} else {
v, o, err := d.asInterface(offset, k)
if err != nil {
return 0, err
}
if v != nil {
rv.Set(reflect.ValueOf(v))
}
offset = o
}
default:
return 0, fmt.Errorf("%v is %w type", rv.Kind(), def.ErrUnsupportedType)
}
return offset, nil
}
func (d *decoder) errorTemplate(code byte, k reflect.Kind) error {
return fmt.Errorf("%w %x decoding as %v", def.ErrCanNotDecode, code, k)
}
+102
View File
@@ -0,0 +1,102 @@
package decoding
import (
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/time"
)
var extCoderMap = map[int8]ext.Decoder{time.Decoder.Code(): time.Decoder}
var extCoders = []ext.Decoder{time.Decoder}
// AddExtDecoder adds decoders for extension types.
func AddExtDecoder(f ext.Decoder) {
// ignore time
if f.Code() == time.Decoder.Code() {
return
}
_, ok := extCoderMap[f.Code()]
if !ok {
extCoderMap[f.Code()] = f
updateExtCoders()
}
}
// RemoveExtDecoder removes decoders for extension types.
func RemoveExtDecoder(f ext.Decoder) {
// ignore time
if f.Code() == time.Decoder.Code() {
return
}
_, ok := extCoderMap[f.Code()]
if ok {
delete(extCoderMap, f.Code())
updateExtCoders()
}
}
func updateExtCoders() {
extCoders = make([]ext.Decoder, len(extCoderMap))
i := 0
for k := range extCoderMap {
extCoders[i] = extCoderMap[k]
i++
}
}
/*
var zero = time.Unix(0,0)
func (d *decoder) isDateTime(offset int) bool {
code, offset := d.readSize1(offset)
if code == def.Fixext4 {
t, _ := d.readSize1(offset)
return int8(t) == def.TimeStamp
} else if code == def.Fixext8 {
t, _ := d.readSize1(offset)
return int8(t) == def.TimeStamp
} else if code == def.Ext8 {
l, offset := d.readSize1(offset)
t, _ := d.readSize1(offset)
return l == 12 && int8(t) == def.TimeStamp
}
return false
}
func (d *decoder) asDateTime(offset int, k reflect.Kind) (time.Time, int, error) {
code, offset := d.readSize1(offset)
switch code {
case def.Fixext4:
_, offset = d.readSize1(offset)
bs, offset := d.readSize4(offset)
return time.Unix(int64(binary.BigEndian.Uint32(bs)), 0), offset, nil
case def.Fixext8:
_, offset = d.readSize1(offset)
bs, offset := d.readSize8(offset)
data64 := binary.BigEndian.Uint64(bs)
nano := int64(data64 >> 34)
if nano > 999999999 {
return zero, 0, fmt.Errorf("In timestamp 64 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
return time.Unix(int64(data64&0x00000003ffffffff), nano), offset, nil
case def.Ext8:
_, offset = d.readSize1(offset)
_, offset = d.readSize1(offset)
nanobs, offset := d.readSize4(offset)
secbs, offset := d.readSize8(offset)
nano := binary.BigEndian.Uint32(nanobs)
if nano > 999999999 {
return zero, 0, fmt.Errorf("In timestamp 96 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
sec := binary.BigEndian.Uint64(secbs)
return time.Unix(int64(sec), int64(nano)), offset, nil
}
return zero, 0, d.errorTemplate(code, k)
}
*/
@@ -0,0 +1,92 @@
package decoding
import (
"encoding/binary"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asFloat32(offset int, k reflect.Kind) (float32, int, error) {
code, _, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case code == def.Float32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := math.Float32frombits(binary.BigEndian.Uint32(bs))
return v, offset, nil
case d.isPositiveFixNum(code), code == def.Uint8, code == def.Uint16, code == def.Uint32, code == def.Uint64:
v, offset, err := d.asUint(offset, k)
if err != nil {
return 0, 0, err
}
return float32(v), offset, nil
case d.isNegativeFixNum(code), code == def.Int8, code == def.Int16, code == def.Int32, code == def.Int64:
v, offset, err := d.asInt(offset, k)
if err != nil {
return 0, 0, err
}
return float32(v), offset, nil
case code == def.Nil:
offset++
return 0, offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
func (d *decoder) asFloat64(offset int, k reflect.Kind) (float64, int, error) {
code, _, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case code == def.Float64:
offset++
bs, offset, err := d.readSize8(offset)
if err != nil {
return 0, 0, err
}
v := math.Float64frombits(binary.BigEndian.Uint64(bs))
return v, offset, nil
case code == def.Float32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := math.Float32frombits(binary.BigEndian.Uint32(bs))
return float64(v), offset, nil
case d.isPositiveFixNum(code), code == def.Uint8, code == def.Uint16, code == def.Uint32, code == def.Uint64:
v, offset, err := d.asUint(offset, k)
if err != nil {
return 0, 0, err
}
return float64(v), offset, nil
case d.isNegativeFixNum(code), code == def.Int8, code == def.Int16, code == def.Int32, code == def.Int64:
v, offset, err := d.asInt(offset, k)
if err != nil {
return 0, 0, err
}
return float64(v), offset, nil
case code == def.Nil:
offset++
return 0, offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
+128
View File
@@ -0,0 +1,128 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) isPositiveFixNum(v byte) bool {
return def.PositiveFixIntMin <= v && v <= def.PositiveFixIntMax
}
func (d *decoder) isNegativeFixNum(v byte) bool {
return def.NegativeFixintMin <= int8(v) && int8(v) <= def.NegativeFixintMax
}
func (d *decoder) asInt(offset int, k reflect.Kind) (int64, int, error) {
code, _, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case d.isPositiveFixNum(code):
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return int64(b), offset, nil
case d.isNegativeFixNum(code):
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return int64(int8(b)), offset, nil
case code == def.Uint8:
offset++
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return int64(uint8(b)), offset, nil
case code == def.Int8:
offset++
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return int64(int8(b)), offset, nil
case code == def.Uint16:
offset++
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
v := binary.BigEndian.Uint16(bs)
return int64(v), offset, nil
case code == def.Int16:
offset++
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
v := int16(binary.BigEndian.Uint16(bs))
return int64(v), offset, nil
case code == def.Uint32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := binary.BigEndian.Uint32(bs)
return int64(v), offset, nil
case code == def.Int32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := int32(binary.BigEndian.Uint32(bs))
return int64(v), offset, nil
case code == def.Uint64:
offset++
bs, offset, err := d.readSize8(offset)
if err != nil {
return 0, 0, err
}
return int64(binary.BigEndian.Uint64(bs)), offset, nil
case code == def.Int64:
offset++
bs, offset, err := d.readSize8(offset)
if err != nil {
return 0, 0, err
}
return int64(binary.BigEndian.Uint64(bs)), offset, nil
case code == def.Float32:
v, offset, err := d.asFloat32(offset, k)
if err != nil {
return 0, 0, err
}
return int64(v), offset, nil
case code == def.Float64:
v, offset, err := d.asFloat64(offset, k)
if err != nil {
return 0, 0, err
}
return int64(v), offset, nil
case code == def.Nil:
offset++
return 0, offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,190 @@
package decoding
import (
"fmt"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asInterface(offset int, k reflect.Kind) (interface{}, int, error) {
code, _, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case code == def.Nil:
offset++
return nil, offset, nil
case code == def.True, code == def.False:
v, offset, err := d.asBool(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, nil
case d.isPositiveFixNum(code), code == def.Uint8:
v, offset, err := d.asUint(offset, k)
if err != nil {
return nil, 0, err
}
return uint8(v), offset, err
case code == def.Uint16:
v, offset, err := d.asUint(offset, k)
if err != nil {
return nil, 0, err
}
return uint16(v), offset, err
case code == def.Uint32:
v, offset, err := d.asUint(offset, k)
if err != nil {
return nil, 0, err
}
return uint32(v), offset, err
case code == def.Uint64:
v, offset, err := d.asUint(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case d.isNegativeFixNum(code), code == def.Int8:
v, offset, err := d.asInt(offset, k)
if err != nil {
return nil, 0, err
}
return int8(v), offset, err
case code == def.Int16:
v, offset, err := d.asInt(offset, k)
if err != nil {
return nil, 0, err
}
return int16(v), offset, err
case code == def.Int32:
v, offset, err := d.asInt(offset, k)
if err != nil {
return nil, 0, err
}
return int32(v), offset, err
case code == def.Int64:
v, offset, err := d.asInt(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case code == def.Float32:
v, offset, err := d.asFloat32(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case code == def.Float64:
v, offset, err := d.asFloat64(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case d.isFixString(code), code == def.Str8, code == def.Str16, code == def.Str32:
v, offset, err := d.asString(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case code == def.Bin8, code == def.Bin16, code == def.Bin32:
v, offset, err := d.asBin(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, err
case d.isFixSlice(code), code == def.Array16, code == def.Array32:
l, o, err := d.sliceLength(offset, k)
if err != nil {
return nil, 0, err
}
if err = d.hasRequiredLeastSliceSize(o, l); err != nil {
return nil, 0, err
}
v := make([]interface{}, l)
for i := 0; i < l; i++ {
vv, o2, err := d.asInterface(o, k)
if err != nil {
return nil, 0, err
}
v[i] = vv
o = o2
}
offset = o
return v, offset, nil
case d.isFixMap(code), code == def.Map16, code == def.Map32:
l, o, err := d.mapLength(offset, k)
if err != nil {
return nil, 0, err
}
if err = d.hasRequiredLeastMapSize(o, l); err != nil {
return nil, 0, err
}
v := make(map[interface{}]interface{}, l)
for i := 0; i < l; i++ {
if err := d.canSetAsMapKey(o); err != nil {
return nil, 0, err
}
key, o2, err := d.asInterface(o, k)
if err != nil {
return nil, 0, err
}
value, o2, err := d.asInterface(o2, k)
if err != nil {
return nil, 0, err
}
v[key] = value
o = o2
}
offset = o
return v, offset, nil
}
/* use ext
if d.isDateTime(offset) {
v, offset, err := d.asDateTime(offset, k)
if err != nil {
return nil, 0, err
}
return v, offset, nil
}
*/
// ext
for i := range extCoders {
if extCoders[i].IsType(offset, &d.data) {
v, offset, err := extCoders[i].AsValue(offset, k, &d.data)
if err != nil {
return nil, 0, err
}
return v, offset, nil
}
}
return nil, 0, d.errorTemplate(code, k)
}
func (d *decoder) canSetAsMapKey(index int) error {
code, _, err := d.readSize1(index)
if err != nil {
return err
}
switch {
case d.isFixSlice(code), code == def.Array16, code == def.Array32:
return fmt.Errorf("%w. code: %x", def.ErrCanNotSetSliceAsMapKey, code)
case d.isFixMap(code), code == def.Map16, code == def.Map32:
return fmt.Errorf("%w. code: %x", def.ErrCanNotSetMapAsMapKey, code)
}
return nil
}
+749
View File
@@ -0,0 +1,749 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var (
typeMapStringInt = reflect.TypeOf(map[string]int{})
typeMapStringInt8 = reflect.TypeOf(map[string]int8{})
typeMapStringInt16 = reflect.TypeOf(map[string]int16{})
typeMapStringInt32 = reflect.TypeOf(map[string]int32{})
typeMapStringInt64 = reflect.TypeOf(map[string]int64{})
typeMapStringUint = reflect.TypeOf(map[string]uint{})
typeMapStringUint8 = reflect.TypeOf(map[string]uint8{})
typeMapStringUint16 = reflect.TypeOf(map[string]uint16{})
typeMapStringUint32 = reflect.TypeOf(map[string]uint32{})
typeMapStringUint64 = reflect.TypeOf(map[string]uint64{})
typeMapStringFloat32 = reflect.TypeOf(map[string]float32{})
typeMapStringFloat64 = reflect.TypeOf(map[string]float64{})
typeMapStringBool = reflect.TypeOf(map[string]bool{})
typeMapStringString = reflect.TypeOf(map[string]string{})
typeMapIntString = reflect.TypeOf(map[int]string{})
typeMapInt8String = reflect.TypeOf(map[int8]string{})
typeMapInt16String = reflect.TypeOf(map[int16]string{})
typeMapInt32String = reflect.TypeOf(map[int32]string{})
typeMapInt64String = reflect.TypeOf(map[int64]string{})
typeMapIntBool = reflect.TypeOf(map[int]bool{})
typeMapInt8Bool = reflect.TypeOf(map[int8]bool{})
typeMapInt16Bool = reflect.TypeOf(map[int16]bool{})
typeMapInt32Bool = reflect.TypeOf(map[int32]bool{})
typeMapInt64Bool = reflect.TypeOf(map[int64]bool{})
typeMapUintString = reflect.TypeOf(map[uint]string{})
typeMapUint8String = reflect.TypeOf(map[uint8]string{})
typeMapUint16String = reflect.TypeOf(map[uint16]string{})
typeMapUint32String = reflect.TypeOf(map[uint32]string{})
typeMapUint64String = reflect.TypeOf(map[uint64]string{})
typeMapUintBool = reflect.TypeOf(map[uint]bool{})
typeMapUint8Bool = reflect.TypeOf(map[uint8]bool{})
typeMapUint16Bool = reflect.TypeOf(map[uint16]bool{})
typeMapUint32Bool = reflect.TypeOf(map[uint32]bool{})
typeMapUint64Bool = reflect.TypeOf(map[uint64]bool{})
typeMapFloat32String = reflect.TypeOf(map[float32]string{})
typeMapFloat64String = reflect.TypeOf(map[float64]string{})
typeMapFloat32Bool = reflect.TypeOf(map[float32]bool{})
typeMapFloat64Bool = reflect.TypeOf(map[float64]bool{})
)
func (d *decoder) isFixMap(v byte) bool {
return def.FixMap <= v && v <= def.FixMap+0x0f
}
func (d *decoder) mapLength(offset int, k reflect.Kind) (int, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case d.isFixMap(code):
return int(code - def.FixMap), offset, nil
case code == def.Map16:
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint16(bs)), offset, nil
case code == def.Map32:
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint32(bs)), offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
func (d *decoder) hasRequiredLeastMapSize(offset, length int) error {
// minimum check (byte length)
if len(d.data[offset:]) < length*2 {
return def.ErrLackDataLengthToMap
}
return nil
}
func (d *decoder) asFixedMap(rv reflect.Value, offset int, l int) (int, bool, error) {
t := rv.Type()
keyKind := t.Key().Kind()
valueKind := t.Elem().Kind()
switch t {
case typeMapStringInt:
m := make(map[string]int, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asInt(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = int(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringUint:
m := make(map[string]uint, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asUint(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = uint(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringFloat32:
m := make(map[string]float32, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asFloat32(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringFloat64:
m := make(map[string]float64, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asFloat64(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringBool:
m := make(map[string]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringString:
m := make(map[string]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringInt8:
m := make(map[string]int8, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asInt(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = int8(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringInt16:
m := make(map[string]int16, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asInt(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = int16(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringInt32:
m := make(map[string]int32, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asInt(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = int32(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringInt64:
m := make(map[string]int64, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asInt(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringUint8:
m := make(map[string]uint8, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asUint(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = uint8(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringUint16:
m := make(map[string]uint16, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asUint(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = uint16(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringUint32:
m := make(map[string]uint32, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asUint(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = uint32(v)
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapStringUint64:
m := make(map[string]uint64, l)
for i := 0; i < l; i++ {
k, o, err := d.asString(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asUint(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapIntString:
m := make(map[int]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[int(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt8String:
m := make(map[int8]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[int8(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt16String:
m := make(map[int16]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[int16(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt32String:
m := make(map[int32]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[int32(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt64String:
m := make(map[int64]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapIntBool:
m := make(map[int]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[int(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt8Bool:
m := make(map[int8]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[int8(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt16Bool:
m := make(map[int16]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[int16(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt32Bool:
m := make(map[int32]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[int32(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapInt64Bool:
m := make(map[int64]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asInt(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUintString:
m := make(map[uint]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint8String:
m := make(map[uint8]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint8(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint16String:
m := make(map[uint16]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint16(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint32String:
m := make(map[uint32]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint32(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint64String:
m := make(map[uint64]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUintBool:
m := make(map[uint]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint8Bool:
m := make(map[uint8]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint8(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint16Bool:
m := make(map[uint16]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint16(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint32Bool:
m := make(map[uint32]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[uint32(k)] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapUint64Bool:
m := make(map[uint64]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asUint(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapFloat32String:
m := make(map[float32]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asFloat32(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapFloat64String:
m := make(map[float64]string, l)
for i := 0; i < l; i++ {
k, o, err := d.asFloat64(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asString(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapFloat32Bool:
m := make(map[float32]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asFloat32(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
case typeMapFloat64Bool:
m := make(map[float64]bool, l)
for i := 0; i < l; i++ {
k, o, err := d.asFloat64(offset, keyKind)
if err != nil {
return 0, false, err
}
v, o, err := d.asBool(o, valueKind)
if err != nil {
return 0, false, err
}
m[k] = v
offset = o
}
rv.Set(reflect.ValueOf(m))
return offset, true, nil
}
return offset, false, nil
}
@@ -0,0 +1,7 @@
package decoding
import "github.com/shamaton/msgpack/v2/def"
func (d *decoder) isCodeNil(v byte) bool {
return def.Nil == v
}
+32
View File
@@ -0,0 +1,32 @@
package decoding
import (
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) readSize1(index int) (byte, int, error) {
rb := def.Byte1
if len(d.data) < index+rb {
return 0, 0, def.ErrTooShortBytes
}
return d.data[index], index + rb, nil
}
func (d *decoder) readSize2(index int) ([]byte, int, error) {
return d.readSizeN(index, def.Byte2)
}
func (d *decoder) readSize4(index int) ([]byte, int, error) {
return d.readSizeN(index, def.Byte4)
}
func (d *decoder) readSize8(index int) ([]byte, int, error) {
return d.readSizeN(index, def.Byte8)
}
func (d *decoder) readSizeN(index, n int) ([]byte, int, error) {
if len(d.data) < index+n {
return emptyBytes, 0, def.ErrTooShortBytes
}
return d.data[index : index+n], index + n, nil
}
+257
View File
@@ -0,0 +1,257 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var (
typeIntSlice = reflect.TypeOf([]int{})
typeInt8Slice = reflect.TypeOf([]int8{})
typeInt16Slice = reflect.TypeOf([]int16{})
typeInt32Slice = reflect.TypeOf([]int32{})
typeInt64Slice = reflect.TypeOf([]int64{})
typeUintSlice = reflect.TypeOf([]uint{})
typeUint8Slice = reflect.TypeOf([]uint8{})
typeUint16Slice = reflect.TypeOf([]uint16{})
typeUint32Slice = reflect.TypeOf([]uint32{})
typeUint64Slice = reflect.TypeOf([]uint64{})
typeFloat32Slice = reflect.TypeOf([]float32{})
typeFloat64Slice = reflect.TypeOf([]float64{})
typeStringSlice = reflect.TypeOf([]string{})
typeBoolSlice = reflect.TypeOf([]bool{})
)
func (d *decoder) isFixSlice(v byte) bool {
return def.FixArray <= v && v <= def.FixArray+0x0f
}
func (d *decoder) sliceLength(offset int, k reflect.Kind) (int, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case d.isFixSlice(code):
return int(code - def.FixArray), offset, nil
case code == def.Array16:
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint16(bs)), offset, nil
case code == def.Array32:
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint32(bs)), offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
func (d *decoder) hasRequiredLeastSliceSize(offset, length int) error {
// minimum check (byte length)
if len(d.data[offset:]) < length {
return def.ErrLackDataLengthToSlice
}
return nil
}
func (d *decoder) asFixedSlice(rv reflect.Value, offset int, l int) (int, bool, error) {
t := rv.Type()
k := t.Elem().Kind()
switch t {
case typeIntSlice:
sli := make([]int, l)
for i := range sli {
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = int(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeUintSlice:
sli := make([]uint, l)
for i := range sli {
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = uint(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeStringSlice:
sli := make([]string, l)
for i := range sli {
v, o, err := d.asString(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeBoolSlice:
sli := make([]bool, l)
for i := range sli {
v, o, err := d.asBool(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeFloat32Slice:
sli := make([]float32, l)
for i := range sli {
v, o, err := d.asFloat32(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeFloat64Slice:
sli := make([]float64, l)
for i := range sli {
v, o, err := d.asFloat64(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeInt8Slice:
sli := make([]int8, l)
for i := range sli {
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = int8(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeInt16Slice:
sli := make([]int16, l)
for i := range sli {
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = int16(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeInt32Slice:
sli := make([]int32, l)
for i := range sli {
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = int32(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeInt64Slice:
sli := make([]int64, l)
for i := range sli {
v, o, err := d.asInt(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeUint8Slice:
sli := make([]uint8, l)
for i := range sli {
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = uint8(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeUint16Slice:
sli := make([]uint16, l)
for i := range sli {
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = uint16(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeUint32Slice:
sli := make([]uint32, l)
for i := range sli {
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = uint32(v)
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
case typeUint64Slice:
sli := make([]uint64, l)
for i := range sli {
v, o, err := d.asUint(offset, k)
if err != nil {
return 0, false, err
}
sli[i] = v
offset = o
}
rv.Set(reflect.ValueOf(sli))
return offset, true, nil
}
return offset, false, nil
}
@@ -0,0 +1,77 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var emptyString = ""
var emptyBytes = []byte{}
func (d *decoder) isCodeString(code byte) bool {
return d.isFixString(code) || code == def.Str8 || code == def.Str16 || code == def.Str32
}
func (d *decoder) isFixString(v byte) bool {
return def.FixStr <= v && v <= def.FixStr+0x1f
}
func (d *decoder) stringByteLength(offset int, k reflect.Kind) (int, int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
if def.FixStr <= code && code <= def.FixStr+0x1f {
l := int(code - def.FixStr)
return l, offset, nil
} else if code == def.Str8 {
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return int(b), offset, nil
} else if code == def.Str16 {
b, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint16(b)), offset, nil
} else if code == def.Str32 {
b, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
return int(binary.BigEndian.Uint32(b)), offset, nil
} else if code == def.Nil {
return 0, offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
func (d *decoder) asString(offset int, k reflect.Kind) (string, int, error) {
bs, offset, err := d.asStringByte(offset, k)
if err != nil {
return emptyString, 0, err
}
return string(bs), offset, nil
}
func (d *decoder) asStringByte(offset int, k reflect.Kind) ([]byte, int, error) {
l, offset, err := d.stringByteLength(offset, k)
if err != nil {
return emptyBytes, 0, err
}
return d.asStringByteByLength(offset, l, k)
}
func (d *decoder) asStringByteByLength(offset int, l int, k reflect.Kind) ([]byte, int, error) {
if l < 1 {
return emptyBytes, offset, nil
}
return d.readSizeN(offset, l)
}
@@ -0,0 +1,315 @@
package decoding
import (
"encoding/binary"
"reflect"
"sync"
"github.com/shamaton/msgpack/v2/def"
)
type structCacheTypeMap struct {
keys [][]byte
indexes []int
}
type structCacheTypeArray struct {
m []int
}
// struct cache map
var mapSCTM = sync.Map{}
var mapSCTA = sync.Map{}
func (d *decoder) setStruct(rv reflect.Value, offset int, k reflect.Kind) (int, error) {
/*
if d.isDateTime(offset) {
dt, offset, err := d.asDateTime(offset, k)
if err != nil {
return 0, err
}
rv.Set(reflect.ValueOf(dt))
return offset, nil
}
*/
for i := range extCoders {
if extCoders[i].IsType(offset, &d.data) {
v, offset, err := extCoders[i].AsValue(offset, k, &d.data)
if err != nil {
return 0, err
}
// Validate that the receptacle is of the right value type.
if rv.Type() == reflect.TypeOf(v) {
rv.Set(reflect.ValueOf(v))
return offset, nil
}
}
}
if d.asArray {
return d.setStructFromArray(rv, offset, k)
}
return d.setStructFromMap(rv, offset, k)
}
func (d *decoder) setStructFromArray(rv reflect.Value, offset int, k reflect.Kind) (int, error) {
// get length
l, o, err := d.sliceLength(offset, k)
if err != nil {
return 0, err
}
if err = d.hasRequiredLeastSliceSize(o, l); err != nil {
return 0, err
}
// find or create reference
var scta *structCacheTypeArray
cache, findCache := mapSCTA.Load(rv.Type())
if !findCache {
scta = &structCacheTypeArray{}
for i := 0; i < rv.NumField(); i++ {
if ok, _, _ := d.CheckField(rv.Type().Field(i)); ok {
scta.m = append(scta.m, i)
}
}
mapSCTA.Store(rv.Type(), scta)
} else {
scta = cache.(*structCacheTypeArray)
}
// set value
for i := 0; i < l; i++ {
if i < len(scta.m) {
o, err = d.decode(rv.Field(scta.m[i]), o)
if err != nil {
return 0, err
}
} else {
o, err = d.jumpOffset(o)
if err != nil {
return 0, err
}
}
}
return o, nil
}
func (d *decoder) setStructFromMap(rv reflect.Value, offset int, k reflect.Kind) (int, error) {
// get length
l, o, err := d.mapLength(offset, k)
if err != nil {
return 0, err
}
if err = d.hasRequiredLeastMapSize(o, l); err != nil {
return 0, err
}
var sctm *structCacheTypeMap
cache, cacheFind := mapSCTM.Load(rv.Type())
if !cacheFind {
sctm = &structCacheTypeMap{}
for i := 0; i < rv.NumField(); i++ {
if ok, _, name := d.CheckField(rv.Type().Field(i)); ok {
sctm.keys = append(sctm.keys, []byte(name))
sctm.indexes = append(sctm.indexes, i)
}
}
mapSCTM.Store(rv.Type(), sctm)
} else {
sctm = cache.(*structCacheTypeMap)
}
for i := 0; i < l; i++ {
dataKey, o2, err := d.asStringByte(o, k)
if err != nil {
return 0, err
}
fieldIndex := -1
for keyIndex, keyBytes := range sctm.keys {
if len(keyBytes) != len(dataKey) {
continue
}
fieldIndex = sctm.indexes[keyIndex]
for dataIndex := range dataKey {
if dataKey[dataIndex] != keyBytes[dataIndex] {
fieldIndex = -1
break
}
}
if fieldIndex >= 0 {
break
}
}
if fieldIndex >= 0 {
o2, err = d.decode(rv.Field(fieldIndex), o2)
if err != nil {
return 0, err
}
} else {
o2, err = d.jumpOffset(o2)
if err != nil {
return 0, err
}
}
o = o2
}
return o, nil
}
func (d *decoder) jumpOffset(offset int) (int, error) {
code, offset, err := d.readSize1(offset)
if err != nil {
return 0, err
}
switch {
case code == def.True, code == def.False, code == def.Nil:
// do nothing
case d.isPositiveFixNum(code) || d.isNegativeFixNum(code):
// do nothing
case code == def.Uint8, code == def.Int8:
offset += def.Byte1
case code == def.Uint16, code == def.Int16:
offset += def.Byte2
case code == def.Uint32, code == def.Int32, code == def.Float32:
offset += def.Byte4
case code == def.Uint64, code == def.Int64, code == def.Float64:
offset += def.Byte8
case d.isFixString(code):
offset += int(code - def.FixStr)
case code == def.Str8, code == def.Bin8:
b, o, err := d.readSize1(offset)
if err != nil {
return 0, err
}
o += int(b)
offset = o
case code == def.Str16, code == def.Bin16:
bs, o, err := d.readSize2(offset)
if err != nil {
return 0, err
}
o += int(binary.BigEndian.Uint16(bs))
offset = o
case code == def.Str32, code == def.Bin32:
bs, o, err := d.readSize4(offset)
if err != nil {
return 0, err
}
o += int(binary.BigEndian.Uint32(bs))
offset = o
case d.isFixSlice(code):
l := int(code - def.FixArray)
for i := 0; i < l; i++ {
offset, err = d.jumpOffset(offset)
if err != nil {
return 0, err
}
}
case code == def.Array16:
bs, o, err := d.readSize2(offset)
if err != nil {
return 0, err
}
l := int(binary.BigEndian.Uint16(bs))
for i := 0; i < l; i++ {
o, err = d.jumpOffset(o)
if err != nil {
return 0, err
}
}
offset = o
case code == def.Array32:
bs, o, err := d.readSize4(offset)
if err != nil {
return 0, err
}
l := int(binary.BigEndian.Uint32(bs))
for i := 0; i < l; i++ {
o, err = d.jumpOffset(o)
if err != nil {
return 0, err
}
}
offset = o
case d.isFixMap(code):
l := int(code - def.FixMap)
for i := 0; i < l*2; i++ {
offset, err = d.jumpOffset(offset)
if err != nil {
return 0, err
}
}
case code == def.Map16:
bs, o, err := d.readSize2(offset)
if err != nil {
return 0, err
}
l := int(binary.BigEndian.Uint16(bs))
for i := 0; i < l*2; i++ {
o, err = d.jumpOffset(o)
if err != nil {
return 0, err
}
}
offset = o
case code == def.Map32:
bs, o, err := d.readSize4(offset)
if err != nil {
return 0, err
}
l := int(binary.BigEndian.Uint32(bs))
for i := 0; i < l*2; i++ {
o, err = d.jumpOffset(o)
if err != nil {
return 0, err
}
}
offset = o
case code == def.Fixext1:
offset += def.Byte1 + def.Byte1
case code == def.Fixext2:
offset += def.Byte1 + def.Byte2
case code == def.Fixext4:
offset += def.Byte1 + def.Byte4
case code == def.Fixext8:
offset += def.Byte1 + def.Byte8
case code == def.Fixext16:
offset += def.Byte1 + def.Byte16
case code == def.Ext8:
b, o, err := d.readSize1(offset)
if err != nil {
return 0, err
}
o += def.Byte1 + int(b)
offset = o
case code == def.Ext16:
bs, o, err := d.readSize2(offset)
if err != nil {
return 0, err
}
o += def.Byte1 + int(binary.BigEndian.Uint16(bs))
offset = o
case code == def.Ext32:
bs, o, err := d.readSize4(offset)
if err != nil {
return 0, err
}
o += def.Byte1 + int(binary.BigEndian.Uint32(bs))
offset = o
}
return offset, nil
}
+106
View File
@@ -0,0 +1,106 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asUint(offset int, k reflect.Kind) (uint64, int, error) {
code, _, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
switch {
case d.isPositiveFixNum(code):
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return uint64(b), offset, nil
case d.isNegativeFixNum(code):
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return uint64(int8(b)), offset, nil
case code == def.Uint8:
offset++
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return uint64(uint8(b)), offset, nil
case code == def.Int8:
offset++
b, offset, err := d.readSize1(offset)
if err != nil {
return 0, 0, err
}
return uint64(int8(b)), offset, nil
case code == def.Uint16:
offset++
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
v := binary.BigEndian.Uint16(bs)
return uint64(v), offset, nil
case code == def.Int16:
offset++
bs, offset, err := d.readSize2(offset)
if err != nil {
return 0, 0, err
}
v := int16(binary.BigEndian.Uint16(bs))
return uint64(v), offset, nil
case code == def.Uint32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := binary.BigEndian.Uint32(bs)
return uint64(v), offset, nil
case code == def.Int32:
offset++
bs, offset, err := d.readSize4(offset)
if err != nil {
return 0, 0, err
}
v := int32(binary.BigEndian.Uint32(bs))
return uint64(v), offset, nil
case code == def.Uint64:
offset++
bs, offset, err := d.readSize8(offset)
if err != nil {
return 0, 0, err
}
return binary.BigEndian.Uint64(bs), offset, nil
case code == def.Int64:
offset++
bs, offset, err := d.readSize8(offset)
if err != nil {
return 0, 0, err
}
return binary.BigEndian.Uint64(bs), offset, nil
case code == def.Nil:
offset++
return 0, offset, nil
}
return 0, 0, d.errorTemplate(code, k)
}
+16
View File
@@ -0,0 +1,16 @@
package encoding
import "github.com/shamaton/msgpack/v2/def"
//func (e *encoder) calcBool() int {
// return 0
//}
func (e *encoder) writeBool(v bool, offset int) int {
if v {
offset = e.setByte1Int(def.True, offset)
} else {
offset = e.setByte1Int(def.False, offset)
}
return offset
}
+41
View File
@@ -0,0 +1,41 @@
package encoding
import (
"fmt"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var typeByte = reflect.TypeOf(byte(0))
func (e *encoder) isByteSlice(rv reflect.Value) bool {
return rv.Type().Elem() == typeByte
}
func (e *encoder) calcByteSlice(l int) (int, error) {
if l <= math.MaxUint8 {
return def.Byte1 + def.Byte1 + l, nil
} else if l <= math.MaxUint16 {
return def.Byte1 + def.Byte2 + l, nil
} else if uint(l) <= math.MaxUint32 {
return def.Byte1 + def.Byte4 + l, nil
}
// not supported error
return 0, fmt.Errorf("%w slice length : %d", def.ErrUnsupportedType, l)
}
func (e *encoder) writeByteSliceLength(l int, offset int) int {
if l <= math.MaxUint8 {
offset = e.setByte1Int(def.Bin8, offset)
offset = e.setByte1Int(l, offset)
} else if l <= math.MaxUint16 {
offset = e.setByte1Int(def.Bin16, offset)
offset = e.setByte2Int(l, offset)
} else if uint(l) <= math.MaxUint32 {
offset = e.setByte1Int(def.Bin32, offset)
offset = e.setByte4Int(l, offset)
}
return offset
}
@@ -0,0 +1,31 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) calcComplex64() int {
return def.Byte1 + def.Byte1 + def.Byte8
}
func (e *encoder) calcComplex128() int {
return def.Byte1 + def.Byte1 + def.Byte16
}
func (e *encoder) writeComplex64(v complex64, offset int) int {
offset = e.setByte1Int(def.Fixext8, offset)
offset = e.setByte1Int(int(def.ComplexTypeCode()), offset)
offset = e.setByte4Uint64(uint64(math.Float32bits(real(v))), offset)
offset = e.setByte4Uint64(uint64(math.Float32bits(imag(v))), offset)
return offset
}
func (e *encoder) writeComplex128(v complex128, offset int) int {
offset = e.setByte1Int(def.Fixext16, offset)
offset = e.setByte1Int(int(def.ComplexTypeCode()), offset)
offset = e.setByte8Uint64(math.Float64bits(real(v)), offset)
offset = e.setByte8Uint64(math.Float64bits(imag(v)), offset)
return offset
}
@@ -0,0 +1,382 @@
package encoding
import (
"fmt"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/internal/common"
)
type encoder struct {
d []byte
asArray bool
common.Common
mk map[uintptr][]reflect.Value
mv map[uintptr][]reflect.Value
}
// Encode returns the MessagePack-encoded byte array of v.
func Encode(v interface{}, asArray bool) (b []byte, err error) {
e := encoder{asArray: asArray}
/*
defer func() {
e := recover()
if e != nil {
b = nil
err = fmt.Errorf("unexpected error!! \n%s", stackTrace())
}
}()
*/
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
}
size, err := e.calcSize(rv)
if err != nil {
return nil, err
}
e.d = make([]byte, size)
last := e.create(rv, 0)
if size != last {
return nil, fmt.Errorf("%w size=%d, lastIdx=%d", def.ErrNotMatchLastIndex, size, last)
}
return e.d, err
}
//func stackTrace() string {
// msg := ""
// for depth := 0; ; depth++ {
// _, file, line, ok := runtime.Caller(depth)
// if !ok {
// break
// }
// msg += fmt.Sprintln(depth, ": ", file, ":", line)
// }
// return msg
//}
func (e *encoder) calcSize(rv reflect.Value) (int, error) {
switch rv.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
v := rv.Uint()
return e.calcUint(v), nil
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
v := rv.Int()
return e.calcInt(int64(v)), nil
case reflect.Float32:
return e.calcFloat32(0), nil
case reflect.Float64:
return e.calcFloat64(0), nil
case reflect.String:
return e.calcString(rv.String()), nil
case reflect.Bool:
return def.Byte1, nil
case reflect.Complex64:
return e.calcComplex64(), nil
case reflect.Complex128:
return e.calcComplex128(), nil
case reflect.Slice:
if rv.IsNil() {
return def.Byte1, nil
}
// bin format
if e.isByteSlice(rv) {
size, err := e.calcByteSlice(rv.Len())
if err != nil {
return 0, err
}
return size, nil
}
if size, find := e.calcFixedSlice(rv); find {
return size, nil
}
// func
elem := rv.Type().Elem()
var f structCalcFunc
if elem.Kind() == reflect.Struct {
f = e.getStructCalc(elem)
} 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++ {
s, err := f(rv.Index(i))
if err != nil {
return 0, err
}
size += s
}
return size, nil
case reflect.Array:
// bin format
if e.isByteSlice(rv) {
size, err := e.calcByteSlice(rv.Len())
if err != nil {
return 0, err
}
return size, nil
}
// func
elem := rv.Type().Elem()
var f structCalcFunc
if elem.Kind() == reflect.Struct {
f = e.getStructCalc(elem)
} 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++ {
s, err := f(rv.Index(i))
if err != nil {
return 0, err
}
size += s
}
return size, nil
case reflect.Map:
if rv.IsNil() {
return def.Byte1, nil
}
if size, find := e.calcFixedMap(rv); find {
return size, nil
}
if e.mk == nil {
e.mk = map[uintptr][]reflect.Value{}
e.mv = map[uintptr][]reflect.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 {
keySize, err := e.calcSize(k)
if err != nil {
return 0, err
}
value := rv.MapIndex(k)
valueSize, err := e.calcSize(value)
if err != nil {
return 0, err
}
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
}
return size, nil
case reflect.Ptr:
if rv.IsNil() {
return def.Byte1, nil
}
size, err := e.calcSize(rv.Elem())
if err != nil {
return 0, err
}
return size, nil
case reflect.Interface:
size, err := e.calcSize(rv.Elem())
if err != nil {
return 0, err
}
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)
}
}
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 {
switch rv.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
v := rv.Uint()
offset = e.writeUint(v, offset)
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
v := rv.Int()
offset = e.writeInt(v, offset)
case reflect.Float32:
offset = e.writeFloat32(rv.Float(), offset)
case reflect.Float64:
offset = e.writeFloat64(rv.Float(), offset)
case reflect.Bool:
offset = e.writeBool(rv.Bool(), offset)
case reflect.String:
offset = e.writeString(rv.String(), offset)
case reflect.Complex64:
offset = e.writeComplex64(complex64(rv.Complex()), offset)
case reflect.Complex128:
offset = e.writeComplex128(rv.Complex(), offset)
case reflect.Slice:
if rv.IsNil() {
return e.writeNil(offset)
}
// bin format
if e.isByteSlice(rv) {
offset = e.writeByteSliceLength(rv.Len(), offset)
offset = e.setBytes(rv.Bytes(), offset)
return offset
}
if offset, find := e.writeFixedSlice(rv, offset); find {
return offset
}
// func
elem := rv.Type().Elem()
var f structWriteFunc
if elem.Kind() == reflect.Struct {
f = e.getStructWriter(elem)
} else {
f = e.create
}
// objects
l := rv.Len()
offset = e.writeSliceLength(l, offset)
for i := 0; i < l; i++ {
offset = f(rv.Index(i), offset)
}
case reflect.Array:
l := rv.Len()
// bin format
if e.isByteSlice(rv) {
offset = e.writeByteSliceLength(l, offset)
// objects
for i := 0; i < l; i++ {
offset = e.setByte1Uint64(rv.Index(i).Uint(), offset)
}
return offset
}
// format
offset = e.writeSliceLength(l, offset)
// func
elem := rv.Type().Elem()
var f structWriteFunc
if elem.Kind() == reflect.Struct {
f = e.getStructWriter(elem)
} else {
f = e.create
}
// objects
for i := 0; i < l; i++ {
offset = f(rv.Index(i), offset)
}
case reflect.Map:
if rv.IsNil() {
return e.writeNil(offset)
}
l := rv.Len()
offset = e.writeMapLength(l, offset)
if offset, find := e.writeFixedMap(rv, offset); find {
return offset
}
// key-value
p := rv.Pointer()
for i := range e.mk[p] {
offset = e.create(e.mk[p][i], offset)
offset = e.create(e.mv[p][i], offset)
}
case reflect.Struct:
offset = e.writeStruct(rv, offset)
case reflect.Ptr:
if rv.IsNil() {
return e.writeNil(offset)
}
offset = e.create(rv.Elem(), offset)
case reflect.Interface:
offset = e.create(rv.Elem(), offset)
case reflect.Invalid:
return e.writeNil(offset)
}
return offset
}
+97
View File
@@ -0,0 +1,97 @@
package encoding
import (
"reflect"
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/time"
)
var extCoderMap = map[reflect.Type]ext.Encoder{time.Encoder.Type(): time.Encoder}
var extCoders = []ext.Encoder{time.Encoder}
// AddExtEncoder adds encoders for extension types.
func AddExtEncoder(f ext.Encoder) {
// ignore time
if f.Type() == time.Encoder.Type() {
return
}
_, ok := extCoderMap[f.Type()]
if !ok {
extCoderMap[f.Type()] = f
updateExtCoders()
}
}
// RemoveExtEncoder removes encoders for extension types.
func RemoveExtEncoder(f ext.Encoder) {
// ignore time
if f.Type() == time.Encoder.Type() {
return
}
_, ok := extCoderMap[f.Type()]
if ok {
delete(extCoderMap, f.Type())
updateExtCoders()
}
}
func updateExtCoders() {
extCoders = make([]ext.Encoder, len(extCoderMap))
i := 0
for k := range extCoderMap {
extCoders[i] = extCoderMap[k]
i++
}
}
/*
func (e *encoder) isDateTime(value reflect.Value) (bool, time.Time) {
i := value.Interface()
switch t := i.(type) {
case time.Time:
return true, t
}
return false, now
}
func (e *encoder) calcTime(t time.Time) int {
secs := uint64(t.Unix())
if secs>>34 == 0 {
data := uint64(t.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
return def.Byte1 + def.Byte4
}
return def.Byte1 + def.Byte8
}
return def.Byte1 + def.Byte1 + def.Byte4 + def.Byte8
}
func (e *encoder) writeTime(t time.Time, offset int) int {
secs := uint64(t.Unix())
if secs>>34 == 0 {
data := uint64(t.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
offset = e.setByte1Int(def.Fixext4, offset)
offset = e.setByte1Int(def.TimeStamp, offset)
offset = e.setByte4Uint64(data, offset)
return offset
}
offset = e.setByte1Int(def.Fixext8, offset)
offset = e.setByte1Int(def.TimeStamp, offset)
offset = e.setByte8Uint64(data, offset)
return offset
}
offset = e.setByte1Int(def.Ext8, offset)
offset = e.setByte1Int(12, offset)
offset = e.setByte1Int(def.TimeStamp, offset)
offset = e.setByte4Int(t.Nanosecond(), offset)
offset = e.setByte8Uint64(secs, offset)
return offset
}
*/
@@ -0,0 +1,27 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) calcFloat32(_ float64) int {
return def.Byte1 + def.Byte4
}
func (e *encoder) calcFloat64(_ float64) int {
return def.Byte1 + def.Byte8
}
func (e *encoder) writeFloat32(v float64, offset int) int {
offset = e.setByte1Int(def.Float32, offset)
offset = e.setByte4Uint64(uint64(math.Float32bits(float32(v))), offset)
return offset
}
func (e *encoder) writeFloat64(v float64, offset int) int {
offset = e.setByte1Int(def.Float64, offset)
offset = e.setByte8Uint64(math.Float64bits(v), offset)
return offset
}
+48
View File
@@ -0,0 +1,48 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) isNegativeFixInt64(v int64) bool {
return def.NegativeFixintMin <= v && v <= def.NegativeFixintMax
}
func (e *encoder) calcInt(v int64) int {
if v >= 0 {
return e.calcUint(uint64(v))
} else if e.isNegativeFixInt64(v) {
// format code only
return def.Byte1
} else if v >= math.MinInt8 {
return def.Byte1 + def.Byte1
} else if v >= math.MinInt16 {
return def.Byte1 + def.Byte2
} else if v >= math.MinInt32 {
return def.Byte1 + def.Byte4
}
return def.Byte1 + def.Byte8
}
func (e *encoder) writeInt(v int64, offset int) int {
if v >= 0 {
offset = e.writeUint(uint64(v), offset)
} else if e.isNegativeFixInt64(v) {
offset = e.setByte1Int64(v, offset)
} else if v >= math.MinInt8 {
offset = e.setByte1Int(def.Int8, offset)
offset = e.setByte1Int64(v, offset)
} else if v >= math.MinInt16 {
offset = e.setByte1Int(def.Int16, offset)
offset = e.setByte2Int64(v, offset)
} else if v >= math.MinInt32 {
offset = e.setByte1Int(def.Int32, offset)
offset = e.setByte4Int64(v, offset)
} else {
offset = e.setByte1Int(def.Int64, offset)
offset = e.setByte8Int64(v, offset)
}
return offset
}
+559
View File
@@ -0,0 +1,559 @@
package encoding
import (
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
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, _ := e.calcLength(len(m))
for k, v := range m {
size += e.calcString(k)
size += e.calcInt(int64(v))
}
return size, true
case map[string]uint:
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]string:
size, _ := e.calcLength(len(m))
for k, v := range m {
size += e.calcString(k)
size += e.calcString(v)
}
return size, true
case map[string]float32:
size, _ := e.calcLength(len(m))
for k := range m {
size += e.calcString(k)
size += e.calcFloat32(0)
}
return size, true
case map[string]float64:
size, _ := e.calcLength(len(m))
for k := range m {
size += e.calcString(k)
size += e.calcFloat64(0)
}
return size, true
case map[string]bool:
size, _ := e.calcLength(len(m))
for k := range m {
size += e.calcString(k)
size += def.Byte1 /*+ e.calcBool()*/
}
return size, true
case map[string]int8:
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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := e.calcLength(len(m))
for k, v := range m {
size += e.calcString(k)
size += e.calcUint(v)
}
return size, true
case map[int]string:
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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcInt(int64(k))
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
case map[uint]string:
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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcUint(uint64(k))
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
case map[float32]string:
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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcFloat32(float64(k))
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
case map[float64]string:
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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcFloat64(k)
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
case map[int8]string:
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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcInt(k)
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
case map[uint8]string:
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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := 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, _ := e.calcLength(len(m))
for k := range m {
size += e.calcUint(k)
size += def.Byte1 /* + e.calcBool()*/
}
return size, true
}
return 0, false
}
func (e *encoder) writeMapLength(l int, offset int) int {
// format
if l <= 0x0f {
offset = e.setByte1Int(def.FixMap+l, offset)
} else if l <= math.MaxUint16 {
offset = e.setByte1Int(def.Map16, offset)
offset = e.setByte2Int(l, offset)
} else if uint(l) <= math.MaxUint32 {
offset = e.setByte1Int(def.Map32, offset)
offset = e.setByte4Int(l, offset)
}
return offset
}
func (e *encoder) writeFixedMap(rv reflect.Value, offset int) (int, bool) {
switch m := rv.Interface().(type) {
case map[string]int:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeInt(int64(v), offset)
}
return offset, true
case map[string]uint:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeUint(uint64(v), offset)
}
return offset, true
case map[string]float32:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeFloat32(float64(v), offset)
}
return offset, true
case map[string]float64:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeFloat64(v, offset)
}
return offset, true
case map[string]bool:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[string]string:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[string]int8:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeInt(int64(v), offset)
}
return offset, true
case map[string]int16:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeInt(int64(v), offset)
}
return offset, true
case map[string]int32:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeInt(int64(v), offset)
}
return offset, true
case map[string]int64:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeInt(int64(v), offset)
}
return offset, true
case map[string]uint8:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeUint(uint64(v), offset)
}
return offset, true
case map[string]uint16:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeUint(uint64(v), offset)
}
return offset, true
case map[string]uint32:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeUint(uint64(v), offset)
}
return offset, true
case map[string]uint64:
for k, v := range m {
offset = e.writeString(k, offset)
offset = e.writeUint(uint64(v), offset)
}
return offset, true
case map[int]string:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[int]bool:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[uint]string:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[uint]bool:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[float32]string:
for k, v := range m {
offset = e.writeFloat32(float64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[float32]bool:
for k, v := range m {
offset = e.writeFloat32(float64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[float64]string:
for k, v := range m {
offset = e.writeFloat64(k, offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[float64]bool:
for k, v := range m {
offset = e.writeFloat64(k, offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[int8]string:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[int8]bool:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[int16]string:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[int16]bool:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[int32]string:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[int32]bool:
for k, v := range m {
offset = e.writeInt(int64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[int64]string:
for k, v := range m {
offset = e.writeInt(k, offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[int64]bool:
for k, v := range m {
offset = e.writeInt(k, offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[uint8]string:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[uint8]bool:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[uint16]string:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[uint16]bool:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[uint32]string:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[uint32]bool:
for k, v := range m {
offset = e.writeUint(uint64(k), offset)
offset = e.writeBool(v, offset)
}
return offset, true
case map[uint64]string:
for k, v := range m {
offset = e.writeUint(k, offset)
offset = e.writeString(v, offset)
}
return offset, true
case map[uint64]bool:
for k, v := range m {
offset = e.writeUint(k, offset)
offset = e.writeBool(v, offset)
}
return offset, true
}
return offset, false
}
@@ -0,0 +1,8 @@
package encoding
import "github.com/shamaton/msgpack/v2/def"
func (e *encoder) writeNil(offset int) int {
offset = e.setByte1Int(def.Nil, offset)
return offset
}
+89
View File
@@ -0,0 +1,89 @@
package encoding
func (e *encoder) setByte1Int64(value int64, offset int) int {
e.d[offset] = byte(value)
return offset + 1
}
func (e *encoder) setByte2Int64(value int64, offset int) int {
e.d[offset+0] = byte(value >> 8)
e.d[offset+1] = byte(value)
return offset + 2
}
func (e *encoder) setByte4Int64(value int64, offset int) int {
e.d[offset+0] = byte(value >> 24)
e.d[offset+1] = byte(value >> 16)
e.d[offset+2] = byte(value >> 8)
e.d[offset+3] = byte(value)
return offset + 4
}
func (e *encoder) setByte8Int64(value int64, offset int) int {
e.d[offset] = byte(value >> 56)
e.d[offset+1] = byte(value >> 48)
e.d[offset+2] = byte(value >> 40)
e.d[offset+3] = byte(value >> 32)
e.d[offset+4] = byte(value >> 24)
e.d[offset+5] = byte(value >> 16)
e.d[offset+6] = byte(value >> 8)
e.d[offset+7] = byte(value)
return offset + 8
}
func (e *encoder) setByte1Uint64(value uint64, offset int) int {
e.d[offset] = byte(value)
return offset + 1
}
func (e *encoder) setByte2Uint64(value uint64, offset int) int {
e.d[offset] = byte(value >> 8)
e.d[offset+1] = byte(value)
return offset + 2
}
func (e *encoder) setByte4Uint64(value uint64, offset int) int {
e.d[offset] = byte(value >> 24)
e.d[offset+1] = byte(value >> 16)
e.d[offset+2] = byte(value >> 8)
e.d[offset+3] = byte(value)
return offset + 4
}
func (e *encoder) setByte8Uint64(value uint64, offset int) int {
e.d[offset] = byte(value >> 56)
e.d[offset+1] = byte(value >> 48)
e.d[offset+2] = byte(value >> 40)
e.d[offset+3] = byte(value >> 32)
e.d[offset+4] = byte(value >> 24)
e.d[offset+5] = byte(value >> 16)
e.d[offset+6] = byte(value >> 8)
e.d[offset+7] = byte(value)
return offset + 8
}
func (e *encoder) setByte1Int(code, offset int) int {
e.d[offset] = byte(code)
return offset + 1
}
func (e *encoder) setByte2Int(value int, offset int) int {
e.d[offset] = byte(value >> 8)
e.d[offset+1] = byte(value)
return offset + 2
}
func (e *encoder) setByte4Int(value int, offset int) int {
e.d[offset] = byte(value >> 24)
e.d[offset+1] = byte(value >> 16)
e.d[offset+2] = byte(value >> 8)
e.d[offset+3] = byte(value)
return offset + 4
}
func (e *encoder) setBytes(bs []byte, offset int) int {
for i := range bs {
e.d[offset+i] = bs[i]
}
return offset + len(bs)
}
+232
View File
@@ -0,0 +1,232 @@
package encoding
import (
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
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, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcInt(int64(v))
}
return size, true
case []uint:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcUint(uint64(v))
}
return size, true
case []string:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcString(v)
}
return size, true
case []float32:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcFloat32(float64(v))
}
return size, true
case []float64:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcFloat64(v)
}
return size, true
case []bool:
size, _ := e.calcLength(len(sli))
size += def.Byte1 * len(sli)
return size, true
case []int8:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcInt(int64(v))
}
return size, true
case []int16:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcInt(int64(v))
}
return size, true
case []int32:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcInt(int64(v))
}
return size, true
case []int64:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcInt(v)
}
return size, true
case []uint8:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcUint(uint64(v))
}
return size, true
case []uint16:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcUint(uint64(v))
}
return size, true
case []uint32:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcUint(uint64(v))
}
return size, true
case []uint64:
size, _ := e.calcLength(len(sli))
for _, v := range sli {
size += e.calcUint(v)
}
return size, true
}
return 0, false
}
func (e *encoder) writeSliceLength(l int, offset int) int {
// format size
if l <= 0x0f {
offset = e.setByte1Int(def.FixArray+l, offset)
} else if l <= math.MaxUint16 {
offset = e.setByte1Int(def.Array16, offset)
offset = e.setByte2Int(l, offset)
} else if uint(l) <= math.MaxUint32 {
offset = e.setByte1Int(def.Array32, offset)
offset = e.setByte4Int(l, offset)
}
return offset
}
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)
}
return offset, true
}
return offset, false
}
@@ -0,0 +1,43 @@
package encoding
import (
"math"
"unsafe"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) calcString(v string) int {
// NOTE : unsafe
strBytes := *(*[]byte)(unsafe.Pointer(&v))
l := len(strBytes)
if l < 32 {
return def.Byte1 + l
} else if l <= math.MaxUint8 {
return def.Byte1 + def.Byte1 + l
} else if l <= math.MaxUint16 {
return def.Byte1 + def.Byte2 + l
}
return def.Byte1 + def.Byte4 + l
// NOTE : length over uint32
}
func (e *encoder) writeString(str string, offset int) int {
// NOTE : unsafe
strBytes := *(*[]byte)(unsafe.Pointer(&str))
l := len(strBytes)
if l < 32 {
offset = e.setByte1Int(def.FixStr+l, offset)
} else if l <= math.MaxUint8 {
offset = e.setByte1Int(def.Str8, offset)
offset = e.setByte1Int(l, offset)
} else if l <= math.MaxUint16 {
offset = e.setByte1Int(def.Str16, offset)
offset = e.setByte2Int(l, offset)
} else {
offset = e.setByte1Int(def.Str32, offset)
offset = e.setByte4Int(l, offset)
}
offset += copy(e.d[offset:], str)
return offset
}
@@ -0,0 +1,275 @@
package encoding
import (
"math"
"reflect"
"sync"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/internal/common"
)
type structCache struct {
indexes []int
names []string
omits []bool
noOmit bool
common.Common
}
var cachemap = sync.Map{}
type structCalcFunc func(rv reflect.Value) (int, error)
type structWriteFunc func(rv reflect.Value, offset int) int
func (e *encoder) getStructCalc(typ reflect.Type) structCalcFunc {
for j := range extCoders {
if extCoders[j].Type() == typ {
return extCoders[j].CalcByteSize
}
}
if e.asArray {
return e.calcStructArray
}
return e.calcStructMap
}
func (e *encoder) calcStruct(rv reflect.Value) (int, error) {
//if isTime, tm := e.isDateTime(rv); isTime {
// size := e.calcTime(tm)
// return size, nil
//}
for i := range extCoders {
if extCoders[i].Type() == rv.Type() {
return extCoders[i].CalcByteSize(rv)
}
}
if e.asArray {
return e.calcStructArray(rv)
}
return e.calcStructMap(rv)
}
func (e *encoder) calcStructArray(rv reflect.Value) (int, error) {
ret := 0
t := rv.Type()
cache, find := cachemap.Load(t)
var c *structCache
if !find {
num := rv.NumField()
c = &structCache{
indexes: make([]int, 0, num),
names: make([]string, 0, num),
omits: make([]bool, 0, num),
}
omitCount := 0
for i := 0; i < num; i++ {
field := t.Field(i)
if ok, omit, name := e.CheckField(field); ok {
size, err := e.calcSize(rv.Field(i))
if err != nil {
return 0, err
}
ret += size
c.indexes = append(c.indexes, i)
c.names = append(c.names, name)
c.omits = append(c.omits, omit)
if omit {
omitCount++
}
}
}
c.noOmit = omitCount == 0
cachemap.Store(t, c)
} else {
c = cache.(*structCache)
for i := 0; i < len(c.indexes); i++ {
size, err := e.calcSize(rv.Field(c.indexes[i]))
if err != nil {
return 0, err
}
ret += size
}
}
// format size
size, err := e.calcLength(len(c.indexes))
if err != nil {
return 0, err
}
ret += size
return ret, nil
}
func (e *encoder) calcStructMap(rv reflect.Value) (int, error) {
ret := 0
t := rv.Type()
cache, find := cachemap.Load(t)
var c *structCache
var l int
if !find {
num := rv.NumField()
c = &structCache{
indexes: make([]int, 0, num),
names: make([]string, 0, num),
omits: make([]bool, 0, num),
}
omitCount := 0
for i := 0; i < num; i++ {
if ok, omit, name := e.CheckField(rv.Type().Field(i)); ok {
size, err := e.calcSizeWithOmitEmpty(rv.Field(i), name, omit)
if err != nil {
return 0, err
}
ret += size
c.indexes = append(c.indexes, i)
c.names = append(c.names, name)
c.omits = append(c.omits, omit)
if omit {
omitCount++
}
if size > 0 {
l++
}
}
}
c.noOmit = omitCount == 0
cachemap.Store(t, c)
} else {
c = cache.(*structCache)
for i := 0; i < len(c.indexes); i++ {
size, err := e.calcSizeWithOmitEmpty(rv.Field(c.indexes[i]), c.names[i], c.omits[i])
if err != nil {
return 0, err
}
ret += size
if size > 0 {
l++
}
}
}
// format size
size, err := e.calcLength(len(c.indexes))
if err != nil {
return 0, err
}
ret += size
return ret, nil
}
func (e *encoder) calcSizeWithOmitEmpty(rv reflect.Value, name string, omit bool) (int, error) {
keySize := 0
valueSize := 0
if !omit || !rv.IsZero() {
keySize = e.calcString(name)
vSize, err := e.calcSize(rv)
if err != nil {
return 0, err
}
valueSize = vSize
}
return keySize + valueSize, nil
}
func (e *encoder) getStructWriter(typ reflect.Type) structWriteFunc {
for i := range extCoders {
if extCoders[i].Type() == typ {
return func(rv reflect.Value, offset int) int {
return extCoders[i].WriteToBytes(rv, offset, &e.d)
}
}
}
if e.asArray {
return e.writeStructArray
}
return e.writeStructMap
}
func (e *encoder) writeStruct(rv reflect.Value, offset int) int {
/*
if isTime, tm := e.isDateTime(rv); isTime {
return e.writeTime(tm, offset)
}
*/
for i := range extCoders {
if extCoders[i].Type() == rv.Type() {
return extCoders[i].WriteToBytes(rv, offset, &e.d)
}
}
if e.asArray {
return e.writeStructArray(rv, offset)
}
return e.writeStructMap(rv, offset)
}
func (e *encoder) writeStructArray(rv reflect.Value, offset int) int {
cache, _ := cachemap.Load(rv.Type())
c := cache.(*structCache)
// write format
num := len(c.indexes)
if num <= 0x0f {
offset = e.setByte1Int(def.FixArray+num, offset)
} else if num <= math.MaxUint16 {
offset = e.setByte1Int(def.Array16, offset)
offset = e.setByte2Int(num, offset)
} else if uint(num) <= math.MaxUint32 {
offset = e.setByte1Int(def.Array32, offset)
offset = e.setByte4Int(num, offset)
}
for i := 0; i < num; i++ {
offset = e.create(rv.Field(c.indexes[i]), offset)
}
return offset
}
func (e *encoder) writeStructMap(rv reflect.Value, offset int) int {
cache, _ := cachemap.Load(rv.Type())
c := cache.(*structCache)
// format size
num := len(c.indexes)
l := 0
if c.noOmit {
l = num
} else {
for i := 0; i < num; i++ {
irv := rv.Field(c.indexes[i])
if !c.omits[i] || !irv.IsZero() {
l++
}
}
}
if l <= 0x0f {
offset = e.setByte1Int(def.FixMap+l, offset)
} else if l <= math.MaxUint16 {
offset = e.setByte1Int(def.Map16, offset)
offset = e.setByte2Int(l, offset)
} else if uint(l) <= math.MaxUint32 {
offset = e.setByte1Int(def.Map32, offset)
offset = e.setByte4Int(l, offset)
}
for i := 0; i < num; i++ {
irv := rv.Field(c.indexes[i])
if !c.omits[i] || !irv.IsZero() {
offset = e.writeString(c.names[i], offset)
offset = e.create(irv, offset)
}
}
return offset
}
+40
View File
@@ -0,0 +1,40 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) calcUint(v uint64) int {
if v <= math.MaxInt8 {
// format code only
return def.Byte1
} else if v <= math.MaxUint8 {
return def.Byte1 + def.Byte1
} else if v <= math.MaxUint16 {
return def.Byte1 + def.Byte2
} else if v <= math.MaxUint32 {
return def.Byte1 + def.Byte4
}
return def.Byte1 + def.Byte8
}
func (e *encoder) writeUint(v uint64, offset int) int {
if v <= math.MaxInt8 {
offset = e.setByte1Uint64(v, offset)
} else if v <= math.MaxUint8 {
offset = e.setByte1Int(def.Uint8, offset)
offset = e.setByte1Uint64(v, offset)
} else if v <= math.MaxUint16 {
offset = e.setByte1Int(def.Uint16, offset)
offset = e.setByte2Uint64(v, offset)
} else if v <= math.MaxUint32 {
offset = e.setByte1Int(def.Uint32, offset)
offset = e.setByte4Uint64(v, offset)
} else {
offset = e.setByte1Int(def.Uint64, offset)
offset = e.setByte8Uint64(v, offset)
}
return offset
}
@@ -0,0 +1,63 @@
package decoding
import (
"encoding/binary"
"reflect"
"unsafe"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) isCodeBin(v byte) bool {
switch v {
case def.Bin8, def.Bin16, def.Bin32:
return true
}
return false
}
func (d *decoder) asBinWithCode(code byte, k reflect.Kind) ([]byte, error) {
switch code {
case def.Bin8:
l, err := d.readSize1()
if err != nil {
return emptyBytes, err
}
// avoid common buffer reference
return d.copySizeN(int(l))
case def.Bin16:
bs, err := d.readSize2()
if err != nil {
return emptyBytes, err
}
// avoid common buffer reference
return d.copySizeN(int(binary.BigEndian.Uint16(bs)))
case def.Bin32:
bs, err := d.readSize4()
if err != nil {
return emptyBytes, err
}
// avoid common buffer reference
return d.copySizeN(int(binary.BigEndian.Uint32(bs)))
}
return emptyBytes, d.errorTemplate(code, k)
}
func (d *decoder) asBinStringWithCode(code byte, k reflect.Kind) (string, error) {
bs, err := d.asBinWithCode(code, k)
return *(*string)(unsafe.Pointer(&bs)), err
}
func (d *decoder) copySizeN(n int) ([]byte, error) {
bs, err := d.readSizeN(n)
if err != nil {
return emptyBytes, err
}
v := make([]byte, n)
copy(v, bs)
return v, nil
}
@@ -0,0 +1,25 @@
package decoding
import (
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asBool(k reflect.Kind) (bool, error) {
code, err := d.readSize1()
if err != nil {
return false, err
}
return d.asBoolWithCode(code, k)
}
func (d *decoder) asBoolWithCode(code byte, k reflect.Kind) (bool, error) {
switch code {
case def.True:
return true, nil
case def.False:
return false, nil
}
return false, d.errorTemplate(code, k)
}
@@ -0,0 +1,108 @@
package decoding
import (
"encoding/binary"
"fmt"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asComplex64(code byte, k reflect.Kind) (complex64, error) {
switch code {
case def.Fixext8:
t, err := d.readSize1()
if err != nil {
return complex(0, 0), err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), fmt.Errorf("fixext8. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, err := d.readSize4()
if err != nil {
return complex(0, 0), err
}
r := math.Float32frombits(binary.BigEndian.Uint32(rb))
ib, err := d.readSize4()
if err != nil {
return complex(0, 0), err
}
i := math.Float32frombits(binary.BigEndian.Uint32(ib))
return complex(r, i), nil
case def.Fixext16:
t, err := d.readSize1()
if err != nil {
return complex(0, 0), err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), fmt.Errorf("fixext16. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, err := d.readSize8()
if err != nil {
return complex(0, 0), err
}
r := math.Float64frombits(binary.BigEndian.Uint64(rb))
ib, err := d.readSize8()
if err != nil {
return complex(0, 0), err
}
i := math.Float64frombits(binary.BigEndian.Uint64(ib))
return complex64(complex(r, i)), nil
}
return complex(0, 0), d.errorTemplate(code, k)
}
func (d *decoder) asComplex128(code byte, k reflect.Kind) (complex128, error) {
switch code {
case def.Fixext8:
t, err := d.readSize1()
if err != nil {
return complex(0, 0), err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), fmt.Errorf("fixext8. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, err := d.readSize4()
if err != nil {
return complex(0, 0), err
}
r := math.Float32frombits(binary.BigEndian.Uint32(rb))
ib, err := d.readSize4()
if err != nil {
return complex(0, 0), err
}
i := math.Float32frombits(binary.BigEndian.Uint32(ib))
return complex128(complex(r, i)), nil
case def.Fixext16:
t, err := d.readSize1()
if err != nil {
return complex(0, 0), err
}
if int8(t) != def.ComplexTypeCode() {
return complex(0, 0), fmt.Errorf("fixext16. complex type is diffrent %d, %d", t, def.ComplexTypeCode())
}
rb, err := d.readSize8()
if err != nil {
return complex(0, 0), err
}
r := math.Float64frombits(binary.BigEndian.Uint64(rb))
ib, err := d.readSize8()
if err != nil {
return complex(0, 0), err
}
i := math.Float64frombits(binary.BigEndian.Uint64(ib))
return complex(r, i), nil
}
return complex(0, 0), d.errorTemplate(code, k)
}
@@ -0,0 +1,324 @@
package decoding
import (
"fmt"
"io"
"reflect"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/internal/common"
)
type decoder struct {
r io.Reader
asArray bool
buf *common.Buffer
common.Common
}
// Decode analyzes the MessagePack-encoded data and stores
// the result into the pointer of v.
func Decode(r io.Reader, v interface{}, asArray bool) error {
if r == nil {
return def.ErrNoData
}
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr {
return fmt.Errorf("%w. v.(type): %T", def.ErrReceiverNotPointer, v)
}
rv = rv.Elem()
d := decoder{r: r,
buf: common.GetBuffer(),
asArray: asArray,
}
err := d.decode(rv)
common.PutBuffer(d.buf)
return err
}
func (d *decoder) decode(rv reflect.Value) error {
code, err := d.readSize1()
if err != nil {
return err
}
return d.decodeWithCode(code, rv)
}
func (d *decoder) decodeWithCode(code byte, rv reflect.Value) error {
k := rv.Kind()
switch k {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := d.asIntWithCode(code, k)
if err != nil {
return err
}
rv.SetInt(v)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := d.asUintWithCode(code, k)
if err != nil {
return err
}
rv.SetUint(v)
case reflect.Float32:
v, err := d.asFloat32WithCode(code, k)
if err != nil {
return err
}
rv.SetFloat(float64(v))
case reflect.Float64:
v, err := d.asFloat64WithCode(code, k)
if err != nil {
return err
}
rv.SetFloat(v)
case reflect.String:
// byte slice
if d.isCodeBin(code) {
v, err := d.asBinStringWithCode(code, k)
if err != nil {
return err
}
rv.SetString(v)
return nil
}
v, err := d.asStringWithCode(code, k)
if err != nil {
return err
}
rv.SetString(v)
case reflect.Bool:
v, err := d.asBoolWithCode(code, k)
if err != nil {
return err
}
rv.SetBool(v)
case reflect.Slice:
// nil
if d.isCodeNil(code) {
return nil
}
// byte slice
if d.isCodeBin(code) {
bs, err := d.asBinWithCode(code, k)
if err != nil {
return err
}
rv.SetBytes(bs)
return nil
}
// string to bytes
if d.isCodeString(code) {
l, err := d.stringByteLength(code, k)
if err != nil {
return err
}
bs, err := d.asStringByteByLength(l, k)
if err != nil {
return err
}
rv.SetBytes(bs)
return nil
}
// get slice length
l, err := d.sliceLength(code, k)
if err != nil {
return err
}
// check fixed type
found, err := d.asFixedSlice(rv, l)
if err != nil {
return err
}
if found {
return nil
}
// create slice dynamically
tmpSlice := reflect.MakeSlice(rv.Type(), l, l)
for i := 0; i < l; i++ {
v := tmpSlice.Index(i)
if v.Kind() == reflect.Struct {
structCode, err := d.readSize1()
if err != nil {
return err
}
if err = d.setStruct(structCode, v, k); err != nil {
return err
}
} else {
if err = d.decode(v); err != nil {
return err
}
}
}
rv.Set(tmpSlice)
case reflect.Complex64:
v, err := d.asComplex64(code, k)
if err != nil {
return err
}
rv.SetComplex(complex128(v))
case reflect.Complex128:
v, err := d.asComplex128(code, k)
if err != nil {
return err
}
rv.SetComplex(v)
case reflect.Array:
// nil
if d.isCodeNil(code) {
return nil
}
// byte slice
if d.isCodeBin(code) {
bs, err := d.asBinWithCode(code, k)
if err != nil {
return err
}
if len(bs) > rv.Len() {
return fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), len(bs), def.ErrNotMatchArrayElement)
}
for i, b := range bs {
rv.Index(i).SetUint(uint64(b))
}
return nil
}
// string to bytes
if d.isCodeString(code) {
l, err := d.stringByteLength(code, k)
if err != nil {
return err
}
if l > rv.Len() {
return fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), l, def.ErrNotMatchArrayElement)
}
bs, err := d.asStringByteByLength(l, k)
if err != nil {
return err
}
for i, b := range bs {
rv.Index(i).SetUint(uint64(b))
}
return nil
}
// get slice length
l, err := d.sliceLength(code, k)
if err != nil {
return err
}
if l > rv.Len() {
return fmt.Errorf("%v len is %d, but msgpack has %d elements, %w", rv.Type(), rv.Len(), l, def.ErrNotMatchArrayElement)
}
// create array dynamically
for i := 0; i < l; i++ {
err = d.decode(rv.Index(i))
if err != nil {
return err
}
}
case reflect.Map:
// nil
if d.isCodeNil(code) {
return nil
}
// get map length
l, err := d.mapLength(code, k)
if err != nil {
return err
}
// check fixed type
found, err := d.asFixedMap(rv, l)
if err != nil {
return err
}
if found {
return nil
}
// create dynamically
key := rv.Type().Key()
value := rv.Type().Elem()
if rv.IsNil() {
rv.Set(reflect.MakeMapWithSize(rv.Type(), l))
}
for i := 0; i < l; i++ {
k := reflect.New(key).Elem()
v := reflect.New(value).Elem()
err = d.decode(k)
if err != nil {
return err
}
err = d.decode(v)
if err != nil {
return err
}
rv.SetMapIndex(k, v)
}
case reflect.Struct:
err := d.setStruct(code, rv, k)
if err != nil {
return err
}
case reflect.Ptr:
// nil
if d.isCodeNil(code) {
return nil
}
if rv.Elem().Kind() == reflect.Invalid {
n := reflect.New(rv.Type().Elem())
rv.Set(n)
}
err := d.decodeWithCode(code, rv.Elem())
if err != nil {
return err
}
case reflect.Interface:
if rv.Elem().Kind() == reflect.Ptr {
err := d.decode(rv.Elem())
if err != nil {
return err
}
} else {
v, err := d.asInterfaceWithCode(code, k)
if err != nil {
return err
}
if v != nil {
rv.Set(reflect.ValueOf(v))
}
}
default:
return fmt.Errorf("%v is %w type", rv.Kind(), def.ErrUnsupportedType)
}
return nil
}
func (d *decoder) errorTemplate(code byte, k reflect.Kind) error {
return fmt.Errorf("%w %x decoding as %v", def.ErrCanNotDecode, code, k)
}
@@ -0,0 +1,160 @@
package decoding
import (
"encoding/binary"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/time"
)
var extCoderMap = map[int8]ext.StreamDecoder{time.StreamDecoder.Code(): time.StreamDecoder}
var extCoders = []ext.StreamDecoder{time.StreamDecoder}
// AddExtDecoder adds decoders for extension types.
func AddExtDecoder(f ext.StreamDecoder) {
// ignore time
if f.Code() == time.Decoder.Code() {
return
}
_, ok := extCoderMap[f.Code()]
if !ok {
extCoderMap[f.Code()] = f
updateExtCoders()
}
}
// RemoveExtDecoder removes decoders for extension types.
func RemoveExtDecoder(f ext.StreamDecoder) {
// ignore time
if f.Code() == time.Decoder.Code() {
return
}
_, ok := extCoderMap[f.Code()]
if ok {
delete(extCoderMap, f.Code())
updateExtCoders()
}
}
func updateExtCoders() {
extCoders = make([]ext.StreamDecoder, len(extCoderMap))
i := 0
for k := range extCoderMap {
extCoders[i] = extCoderMap[k]
i++
}
}
func (d *decoder) readIfExtType(code byte) (innerType int8, data []byte, err error) {
switch code {
case def.Fixext1:
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
v, err := d.readSize1()
if err != nil {
return 0, nil, err
}
return int8(typ), []byte{v}, nil
case def.Fixext2:
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSize2()
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Fixext4:
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSize4()
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Fixext8:
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSize8()
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Fixext16:
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSize16()
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Ext8:
bs, err := d.readSize1()
if err != nil {
return 0, nil, err
}
size := int(bs)
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSizeN(size)
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Ext16:
bs, err := d.readSize2()
if err != nil {
return 0, nil, err
}
size := int(binary.BigEndian.Uint16(bs))
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSizeN(size)
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
case def.Ext32:
bs, err := d.readSize4()
if err != nil {
return 0, nil, err
}
size := int(binary.BigEndian.Uint32(bs))
typ, err := d.readSize1()
if err != nil {
return 0, nil, err
}
data, err = d.readSizeN(size)
if err != nil {
return 0, nil, err
}
return int8(typ), data, nil
}
return 0, nil, nil
}
@@ -0,0 +1,93 @@
package decoding
import (
"encoding/binary"
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asFloat32(k reflect.Kind) (float32, error) {
code, err := d.readSize1()
if err != nil {
return 0, err
}
return d.asFloat32WithCode(code, k)
}
func (d *decoder) asFloat32WithCode(code byte, k reflect.Kind) (float32, error) {
switch {
case code == def.Float32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := math.Float32frombits(binary.BigEndian.Uint32(bs))
return v, nil
case d.isPositiveFixNum(code), code == def.Uint8, code == def.Uint16, code == def.Uint32, code == def.Uint64:
v, err := d.asUintWithCode(code, k)
if err != nil {
return 0, err
}
return float32(v), nil
case d.isNegativeFixNum(code), code == def.Int8, code == def.Int16, code == def.Int32, code == def.Int64:
v, err := d.asIntWithCode(code, k)
if err != nil {
return 0, err
}
return float32(v), nil
case code == def.Nil:
return 0, nil
}
return 0, d.errorTemplate(code, k)
}
func (d *decoder) asFloat64(k reflect.Kind) (float64, error) {
code, err := d.readSize1()
if err != nil {
return 0, err
}
return d.asFloat64WithCode(code, k)
}
func (d *decoder) asFloat64WithCode(code byte, k reflect.Kind) (float64, error) {
switch {
case code == def.Float64:
bs, err := d.readSize8()
if err != nil {
return 0, err
}
v := math.Float64frombits(binary.BigEndian.Uint64(bs))
return v, nil
case code == def.Float32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := math.Float32frombits(binary.BigEndian.Uint32(bs))
return float64(v), nil
case d.isPositiveFixNum(code), code == def.Uint8, code == def.Uint16, code == def.Uint32, code == def.Uint64:
v, err := d.asUintWithCode(code, k)
if err != nil {
return 0, err
}
return float64(v), nil
case d.isNegativeFixNum(code), code == def.Int8, code == def.Int16, code == def.Int32, code == def.Int64:
v, err := d.asIntWithCode(code, k)
if err != nil {
return 0, err
}
return float64(v), nil
case code == def.Nil:
return 0, nil
}
return 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,113 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) isPositiveFixNum(v byte) bool {
return def.PositiveFixIntMin <= v && v <= def.PositiveFixIntMax
}
func (d *decoder) isNegativeFixNum(v byte) bool {
return def.NegativeFixintMin <= int8(v) && int8(v) <= def.NegativeFixintMax
}
func (d *decoder) asInt(k reflect.Kind) (int64, error) {
code, err := d.readSize1()
if err != nil {
return 0, err
}
return d.asIntWithCode(code, k)
}
func (d *decoder) asIntWithCode(code byte, k reflect.Kind) (int64, error) {
switch {
case d.isPositiveFixNum(code):
return int64(code), nil
case d.isNegativeFixNum(code):
return int64(int8(code)), nil
case code == def.Uint8:
b, err := d.readSize1()
if err != nil {
return 0, err
}
return int64(b), nil
case code == def.Int8:
b, err := d.readSize1()
if err != nil {
return 0, err
}
return int64(int8(b)), nil
case code == def.Uint16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
v := binary.BigEndian.Uint16(bs)
return int64(v), nil
case code == def.Int16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
v := int16(binary.BigEndian.Uint16(bs))
return int64(v), nil
case code == def.Uint32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := binary.BigEndian.Uint32(bs)
return int64(v), nil
case code == def.Int32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := int32(binary.BigEndian.Uint32(bs))
return int64(v), nil
case code == def.Uint64:
bs, err := d.readSize8()
if err != nil {
return 0, err
}
return int64(binary.BigEndian.Uint64(bs)), nil
case code == def.Int64:
bs, err := d.readSize8()
if err != nil {
return 0, err
}
return int64(binary.BigEndian.Uint64(bs)), nil
case code == def.Float32:
v, err := d.asFloat32WithCode(code, k)
if err != nil {
return 0, err
}
return int64(v), nil
case code == def.Float64:
v, err := d.asFloat64WithCode(code, k)
if err != nil {
return 0, err
}
return int64(v), nil
case code == def.Nil:
return 0, nil
}
return 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,177 @@
package decoding
import (
"fmt"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asInterface(k reflect.Kind) (interface{}, error) {
code, err := d.readSize1()
if err != nil {
return nil, err
}
return d.asInterfaceWithCode(code, k)
}
func (d *decoder) asInterfaceWithCode(code byte, k reflect.Kind) (interface{}, error) {
switch {
case code == def.Nil:
return nil, nil
case code == def.True, code == def.False:
v, err := d.asBoolWithCode(code, k)
if err != nil {
return nil, err
}
return v, nil
case d.isPositiveFixNum(code), code == def.Uint8:
v, err := d.asUintWithCode(code, k)
if err != nil {
return nil, err
}
return uint8(v), err
case code == def.Uint16:
v, err := d.asUintWithCode(code, k)
if err != nil {
return nil, err
}
return uint16(v), err
case code == def.Uint32:
v, err := d.asUintWithCode(code, k)
if err != nil {
return nil, err
}
return uint32(v), err
case code == def.Uint64:
v, err := d.asUintWithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case d.isNegativeFixNum(code), code == def.Int8:
v, err := d.asIntWithCode(code, k)
if err != nil {
return nil, err
}
return int8(v), err
case code == def.Int16:
v, err := d.asIntWithCode(code, k)
if err != nil {
return nil, err
}
return int16(v), err
case code == def.Int32:
v, err := d.asIntWithCode(code, k)
if err != nil {
return nil, err
}
return int32(v), err
case code == def.Int64:
v, err := d.asIntWithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case code == def.Float32:
v, err := d.asFloat32WithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case code == def.Float64:
v, err := d.asFloat64WithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case d.isFixString(code), code == def.Str8, code == def.Str16, code == def.Str32:
v, err := d.asStringWithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case code == def.Bin8, code == def.Bin16, code == def.Bin32:
v, err := d.asBinWithCode(code, k)
if err != nil {
return nil, err
}
return v, err
case d.isFixSlice(code), code == def.Array16, code == def.Array32:
l, err := d.sliceLength(code, k)
if err != nil {
return nil, err
}
v := make([]interface{}, l)
for i := 0; i < l; i++ {
vv, err := d.asInterface(k)
if err != nil {
return nil, err
}
v[i] = vv
}
return v, nil
case d.isFixMap(code), code == def.Map16, code == def.Map32:
l, err := d.mapLength(code, k)
if err != nil {
return nil, err
}
v := make(map[interface{}]interface{}, l)
for i := 0; i < l; i++ {
keyCode, err := d.readSize1()
if err != nil {
return 0, err
}
if err := d.canSetAsMapKey(keyCode); err != nil {
return nil, err
}
key, err := d.asInterfaceWithCode(keyCode, k)
if err != nil {
return nil, err
}
value, err := d.asInterface(k)
if err != nil {
return nil, err
}
v[key] = value
}
return v, nil
}
// ext
extInnerType, extData, err := d.readIfExtType(code)
if err != nil {
return nil, err
}
for i := range extCoders {
if extCoders[i].IsType(code, extInnerType, len(extData)) {
v, err := extCoders[i].ToValue(code, extData, k)
if err != nil {
return nil, err
}
return v, nil
}
}
return nil, d.errorTemplate(code, k)
}
func (d *decoder) canSetAsMapKey(code byte) error {
switch {
case d.isFixSlice(code), code == def.Array16, code == def.Array32:
return fmt.Errorf("%w. code: %x", def.ErrCanNotSetSliceAsMapKey, code)
case d.isFixMap(code), code == def.Map16, code == def.Map32:
return fmt.Errorf("%w. code: %x", def.ErrCanNotSetMapAsMapKey, code)
}
return nil
}
@@ -0,0 +1,698 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var (
typeMapStringInt = reflect.TypeOf(map[string]int{})
typeMapStringInt8 = reflect.TypeOf(map[string]int8{})
typeMapStringInt16 = reflect.TypeOf(map[string]int16{})
typeMapStringInt32 = reflect.TypeOf(map[string]int32{})
typeMapStringInt64 = reflect.TypeOf(map[string]int64{})
typeMapStringUint = reflect.TypeOf(map[string]uint{})
typeMapStringUint8 = reflect.TypeOf(map[string]uint8{})
typeMapStringUint16 = reflect.TypeOf(map[string]uint16{})
typeMapStringUint32 = reflect.TypeOf(map[string]uint32{})
typeMapStringUint64 = reflect.TypeOf(map[string]uint64{})
typeMapStringFloat32 = reflect.TypeOf(map[string]float32{})
typeMapStringFloat64 = reflect.TypeOf(map[string]float64{})
typeMapStringBool = reflect.TypeOf(map[string]bool{})
typeMapStringString = reflect.TypeOf(map[string]string{})
typeMapIntString = reflect.TypeOf(map[int]string{})
typeMapInt8String = reflect.TypeOf(map[int8]string{})
typeMapInt16String = reflect.TypeOf(map[int16]string{})
typeMapInt32String = reflect.TypeOf(map[int32]string{})
typeMapInt64String = reflect.TypeOf(map[int64]string{})
typeMapIntBool = reflect.TypeOf(map[int]bool{})
typeMapInt8Bool = reflect.TypeOf(map[int8]bool{})
typeMapInt16Bool = reflect.TypeOf(map[int16]bool{})
typeMapInt32Bool = reflect.TypeOf(map[int32]bool{})
typeMapInt64Bool = reflect.TypeOf(map[int64]bool{})
typeMapUintString = reflect.TypeOf(map[uint]string{})
typeMapUint8String = reflect.TypeOf(map[uint8]string{})
typeMapUint16String = reflect.TypeOf(map[uint16]string{})
typeMapUint32String = reflect.TypeOf(map[uint32]string{})
typeMapUint64String = reflect.TypeOf(map[uint64]string{})
typeMapUintBool = reflect.TypeOf(map[uint]bool{})
typeMapUint8Bool = reflect.TypeOf(map[uint8]bool{})
typeMapUint16Bool = reflect.TypeOf(map[uint16]bool{})
typeMapUint32Bool = reflect.TypeOf(map[uint32]bool{})
typeMapUint64Bool = reflect.TypeOf(map[uint64]bool{})
typeMapFloat32String = reflect.TypeOf(map[float32]string{})
typeMapFloat64String = reflect.TypeOf(map[float64]string{})
typeMapFloat32Bool = reflect.TypeOf(map[float32]bool{})
typeMapFloat64Bool = reflect.TypeOf(map[float64]bool{})
)
func (d *decoder) isFixMap(v byte) bool {
return def.FixMap <= v && v <= def.FixMap+0x0f
}
func (d *decoder) mapLength(code byte, k reflect.Kind) (int, error) {
switch {
case d.isFixMap(code):
return int(code - def.FixMap), nil
case code == def.Map16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint16(bs)), nil
case code == def.Map32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint32(bs)), nil
}
return 0, d.errorTemplate(code, k)
}
func (d *decoder) asFixedMap(rv reflect.Value, l int) (bool, error) {
t := rv.Type()
keyKind := t.Key().Kind()
valueKind := t.Elem().Kind()
switch t {
case typeMapStringInt:
m := make(map[string]int, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asInt(valueKind)
if err != nil {
return false, err
}
m[k] = int(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringUint:
m := make(map[string]uint, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asUint(valueKind)
if err != nil {
return false, err
}
m[k] = uint(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringFloat32:
m := make(map[string]float32, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asFloat32(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringFloat64:
m := make(map[string]float64, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asFloat64(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringBool:
m := make(map[string]bool, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringString:
m := make(map[string]string, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringInt8:
m := make(map[string]int8, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asInt(valueKind)
if err != nil {
return false, err
}
m[k] = int8(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringInt16:
m := make(map[string]int16, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asInt(valueKind)
if err != nil {
return false, err
}
m[k] = int16(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringInt32:
m := make(map[string]int32, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asInt(valueKind)
if err != nil {
return false, err
}
m[k] = int32(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringInt64:
m := make(map[string]int64, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asInt(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringUint8:
m := make(map[string]uint8, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asUint(valueKind)
if err != nil {
return false, err
}
m[k] = uint8(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringUint16:
m := make(map[string]uint16, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asUint(valueKind)
if err != nil {
return false, err
}
m[k] = uint16(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringUint32:
m := make(map[string]uint32, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asUint(valueKind)
if err != nil {
return false, err
}
m[k] = uint32(v)
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapStringUint64:
m := make(map[string]uint64, l)
for i := 0; i < l; i++ {
k, err := d.asString(keyKind)
if err != nil {
return false, err
}
v, err := d.asUint(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapIntString:
m := make(map[int]string, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[int(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt8String:
m := make(map[int8]string, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[int8(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt16String:
m := make(map[int16]string, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[int16(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt32String:
m := make(map[int32]string, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[int32(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt64String:
m := make(map[int64]string, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapIntBool:
m := make(map[int]bool, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[int(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt8Bool:
m := make(map[int8]bool, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[int8(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt16Bool:
m := make(map[int16]bool, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[int16(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt32Bool:
m := make(map[int32]bool, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[int32(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapInt64Bool:
m := make(map[int64]bool, l)
for i := 0; i < l; i++ {
k, err := d.asInt(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUintString:
m := make(map[uint]string, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[uint(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint8String:
m := make(map[uint8]string, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[uint8(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint16String:
m := make(map[uint16]string, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[uint16(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint32String:
m := make(map[uint32]string, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[uint32(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint64String:
m := make(map[uint64]string, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUintBool:
m := make(map[uint]bool, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[uint(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint8Bool:
m := make(map[uint8]bool, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[uint8(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint16Bool:
m := make(map[uint16]bool, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[uint16(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint32Bool:
m := make(map[uint32]bool, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[uint32(k)] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapUint64Bool:
m := make(map[uint64]bool, l)
for i := 0; i < l; i++ {
k, err := d.asUint(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapFloat32String:
m := make(map[float32]string, l)
for i := 0; i < l; i++ {
k, err := d.asFloat32(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapFloat64String:
m := make(map[float64]string, l)
for i := 0; i < l; i++ {
k, err := d.asFloat64(keyKind)
if err != nil {
return false, err
}
v, err := d.asString(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapFloat32Bool:
m := make(map[float32]bool, l)
for i := 0; i < l; i++ {
k, err := d.asFloat32(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
case typeMapFloat64Bool:
m := make(map[float64]bool, l)
for i := 0; i < l; i++ {
k, err := d.asFloat64(keyKind)
if err != nil {
return false, err
}
v, err := d.asBool(valueKind)
if err != nil {
return false, err
}
m[k] = v
}
rv.Set(reflect.ValueOf(m))
return true, nil
}
return false, nil
}
@@ -0,0 +1,7 @@
package decoding
import "github.com/shamaton/msgpack/v2/def"
func (d *decoder) isCodeNil(v byte) bool {
return def.Nil == v
}
@@ -0,0 +1,50 @@
package decoding
func (d *decoder) readSize1() (byte, error) {
if _, err := d.r.Read(d.buf.B1); err != nil {
return 0, err
}
return d.buf.B1[0], nil
}
func (d *decoder) readSize2() ([]byte, error) {
if _, err := d.r.Read(d.buf.B2); err != nil {
return emptyBytes, err
}
return d.buf.B2, nil
}
func (d *decoder) readSize4() ([]byte, error) {
if _, err := d.r.Read(d.buf.B4); err != nil {
return emptyBytes, err
}
return d.buf.B4, nil
}
func (d *decoder) readSize8() ([]byte, error) {
if _, err := d.r.Read(d.buf.B8); err != nil {
return emptyBytes, err
}
return d.buf.B8, nil
}
func (d *decoder) readSize16() ([]byte, error) {
if _, err := d.r.Read(d.buf.B16); err != nil {
return emptyBytes, err
}
return d.buf.B16, nil
}
func (d *decoder) readSizeN(n int) ([]byte, error) {
var b []byte
if n <= len(d.buf.Data) {
b = d.buf.Data[:n]
} else {
d.buf.Data = append(d.buf.Data, make([]byte, n-len(d.buf.Data))...)
b = d.buf.Data
}
if _, err := d.r.Read(b); err != nil {
return emptyBytes, err
}
return b, nil
}
@@ -0,0 +1,230 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var (
typeIntSlice = reflect.TypeOf([]int{})
typeInt8Slice = reflect.TypeOf([]int8{})
typeInt16Slice = reflect.TypeOf([]int16{})
typeInt32Slice = reflect.TypeOf([]int32{})
typeInt64Slice = reflect.TypeOf([]int64{})
typeUintSlice = reflect.TypeOf([]uint{})
typeUint8Slice = reflect.TypeOf([]uint8{})
typeUint16Slice = reflect.TypeOf([]uint16{})
typeUint32Slice = reflect.TypeOf([]uint32{})
typeUint64Slice = reflect.TypeOf([]uint64{})
typeFloat32Slice = reflect.TypeOf([]float32{})
typeFloat64Slice = reflect.TypeOf([]float64{})
typeStringSlice = reflect.TypeOf([]string{})
typeBoolSlice = reflect.TypeOf([]bool{})
)
func (d *decoder) isFixSlice(v byte) bool {
return def.FixArray <= v && v <= def.FixArray+0x0f
}
func (d *decoder) sliceLength(code byte, k reflect.Kind) (int, error) {
switch {
case d.isFixSlice(code):
return int(code - def.FixArray), nil
case code == def.Array16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint16(bs)), nil
case code == def.Array32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint32(bs)), nil
}
return 0, d.errorTemplate(code, k)
}
func (d *decoder) asFixedSlice(rv reflect.Value, l int) (bool, error) {
t := rv.Type()
k := t.Elem().Kind()
switch t {
case typeIntSlice:
sli := make([]int, l)
for i := range sli {
v, err := d.asInt(k)
if err != nil {
return false, err
}
sli[i] = int(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeUintSlice:
sli := make([]uint, l)
for i := range sli {
v, err := d.asUint(k)
if err != nil {
return false, err
}
sli[i] = uint(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeStringSlice:
sli := make([]string, l)
for i := range sli {
v, err := d.asString(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeBoolSlice:
sli := make([]bool, l)
for i := range sli {
v, err := d.asBool(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeFloat32Slice:
sli := make([]float32, l)
for i := range sli {
v, err := d.asFloat32(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeFloat64Slice:
sli := make([]float64, l)
for i := range sli {
v, err := d.asFloat64(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeInt8Slice:
sli := make([]int8, l)
for i := range sli {
v, err := d.asInt(k)
if err != nil {
return false, err
}
sli[i] = int8(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeInt16Slice:
sli := make([]int16, l)
for i := range sli {
v, err := d.asInt(k)
if err != nil {
return false, err
}
sli[i] = int16(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeInt32Slice:
sli := make([]int32, l)
for i := range sli {
v, err := d.asInt(k)
if err != nil {
return false, err
}
sli[i] = int32(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeInt64Slice:
sli := make([]int64, l)
for i := range sli {
v, err := d.asInt(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeUint8Slice:
sli := make([]uint8, l)
for i := range sli {
v, err := d.asUint(k)
if err != nil {
return false, err
}
sli[i] = uint8(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeUint16Slice:
sli := make([]uint16, l)
for i := range sli {
v, err := d.asUint(k)
if err != nil {
return false, err
}
sli[i] = uint16(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeUint32Slice:
sli := make([]uint32, l)
for i := range sli {
v, err := d.asUint(k)
if err != nil {
return false, err
}
sli[i] = uint32(v)
}
rv.Set(reflect.ValueOf(sli))
return true, nil
case typeUint64Slice:
sli := make([]uint64, l)
for i := range sli {
v, err := d.asUint(k)
if err != nil {
return false, err
}
sli[i] = v
}
rv.Set(reflect.ValueOf(sli))
return true, nil
}
return false, nil
}
@@ -0,0 +1,89 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var emptyString = ""
var emptyBytes = []byte{}
func (d *decoder) isCodeString(code byte) bool {
return d.isFixString(code) || code == def.Str8 || code == def.Str16 || code == def.Str32
}
func (d *decoder) isFixString(v byte) bool {
return def.FixStr <= v && v <= def.FixStr+0x1f
}
func (d *decoder) stringByteLength(code byte, k reflect.Kind) (int, error) {
if def.FixStr <= code && code <= def.FixStr+0x1f {
l := int(code - def.FixStr)
return l, nil
} else if code == def.Str8 {
b, err := d.readSize1()
if err != nil {
return 0, err
}
return int(b), nil
} else if code == def.Str16 {
b, err := d.readSize2()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint16(b)), nil
} else if code == def.Str32 {
b, err := d.readSize4()
if err != nil {
return 0, err
}
return int(binary.BigEndian.Uint32(b)), nil
} else if code == def.Nil {
return 0, nil
}
return 0, d.errorTemplate(code, k)
}
func (d *decoder) asString(k reflect.Kind) (string, error) {
code, err := d.readSize1()
if err != nil {
return emptyString, err
}
return d.asStringWithCode(code, k)
}
func (d *decoder) asStringWithCode(code byte, k reflect.Kind) (string, error) {
bs, err := d.asStringByteWithCode(code, k)
if err != nil {
return emptyString, err
}
return string(bs), nil
}
func (d *decoder) asStringByte(k reflect.Kind) ([]byte, error) {
code, err := d.readSize1()
if err != nil {
return emptyBytes, err
}
return d.asStringByteWithCode(code, k)
}
func (d *decoder) asStringByteWithCode(code byte, k reflect.Kind) ([]byte, error) {
l, err := d.stringByteLength(code, k)
if err != nil {
return emptyBytes, err
}
return d.asStringByteByLength(l, k)
}
func (d *decoder) asStringByteByLength(l int, _ reflect.Kind) ([]byte, error) {
if l < 1 {
return emptyBytes, nil
}
// avoid common buffer reference
return d.copySizeN(l)
}
@@ -0,0 +1,302 @@
package decoding
import (
"encoding/binary"
"reflect"
"sync"
"github.com/shamaton/msgpack/v2/def"
)
type structCacheTypeMap struct {
keys [][]byte
indexes []int
}
type structCacheTypeArray struct {
m []int
}
// struct cache map
var mapSCTM = sync.Map{}
var mapSCTA = sync.Map{}
func (d *decoder) setStruct(code byte, rv reflect.Value, k reflect.Kind) error {
if len(extCoders) > 0 {
innerType, data, err := d.readIfExtType(code)
if err != nil {
return err
}
if data != nil {
for i := range extCoders {
if extCoders[i].IsType(code, innerType, len(data)) {
v, err := extCoders[i].ToValue(code, data, k)
if err != nil {
return err
}
// Validate that the receptacle is of the right value type.
if rv.Type() == reflect.TypeOf(v) {
rv.Set(reflect.ValueOf(v))
return nil
}
}
}
}
}
if d.asArray {
return d.setStructFromArray(code, rv, k)
}
return d.setStructFromMap(code, rv, k)
}
func (d *decoder) setStructFromArray(code byte, rv reflect.Value, k reflect.Kind) error {
// get length
l, err := d.sliceLength(code, k)
if err != nil {
return err
}
// find or create reference
var scta *structCacheTypeArray
cache, findCache := mapSCTA.Load(rv.Type())
if !findCache {
scta = &structCacheTypeArray{}
for i := 0; i < rv.NumField(); i++ {
if ok, _, _ := d.CheckField(rv.Type().Field(i)); ok {
scta.m = append(scta.m, i)
}
}
mapSCTA.Store(rv.Type(), scta)
} else {
scta = cache.(*structCacheTypeArray)
}
// set value
for i := 0; i < l; i++ {
if i < len(scta.m) {
err = d.decode(rv.Field(scta.m[i]))
if err != nil {
return err
}
} else {
err = d.jumpOffset()
if err != nil {
return err
}
}
}
return nil
}
func (d *decoder) setStructFromMap(code byte, rv reflect.Value, k reflect.Kind) error {
// get length
l, err := d.mapLength(code, k)
if err != nil {
return err
}
var sctm *structCacheTypeMap
cache, cacheFind := mapSCTM.Load(rv.Type())
if !cacheFind {
sctm = &structCacheTypeMap{}
for i := 0; i < rv.NumField(); i++ {
if ok, _, name := d.CheckField(rv.Type().Field(i)); ok {
sctm.keys = append(sctm.keys, []byte(name))
sctm.indexes = append(sctm.indexes, i)
}
}
mapSCTM.Store(rv.Type(), sctm)
} else {
sctm = cache.(*structCacheTypeMap)
}
for i := 0; i < l; i++ {
dataKey, err := d.asStringByte(k)
if err != nil {
return err
}
fieldIndex := -1
for keyIndex, keyBytes := range sctm.keys {
if len(keyBytes) != len(dataKey) {
continue
}
fieldIndex = sctm.indexes[keyIndex]
for dataIndex := range dataKey {
if dataKey[dataIndex] != keyBytes[dataIndex] {
fieldIndex = -1
break
}
}
if fieldIndex >= 0 {
break
}
}
if fieldIndex >= 0 {
err = d.decode(rv.Field(fieldIndex))
if err != nil {
return err
}
} else {
err = d.jumpOffset()
if err != nil {
return err
}
}
}
return nil
}
func (d *decoder) jumpOffset() error {
code, err := d.readSize1()
if err != nil {
return err
}
switch {
case code == def.True, code == def.False, code == def.Nil:
// do nothing
case d.isPositiveFixNum(code) || d.isNegativeFixNum(code):
// do nothing
case code == def.Uint8, code == def.Int8:
_, err = d.readSize1()
return err
case code == def.Uint16, code == def.Int16:
_, err = d.readSize2()
return err
case code == def.Uint32, code == def.Int32, code == def.Float32:
_, err = d.readSize4()
return err
case code == def.Uint64, code == def.Int64, code == def.Float64:
_, err = d.readSize8()
return err
case d.isFixString(code):
_, err = d.readSizeN(int(code - def.FixStr))
return err
case code == def.Str8, code == def.Bin8:
b, err := d.readSize1()
if err != nil {
return err
}
_, err = d.readSizeN(int(b))
return err
case code == def.Str16, code == def.Bin16:
bs, err := d.readSize2()
if err != nil {
return err
}
_, err = d.readSizeN(int(binary.BigEndian.Uint16(bs)))
return err
case code == def.Str32, code == def.Bin32:
bs, err := d.readSize4()
if err != nil {
return err
}
_, err = d.readSizeN(int(binary.BigEndian.Uint32(bs)))
return err
case d.isFixSlice(code):
l := int(code - def.FixArray)
for i := 0; i < l; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case code == def.Array16:
bs, err := d.readSize2()
if err != nil {
return err
}
l := int(binary.BigEndian.Uint16(bs))
for i := 0; i < l; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case code == def.Array32:
bs, err := d.readSize4()
if err != nil {
return err
}
l := int(binary.BigEndian.Uint32(bs))
for i := 0; i < l; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case d.isFixMap(code):
l := int(code - def.FixMap)
for i := 0; i < l*2; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case code == def.Map16:
bs, err := d.readSize2()
if err != nil {
return err
}
l := int(binary.BigEndian.Uint16(bs))
for i := 0; i < l*2; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case code == def.Map32:
bs, err := d.readSize4()
if err != nil {
return err
}
l := int(binary.BigEndian.Uint32(bs))
for i := 0; i < l*2; i++ {
if err = d.jumpOffset(); err != nil {
return err
}
}
case code == def.Fixext1:
_, err = d.readSizeN(def.Byte1 + def.Byte1)
return err
case code == def.Fixext2:
_, err = d.readSizeN(def.Byte1 + def.Byte2)
return err
case code == def.Fixext4:
_, err = d.readSizeN(def.Byte1 + def.Byte4)
return err
case code == def.Fixext8:
_, err = d.readSizeN(def.Byte1 + def.Byte8)
return err
case code == def.Fixext16:
_, err = d.readSizeN(def.Byte1 + def.Byte16)
return err
case code == def.Ext8:
b, err := d.readSize1()
if err != nil {
return err
}
_, err = d.readSizeN(def.Byte1 + int(b))
return err
case code == def.Ext16:
bs, err := d.readSize2()
if err != nil {
return err
}
_, err = d.readSizeN(def.Byte1 + int(binary.BigEndian.Uint16(bs)))
return err
case code == def.Ext32:
bs, err := d.readSize4()
if err != nil {
return err
}
_, err = d.readSizeN(def.Byte1 + int(binary.BigEndian.Uint32(bs)))
return err
}
return nil
}
@@ -0,0 +1,91 @@
package decoding
import (
"encoding/binary"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (d *decoder) asUint(k reflect.Kind) (uint64, error) {
code, err := d.readSize1()
if err != nil {
return 0, err
}
return d.asUintWithCode(code, k)
}
func (d *decoder) asUintWithCode(code byte, k reflect.Kind) (uint64, error) {
switch {
case d.isPositiveFixNum(code):
return uint64(code), nil
case d.isNegativeFixNum(code):
return uint64(int8(code)), nil
case code == def.Uint8:
b, err := d.readSize1()
if err != nil {
return 0, err
}
return uint64(b), nil
case code == def.Int8:
b, err := d.readSize1()
if err != nil {
return 0, err
}
return uint64(int8(b)), nil
case code == def.Uint16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
v := binary.BigEndian.Uint16(bs)
return uint64(v), nil
case code == def.Int16:
bs, err := d.readSize2()
if err != nil {
return 0, err
}
v := int16(binary.BigEndian.Uint16(bs))
return uint64(v), nil
case code == def.Uint32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := binary.BigEndian.Uint32(bs)
return uint64(v), nil
case code == def.Int32:
bs, err := d.readSize4()
if err != nil {
return 0, err
}
v := int32(binary.BigEndian.Uint32(bs))
return uint64(v), nil
case code == def.Uint64:
bs, err := d.readSize8()
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(bs), nil
case code == def.Int64:
bs, err := d.readSize8()
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(bs), nil
case code == def.Nil:
return 0, nil
}
return 0, d.errorTemplate(code, k)
}
@@ -0,0 +1,10 @@
package encoding
import "github.com/shamaton/msgpack/v2/def"
func (e *encoder) writeBool(v bool) error {
if v {
return e.setByte1Int(def.True)
}
return e.setByte1Int(def.False)
}
@@ -0,0 +1,40 @@
package encoding
import (
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
var typeByte = reflect.TypeOf(byte(0))
func (e *encoder) isByteSlice(rv reflect.Value) bool {
return rv.Type().Elem() == typeByte
}
func (e *encoder) writeByteSliceLength(l int) error {
if l <= math.MaxUint8 {
if err := e.setByte1Int(def.Bin8); err != nil {
return err
}
if err := e.setByte1Int(l); err != nil {
return err
}
} else if l <= math.MaxUint16 {
if err := e.setByte1Int(def.Bin16); err != nil {
return err
}
if err := e.setByte2Int(l); err != nil {
return err
}
} else if uint(l) <= math.MaxUint32 {
if err := e.setByte1Int(def.Bin32); err != nil {
return err
}
if err := e.setByte4Int(l); err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,39 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeComplex64(v complex64) error {
if err := e.setByte1Int(def.Fixext8); err != nil {
return err
}
if err := e.setByte1Int(int(def.ComplexTypeCode())); err != nil {
return err
}
if err := e.setByte4Uint64(uint64(math.Float32bits(real(v)))); err != nil {
return err
}
if err := e.setByte4Uint64(uint64(math.Float32bits(imag(v)))); err != nil {
return err
}
return nil
}
func (e *encoder) writeComplex128(v complex128) error {
if err := e.setByte1Int(def.Fixext16); err != nil {
return err
}
if err := e.setByte1Int(int(def.ComplexTypeCode())); err != nil {
return err
}
if err := e.setByte8Uint64(math.Float64bits(real(v))); err != nil {
return err
}
if err := e.setByte8Uint64(math.Float64bits(imag(v))); err != nil {
return err
}
return nil
}
@@ -0,0 +1,195 @@
package encoding
import (
"fmt"
"io"
"reflect"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/internal/common"
)
type encoder struct {
w io.Writer
asArray bool
buf *common.Buffer
common.Common
}
// Encode writes MessagePack-encoded byte array of v to writer.
func Encode(w io.Writer, v any, asArray bool) error {
e := encoder{
w: w,
buf: common.GetBuffer(),
asArray: asArray,
}
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
}
err := e.create(rv)
if err == nil {
err = e.buf.Flush(e.w)
}
common.PutBuffer(e.buf)
return err
}
func (e *encoder) create(rv reflect.Value) error {
switch rv.Kind() {
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
v := rv.Uint()
return e.writeUint(v)
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
v := rv.Int()
return e.writeInt(v)
case reflect.Float32:
return e.writeFloat32(rv.Float())
case reflect.Float64:
return e.writeFloat64(rv.Float())
case reflect.Bool:
return e.writeBool(rv.Bool())
case reflect.String:
return e.writeString(rv.String())
case reflect.Complex64:
return e.writeComplex64(complex64(rv.Complex()))
case reflect.Complex128:
return e.writeComplex128(rv.Complex())
case reflect.Slice:
if rv.IsNil() {
return e.writeNil()
}
l := rv.Len()
// bin format
if e.isByteSlice(rv) {
if err := e.writeByteSliceLength(l); err != nil {
return err
}
return e.setBytes(rv.Bytes())
}
// format
if err := e.writeSliceLength(l); err != nil {
return err
}
if find, err := e.writeFixedSlice(rv); err != nil {
return err
} else if find {
return nil
}
// func
elem := rv.Type().Elem()
var f structWriteFunc
if elem.Kind() == reflect.Struct {
f = e.getStructWriter(elem)
} else {
f = e.create
}
// objects
for i := 0; i < l; i++ {
if err := f(rv.Index(i)); err != nil {
return err
}
}
case reflect.Array:
l := rv.Len()
// bin format
if e.isByteSlice(rv) {
if err := e.writeByteSliceLength(l); err != nil {
return err
}
// objects
for i := 0; i < l; i++ {
if err := e.setByte1Uint64(rv.Index(i).Uint()); err != nil {
return err
}
}
return nil
}
// format
if err := e.writeSliceLength(l); err != nil {
return err
}
// func
elem := rv.Type().Elem()
var f structWriteFunc
if elem.Kind() == reflect.Struct {
f = e.getStructWriter(elem)
} else {
f = e.create
}
// objects
for i := 0; i < l; i++ {
if err := f(rv.Index(i)); err != nil {
return err
}
}
case reflect.Map:
if rv.IsNil() {
return e.writeNil()
}
l := rv.Len()
if err := e.writeMapLength(l); err != nil {
return err
}
if find, err := e.writeFixedMap(rv); err != nil {
return err
} else if find {
return nil
}
// key-value
keys := rv.MapKeys()
for _, k := range keys {
if err := e.create(k); err != nil {
return err
}
if err := e.create(rv.MapIndex(k)); err != nil {
return err
}
}
case reflect.Struct:
return e.writeStruct(rv)
case reflect.Ptr:
if rv.IsNil() {
return e.writeNil()
}
return e.create(rv.Elem())
case reflect.Interface:
return e.create(rv.Elem())
case reflect.Invalid:
return e.writeNil()
default:
return fmt.Errorf("%v is %w type", rv.Kind(), def.ErrUnsupportedType)
}
return nil
}
@@ -0,0 +1,48 @@
package encoding
import (
"reflect"
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/time"
)
var extCoderMap = map[reflect.Type]ext.StreamEncoder{time.StreamEncoder.Type(): time.StreamEncoder}
var extCoders = []ext.StreamEncoder{time.StreamEncoder}
// AddExtEncoder adds encoders for extension types.
func AddExtEncoder(f ext.StreamEncoder) {
// ignore time
if f.Type() == time.Encoder.Type() {
return
}
_, ok := extCoderMap[f.Type()]
if !ok {
extCoderMap[f.Type()] = f
updateExtCoders()
}
}
// RemoveExtEncoder removes encoders for extension types.
func RemoveExtEncoder(f ext.StreamEncoder) {
// ignore time
if f.Type() == time.Encoder.Type() {
return
}
_, ok := extCoderMap[f.Type()]
if ok {
delete(extCoderMap, f.Type())
updateExtCoders()
}
}
func updateExtCoders() {
extCoders = make([]ext.StreamEncoder, len(extCoderMap))
i := 0
for k := range extCoderMap {
extCoders[i] = extCoderMap[k]
i++
}
}
@@ -0,0 +1,27 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeFloat32(v float64) error {
if err := e.setByte1Int(def.Float32); err != nil {
return err
}
if err := e.setByte4Uint64(uint64(math.Float32bits(float32(v)))); err != nil {
return err
}
return nil
}
func (e *encoder) writeFloat64(v float64) error {
if err := e.setByte1Int(def.Float64); err != nil {
return err
}
if err := e.setByte8Uint64(math.Float64bits(v)); err != nil {
return err
}
return nil
}
@@ -0,0 +1,52 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) isNegativeFixInt64(v int64) bool {
return def.NegativeFixintMin <= v && v <= def.NegativeFixintMax
}
func (e *encoder) writeInt(v int64) error {
if v >= 0 {
if err := e.writeUint(uint64(v)); err != nil {
return err
}
} else if e.isNegativeFixInt64(v) {
if err := e.setByte1Int64(v); err != nil {
return err
}
} else if v >= math.MinInt8 {
if err := e.setByte1Int(def.Int8); err != nil {
return err
}
if err := e.setByte1Int64(v); err != nil {
return err
}
} else if v >= math.MinInt16 {
if err := e.setByte1Int(def.Int16); err != nil {
return err
}
if err := e.setByte2Int64(v); err != nil {
return err
}
} else if v >= math.MinInt32 {
if err := e.setByte1Int(def.Int32); err != nil {
return err
}
if err := e.setByte4Int64(v); err != nil {
return err
}
} else {
if err := e.setByte1Int(def.Int64); err != nil {
return err
}
if err := e.setByte8Int64(v); err != nil {
return err
}
}
return nil
}
@@ -0,0 +1,433 @@
package encoding
import (
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeMapLength(l int) error {
// format
if l <= 0x0f {
if err := e.setByte1Int(def.FixMap + l); err != nil {
return err
}
} else if l <= math.MaxUint16 {
if err := e.setByte1Int(def.Map16); err != nil {
return err
}
if err := e.setByte2Int(l); err != nil {
return err
}
} else if uint(l) <= math.MaxUint32 {
if err := e.setByte1Int(def.Map32); err != nil {
return err
}
if err := e.setByte4Int(l); err != nil {
return err
}
}
return nil
}
func (e *encoder) writeFixedMap(rv reflect.Value) (bool, error) {
switch m := rv.Interface().(type) {
case map[string]int:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]uint:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]float32:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeFloat32(float64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]float64:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeFloat64(v); err != nil {
return false, err
}
}
return true, nil
case map[string]bool:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[string]string:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[string]int8:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]int16:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]int32:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]int64:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]uint8:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]uint16:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]uint32:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case map[string]uint64:
for k, v := range m {
if err := e.writeString(k); err != nil {
return false, err
}
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case map[int]string:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[int]bool:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[uint]string:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[uint]bool:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[float32]string:
for k, v := range m {
if err := e.writeFloat32(float64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[float32]bool:
for k, v := range m {
if err := e.writeFloat32(float64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[float64]string:
for k, v := range m {
if err := e.writeFloat64(k); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[float64]bool:
for k, v := range m {
if err := e.writeFloat64(k); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[int8]string:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[int8]bool:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[int16]string:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[int16]bool:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[int32]string:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[int32]bool:
for k, v := range m {
if err := e.writeInt(int64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[int64]string:
for k, v := range m {
if err := e.writeInt(k); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[int64]bool:
for k, v := range m {
if err := e.writeInt(k); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[uint8]string:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[uint8]bool:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[uint16]string:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[uint16]bool:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[uint32]string:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[uint32]bool:
for k, v := range m {
if err := e.writeUint(uint64(k)); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case map[uint64]string:
for k, v := range m {
if err := e.writeUint(k); err != nil {
return false, err
}
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case map[uint64]bool:
for k, v := range m {
if err := e.writeUint(k); err != nil {
return false, err
}
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
}
return false, nil
}
@@ -0,0 +1,7 @@
package encoding
import "github.com/shamaton/msgpack/v2/def"
func (e *encoder) writeNil() error {
return e.setByte1Int(def.Nil)
}
@@ -0,0 +1,93 @@
package encoding
func (e *encoder) setByte1Int64(value int64) error {
return e.buf.Write(e.w, byte(value))
}
func (e *encoder) setByte2Int64(value int64) error {
return e.buf.Write(e.w,
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte4Int64(value int64) error {
return e.buf.Write(e.w,
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte8Int64(value int64) error {
return e.buf.Write(e.w,
byte(value>>56),
byte(value>>48),
byte(value>>40),
byte(value>>32),
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte1Uint64(value uint64) error {
return e.buf.Write(e.w, byte(value))
}
func (e *encoder) setByte2Uint64(value uint64) error {
return e.buf.Write(e.w,
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte4Uint64(value uint64) error {
return e.buf.Write(e.w,
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte8Uint64(value uint64) error {
return e.buf.Write(e.w,
byte(value>>56),
byte(value>>48),
byte(value>>40),
byte(value>>32),
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte1Int(value int) error {
return e.buf.Write(e.w,
byte(value),
)
}
func (e *encoder) setByte2Int(value int) error {
return e.buf.Write(e.w,
byte(value>>8),
byte(value),
)
}
func (e *encoder) setByte4Int(value int) error {
return e.buf.Write(e.w,
byte(value>>24),
byte(value>>16),
byte(value>>8),
byte(value),
)
}
func (e *encoder) setBytes(bs []byte) error {
return e.buf.Write(e.w, bs...)
}
@@ -0,0 +1,151 @@
package encoding
import (
"math"
"reflect"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeSliceLength(l int) error {
// format size
if l <= 0x0f {
if err := e.setByte1Int(def.FixArray + l); err != nil {
return err
}
} else if l <= math.MaxUint16 {
if err := e.setByte1Int(def.Array16); err != nil {
return err
}
if err := e.setByte2Int(l); err != nil {
return err
}
} else if uint(l) <= math.MaxUint32 {
if err := e.setByte1Int(def.Array32); err != nil {
return err
}
if err := e.setByte4Int(l); err != nil {
return err
}
}
return nil
}
func (e *encoder) writeFixedSlice(rv reflect.Value) (bool, error) {
switch sli := rv.Interface().(type) {
case []int:
for _, v := range sli {
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case []uint:
for _, v := range sli {
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case []string:
for _, v := range sli {
if err := e.writeString(v); err != nil {
return false, err
}
}
return true, nil
case []float32:
for _, v := range sli {
if err := e.writeFloat32(float64(v)); err != nil {
return false, err
}
}
return true, nil
case []float64:
for _, v := range sli {
if err := e.writeFloat64(float64(v)); err != nil {
return false, err
}
}
return true, nil
case []bool:
for _, v := range sli {
if err := e.writeBool(v); err != nil {
return false, err
}
}
return true, nil
case []int8:
for _, v := range sli {
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case []int16:
for _, v := range sli {
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case []int32:
for _, v := range sli {
if err := e.writeInt(int64(v)); err != nil {
return false, err
}
}
return true, nil
case []int64:
for _, v := range sli {
if err := e.writeInt(v); err != nil {
return false, err
}
}
return true, nil
case []uint8:
for _, v := range sli {
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case []uint16:
for _, v := range sli {
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case []uint32:
for _, v := range sli {
if err := e.writeUint(uint64(v)); err != nil {
return false, err
}
}
return true, nil
case []uint64:
for _, v := range sli {
if err := e.writeUint(v); err != nil {
return false, err
}
}
return true, nil
}
return false, nil
}
@@ -0,0 +1,41 @@
package encoding
import (
"math"
"unsafe"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeString(str string) error {
// NOTE : unsafe
strBytes := *(*[]byte)(unsafe.Pointer(&str))
l := len(strBytes)
if l < 32 {
if err := e.setByte1Int(def.FixStr + l); err != nil {
return err
}
} else if l <= math.MaxUint8 {
if err := e.setByte1Int(def.Str8); err != nil {
return err
}
if err := e.setByte1Int(l); err != nil {
return err
}
} else if l <= math.MaxUint16 {
if err := e.setByte1Int(def.Str16); err != nil {
return err
}
if err := e.setByte2Int(l); err != nil {
return err
}
} else {
if err := e.setByte1Int(def.Str32); err != nil {
return err
}
if err := e.setByte4Int(l); err != nil {
return err
}
}
return e.setBytes(strBytes)
}
@@ -0,0 +1,168 @@
package encoding
import (
"math"
"reflect"
"sync"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/internal/common"
)
type structCache struct {
indexes []int
names []string
omits []bool
noOmit bool
common.Common
}
var cachemap = sync.Map{}
type structWriteFunc func(rv reflect.Value) error
func (e *encoder) getStructWriter(typ reflect.Type) structWriteFunc {
for i := range extCoders {
if extCoders[i].Type() == typ {
return func(rv reflect.Value) error {
w := ext.CreateStreamWriter(e.w, e.buf)
return extCoders[i].Write(w, rv)
}
}
}
if e.asArray {
return e.writeStructArray
}
return e.writeStructMap
}
func (e *encoder) writeStruct(rv reflect.Value) error {
for i := range extCoders {
if extCoders[i].Type() == rv.Type() {
w := ext.CreateStreamWriter(e.w, e.buf)
return extCoders[i].Write(w, rv)
}
}
if e.asArray {
return e.writeStructArray(rv)
}
return e.writeStructMap(rv)
}
func (e *encoder) writeStructArray(rv reflect.Value) error {
c := e.getStructCache(rv)
// write format
num := len(c.indexes)
if num <= 0x0f {
if err := e.setByte1Int(def.FixArray + num); err != nil {
return err
}
} else if num <= math.MaxUint16 {
if err := e.setByte1Int(def.Array16); err != nil {
return err
}
if err := e.setByte2Int(num); err != nil {
return err
}
} else if uint(num) <= math.MaxUint32 {
if err := e.setByte1Int(def.Array32); err != nil {
return err
}
if err := e.setByte4Int(num); err != nil {
return err
}
}
for i := 0; i < num; i++ {
if err := e.create(rv.Field(c.indexes[i])); err != nil {
return err
}
}
return nil
}
func (e *encoder) writeStructMap(rv reflect.Value) error {
c := e.getStructCache(rv)
num := len(c.indexes)
l := 0
if c.noOmit {
l = num
} else {
for i := 0; i < num; i++ {
irv := rv.Field(c.indexes[i])
if !c.omits[i] || !irv.IsZero() {
l++
}
}
}
// format size
if l <= 0x0f {
if err := e.setByte1Int(def.FixMap + l); err != nil {
return err
}
} else if l <= math.MaxUint16 {
if err := e.setByte1Int(def.Map16); err != nil {
return err
}
if err := e.setByte2Int(l); err != nil {
return err
}
} else if uint(l) <= math.MaxUint32 {
if err := e.setByte1Int(def.Map32); err != nil {
return err
}
if err := e.setByte4Int(l); err != nil {
return err
}
}
for i := 0; i < num; i++ {
irv := rv.Field(c.indexes[i])
if !c.omits[i] || !irv.IsZero() {
if err := e.writeString(c.names[i]); err != nil {
return err
}
if err := e.create(irv); err != nil {
return err
}
}
}
return nil
}
func (e *encoder) getStructCache(rv reflect.Value) *structCache {
t := rv.Type()
cache, find := cachemap.Load(t)
if find {
return cache.(*structCache)
}
num := rv.NumField()
c := &structCache{
indexes: make([]int, 0, num),
names: make([]string, 0, num),
omits: make([]bool, 0, num),
}
omitCount := 0
for i := 0; i < num; i++ {
if ok, omit, name := e.CheckField(rv.Type().Field(i)); ok {
c.indexes = append(c.indexes, i)
c.names = append(c.names, name)
c.omits = append(c.omits, omit)
if omit {
omitCount++
}
}
}
c.noOmit = omitCount == 0
cachemap.Store(t, c)
return c
}
@@ -0,0 +1,44 @@
package encoding
import (
"math"
"github.com/shamaton/msgpack/v2/def"
)
func (e *encoder) writeUint(v uint64) error {
if v <= math.MaxInt8 {
if err := e.setByte1Uint64(v); err != nil {
return err
}
} else if v <= math.MaxUint8 {
if err := e.setByte1Int(def.Uint8); err != nil {
return err
}
if err := e.setByte1Uint64(v); err != nil {
return err
}
} else if v <= math.MaxUint16 {
if err := e.setByte1Int(def.Uint16); err != nil {
return err
}
if err := e.setByte2Uint64(v); err != nil {
return err
}
} else if v <= math.MaxUint32 {
if err := e.setByte1Int(def.Uint32); err != nil {
return err
}
if err := e.setByte4Uint64(v); err != nil {
return err
}
} else {
if err := e.setByte1Int(def.Uint64); err != nil {
return err
}
if err := e.setByte8Uint64(v); err != nil {
return err
}
}
return nil
}
+95
View File
@@ -0,0 +1,95 @@
package msgpack
import (
"fmt"
"io"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
"github.com/shamaton/msgpack/v2/internal/decoding"
"github.com/shamaton/msgpack/v2/internal/encoding"
streamdecoding "github.com/shamaton/msgpack/v2/internal/stream/decoding"
streamencoding "github.com/shamaton/msgpack/v2/internal/stream/encoding"
"github.com/shamaton/msgpack/v2/time"
)
// StructAsArray is encoding option.
// If this option sets true, default encoding sets to array-format.
var StructAsArray = false
// Marshal returns the MessagePack-encoded byte array of v.
func Marshal(v interface{}) ([]byte, error) {
return encoding.Encode(v, StructAsArray)
}
// MarshalWrite writes MessagePack-encoded byte array of v to writer.
func MarshalWrite(w io.Writer, v interface{}) error {
return streamencoding.Encode(w, v, StructAsArray)
}
// Unmarshal analyzes the MessagePack-encoded data and stores
// the result into the pointer of v.
func Unmarshal(data []byte, v interface{}) error {
return decoding.Decode(data, v, StructAsArray)
}
// UnmarshalRead reads the MessagePack-encoded data from reader and stores
// the result into the pointer of v.
func UnmarshalRead(r io.Reader, v interface{}) error {
return streamdecoding.Decode(r, v, StructAsArray)
}
// AddExtCoder adds encoders for extension types.
func AddExtCoder(e ext.Encoder, d ext.Decoder) error {
if e.Code() != d.Code() {
return fmt.Errorf("code different %d:%d", e.Code(), d.Code())
}
encoding.AddExtEncoder(e)
decoding.AddExtDecoder(d)
return nil
}
// AddExtStreamCoder adds stream encoders for extension types.
func AddExtStreamCoder(e ext.StreamEncoder, d ext.StreamDecoder) error {
if e.Code() != d.Code() {
return fmt.Errorf("code different %d:%d", e.Code(), d.Code())
}
streamencoding.AddExtEncoder(e)
streamdecoding.AddExtDecoder(d)
return nil
}
// RemoveExtCoder removes encoders for extension types.
func RemoveExtCoder(e ext.Encoder, d ext.Decoder) error {
if e.Code() != d.Code() {
return fmt.Errorf("code different %d:%d", e.Code(), d.Code())
}
encoding.RemoveExtEncoder(e)
decoding.RemoveExtDecoder(d)
return nil
}
// RemoveExtStreamCoder removes stream encoders for extension types.
func RemoveExtStreamCoder(e ext.StreamEncoder, d ext.StreamDecoder) error {
if e.Code() != d.Code() {
return fmt.Errorf("code different %d:%d", e.Code(), d.Code())
}
streamencoding.RemoveExtEncoder(e)
streamdecoding.RemoveExtDecoder(d)
return nil
}
// SetComplexTypeCode sets def.complexTypeCode
func SetComplexTypeCode(code int8) {
def.SetComplexTypeCode(code)
}
// SetDecodedTimeAsUTC sets decoded time.Time values to UTC timezone.
func SetDecodedTimeAsUTC() {
time.SetDecodedAsLocal(false)
}
// SetDecodedTimeAsLocal sets decoded time.Time values to local timezone.
func SetDecodedTimeAsLocal() {
time.SetDecodedAsLocal(true)
}
+89
View File
@@ -0,0 +1,89 @@
package time
import (
"encoding/binary"
"fmt"
"reflect"
"time"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
)
var zero = time.Unix(0, 0)
var Decoder = new(timeDecoder)
type timeDecoder struct {
ext.DecoderCommon
}
var _ ext.Decoder = (*timeDecoder)(nil)
func (td *timeDecoder) Code() int8 {
return def.TimeStamp
}
func (td *timeDecoder) IsType(offset int, d *[]byte) bool {
code, offset := td.ReadSize1(offset, d)
if code == def.Fixext4 {
t, _ := td.ReadSize1(offset, d)
return int8(t) == td.Code()
} else if code == def.Fixext8 {
t, _ := td.ReadSize1(offset, d)
return int8(t) == td.Code()
} else if code == def.Ext8 {
l, offset := td.ReadSize1(offset, d)
t, _ := td.ReadSize1(offset, d)
return l == 12 && int8(t) == td.Code()
}
return false
}
func (td *timeDecoder) AsValue(offset int, k reflect.Kind, d *[]byte) (interface{}, int, error) {
code, offset := td.ReadSize1(offset, d)
switch code {
case def.Fixext4:
_, offset = td.ReadSize1(offset, d)
bs, offset := td.ReadSize4(offset, d)
v := time.Unix(int64(binary.BigEndian.Uint32(bs)), 0)
if decodeAsLocal {
return v, offset, nil
}
return v.UTC(), offset, nil
case def.Fixext8:
_, offset = td.ReadSize1(offset, d)
bs, offset := td.ReadSize8(offset, d)
data64 := binary.BigEndian.Uint64(bs)
nano := int64(data64 >> 34)
if nano > 999999999 {
return zero, 0, fmt.Errorf("in timestamp 64 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
v := time.Unix(int64(data64&0x00000003ffffffff), nano)
if decodeAsLocal {
return v, offset, nil
}
return v.UTC(), offset, nil
case def.Ext8:
_, offset = td.ReadSize1(offset, d)
_, offset = td.ReadSize1(offset, d)
nanobs, offset := td.ReadSize4(offset, d)
secbs, offset := td.ReadSize8(offset, d)
nano := binary.BigEndian.Uint32(nanobs)
if nano > 999999999 {
return zero, 0, fmt.Errorf("in timestamp 96 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
sec := binary.BigEndian.Uint64(secbs)
v := time.Unix(int64(sec), int64(nano))
if decodeAsLocal {
return v, offset, nil
}
return v.UTC(), offset, nil
}
return zero, 0, fmt.Errorf("should not reach this line!! code %x decoding %v", code, k)
}
+68
View File
@@ -0,0 +1,68 @@
package time
import (
"encoding/binary"
"fmt"
"reflect"
"time"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
)
var StreamDecoder = new(timeStreamDecoder)
type timeStreamDecoder struct{}
var _ ext.StreamDecoder = (*timeStreamDecoder)(nil)
func (td *timeStreamDecoder) Code() int8 {
return def.TimeStamp
}
func (td *timeStreamDecoder) IsType(code byte, innerType int8, dataLength int) bool {
switch code {
case def.Fixext4, def.Fixext8:
return innerType == td.Code()
case def.Ext8:
return innerType == td.Code() && dataLength == 12
}
return false
}
func (td *timeStreamDecoder) ToValue(code byte, data []byte, k reflect.Kind) (interface{}, error) {
switch code {
case def.Fixext4:
v := time.Unix(int64(binary.BigEndian.Uint32(data)), 0)
if decodeAsLocal {
return v, nil
}
return v.UTC(), nil
case def.Fixext8:
data64 := binary.BigEndian.Uint64(data)
nano := int64(data64 >> 34)
if nano > 999999999 {
return zero, fmt.Errorf("in timestamp 64 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
v := time.Unix(int64(data64&0x00000003ffffffff), nano)
if decodeAsLocal {
return v, nil
}
return v.UTC(), nil
case def.Ext8:
nano := binary.BigEndian.Uint32(data[:4])
if nano > 999999999 {
return zero, fmt.Errorf("in timestamp 96 formats, nanoseconds must not be larger than 999999999 : %d", nano)
}
sec := binary.BigEndian.Uint64(data[4:12])
v := time.Unix(int64(sec), int64(nano))
if decodeAsLocal {
return v, nil
}
return v.UTC(), nil
}
return zero, fmt.Errorf("should not reach this line!! code %x decoding %v", code, k)
}
+66
View File
@@ -0,0 +1,66 @@
package time
import (
"reflect"
"time"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
)
var Encoder = new(timeEncoder)
type timeEncoder struct {
ext.EncoderCommon
}
var typeOf = reflect.TypeOf(time.Time{})
func (td *timeEncoder) Code() int8 {
return def.TimeStamp
}
func (s *timeEncoder) Type() reflect.Type {
return typeOf
}
func (s *timeEncoder) CalcByteSize(value reflect.Value) (int, error) {
t := value.Interface().(time.Time)
secs := uint64(t.Unix())
if secs>>34 == 0 {
data := uint64(t.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
return def.Byte1 + def.Byte1 + def.Byte4, nil
}
return def.Byte1 + def.Byte1 + 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 {
t := value.Interface().(time.Time)
secs := uint64(t.Unix())
if secs>>34 == 0 {
data := uint64(t.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
offset = s.SetByte1Int(def.Fixext4, offset, bytes)
offset = s.SetByte1Int(def.TimeStamp, offset, bytes)
offset = s.SetByte4Uint64(data, offset, bytes)
return offset
}
offset = s.SetByte1Int(def.Fixext8, offset, bytes)
offset = s.SetByte1Int(def.TimeStamp, offset, bytes)
offset = s.SetByte8Uint64(data, offset, bytes)
return offset
}
offset = s.SetByte1Int(def.Ext8, offset, bytes)
offset = s.SetByte1Int(12, offset, bytes)
offset = s.SetByte1Int(def.TimeStamp, offset, bytes)
offset = s.SetByte4Int(t.Nanosecond(), offset, bytes)
offset = s.SetByte8Uint64(secs, offset, bytes)
return offset
}
+72
View File
@@ -0,0 +1,72 @@
package time
import (
"reflect"
"time"
"github.com/shamaton/msgpack/v2/def"
"github.com/shamaton/msgpack/v2/ext"
)
var StreamEncoder = new(timeStreamEncoder)
type timeStreamEncoder struct{}
var _ ext.StreamEncoder = (*timeStreamEncoder)(nil)
func (timeStreamEncoder) Code() int8 {
return def.TimeStamp
}
func (timeStreamEncoder) Type() reflect.Type {
return typeOf
}
func (e timeStreamEncoder) Write(w ext.StreamWriter, value reflect.Value) error {
t := value.Interface().(time.Time)
secs := uint64(t.Unix())
if secs>>34 == 0 {
data := uint64(t.Nanosecond())<<34 | secs
if data&0xffffffff00000000 == 0 {
if err := w.WriteByte1Int(def.Fixext4); err != nil {
return err
}
if err := w.WriteByte1Int(def.TimeStamp); err != nil {
return err
}
if err := w.WriteByte4Uint64(data); err != nil {
return err
}
return nil
}
if err := w.WriteByte1Int(def.Fixext8); err != nil {
return err
}
if err := w.WriteByte1Int(def.TimeStamp); err != nil {
return err
}
if err := w.WriteByte8Uint64(data); err != nil {
return err
}
return nil
}
if err := w.WriteByte1Int(def.Ext8); err != nil {
return err
}
if err := w.WriteByte1Int(12); err != nil {
return err
}
if err := w.WriteByte1Int(def.TimeStamp); err != nil {
return err
}
if err := w.WriteByte4Int(t.Nanosecond()); err != nil {
return err
}
if err := w.WriteByte8Uint64(secs); err != nil {
return err
}
return nil
}
+8
View File
@@ -0,0 +1,8 @@
package time
var decodeAsLocal = true
// SetDecodedAsLocal sets the decoded time to local time.
func SetDecodedAsLocal(b bool) {
decodeAsLocal = b
}