├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── config.yml └── workflows │ ├── build.yml │ ├── commitlint.yml │ └── release.yml ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Makefile ├── README.md ├── bench_test.go ├── commitlint.config.js ├── decode.go ├── decode_map.go ├── decode_number.go ├── decode_query.go ├── decode_slice.go ├── decode_string.go ├── decode_typgen.go ├── decode_value.go ├── encode.go ├── encode_map.go ├── encode_number.go ├── encode_slice.go ├── encode_value.go ├── example_CustomEncoder_test.go ├── example_registerExt_test.go ├── example_test.go ├── ext.go ├── ext_test.go ├── extra └── msgpappengine │ ├── appengine.go │ ├── go.mod │ └── go.sum ├── go.mod ├── go.sum ├── intern.go ├── intern_test.go ├── msgpack.go ├── msgpack_test.go ├── msgpcode └── msgpcode.go ├── package.json ├── safe.go ├── time.go ├── types.go ├── types_test.go ├── unsafe.go └── version.go /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ['https://uptrace.dev/sponsor'] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | --- 8 | 9 | Issue tracker is used for reporting bugs and discussing new features. Please use 10 | [Discord](https://discord.gg/rWtp5Aj) or [stackoverflow](https://stackoverflow.com) for supporting 11 | issues. 12 | 13 | 14 | 15 | ## Expected Behavior 16 | 17 | 18 | 19 | ## Current Behavior 20 | 21 | 22 | 23 | ## Possible Solution 24 | 25 | 26 | 27 | ## Steps to Reproduce 28 | 29 | 30 | 31 | 32 | 1. 33 | 2. 34 | 3. 35 | 4. 36 | 37 | ## Context (Environment) 38 | 39 | 40 | 41 | 42 | 43 | 44 | ## Detailed Description 45 | 46 | 47 | 48 | ## Possible Implementation 49 | 50 | 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord 4 | url: https://discord.gg/rWtp5Aj 5 | about: Ask a question at Discord 6 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Go 2 | 3 | on: 4 | push: 5 | branches: [v5] 6 | pull_request: 7 | branches: [v5] 8 | 9 | jobs: 10 | build: 11 | name: build 12 | runs-on: ubuntu-latest 13 | strategy: 14 | matrix: 15 | go-version: [1.21.x] 16 | 17 | steps: 18 | - name: Set up ${{ matrix.go-version }} 19 | uses: actions/setup-go@v2 20 | with: 21 | go-version: ${{ matrix.go-version }} 22 | 23 | - name: Checkout code 24 | uses: actions/checkout@v2 25 | 26 | - name: Test 27 | run: make test 28 | -------------------------------------------------------------------------------- /.github/workflows/commitlint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Commit Messages 2 | on: [pull_request] 3 | 4 | jobs: 5 | commitlint: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v2 9 | with: 10 | fetch-depth: 0 11 | - uses: wagoid/commitlint-github-action@v4 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Releases 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: ncipollo/release-action@v1 14 | with: 15 | body: 16 | Please refer to 17 | [CHANGELOG.md](https://github.com/vmihailenco/msgpack/blob/v5/CHANGELOG.md) for details 18 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | semi: false 2 | singleQuote: true 3 | proseWrap: always 4 | printWidth: 100 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: go 3 | 4 | go: 5 | - 1.15.x 6 | - 1.16.x 7 | - tip 8 | 9 | matrix: 10 | allow_failures: 11 | - go: tip 12 | 13 | env: 14 | - GO111MODULE=on 15 | 16 | go_import_path: github.com/vmihailenco/msgpack 17 | 18 | before_install: 19 | - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go 20 | env GOPATH)/bin v1.31.0 21 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [5.4.1](https://github.com/vmihailenco/msgpack/compare/v5.4.0...v5.4.1) (2023-10-26) 2 | 3 | 4 | ### Bug Fixes 5 | 6 | * **reflect:** not assignable to type ([edeaedd](https://github.com/vmihailenco/msgpack/commit/edeaeddb2d51868df8c6ff2d8a218b527aeaf5fd)) 7 | 8 | 9 | 10 | # [5.4.0](https://github.com/vmihailenco/msgpack/compare/v5.3.6...v5.4.0) (2023-10-01) 11 | 12 | 13 | 14 | ## [5.3.6](https://github.com/vmihailenco/msgpack/compare/v5.3.5...v5.3.6) (2023-10-01) 15 | 16 | 17 | ### Features 18 | 19 | * allow overwriting time.Time parsing from extID 13 (for NodeJS Date) ([9a6b73b](https://github.com/vmihailenco/msgpack/commit/9a6b73b3588fd962d568715f4375e24b089f7066)) 20 | * apply omitEmptyFlag to empty structs ([e5f8d03](https://github.com/vmihailenco/msgpack/commit/e5f8d03c0a1dd9cc571d648cd610305139078de5)) 21 | * support sorted keys for map[string]bool ([690c1fa](https://github.com/vmihailenco/msgpack/commit/690c1fab9814fab4842295ea986111f49850d9a4)) 22 | 23 | 24 | 25 | ## [5.3.5](https://github.com/vmihailenco/msgpack/compare/v5.3.4...v5.3.5) (2021-10-22) 26 | 27 | - Allow decoding `nil` code as boolean false. 28 | 29 | ## v5 30 | 31 | ### Added 32 | 33 | - `DecodeMap` is split into `DecodeMap`, `DecodeTypedMap`, and `DecodeUntypedMap`. 34 | - New msgpack extensions API. 35 | 36 | ### Changed 37 | 38 | - `Reset*` functions also reset flags. 39 | - `SetMapDecodeFunc` is renamed to `SetMapDecoder`. 40 | - `StructAsArray` is renamed to `UseArrayEncodedStructs`. 41 | - `SortMapKeys` is renamed to `SetSortMapKeys`. 42 | 43 | ### Removed 44 | 45 | - `UseJSONTag` is removed. Use `SetCustomStructTag("json")` instead. 46 | 47 | ## v4 48 | 49 | - Encode, Decode, Marshal, and Unmarshal are changed to accept single argument. EncodeMulti and 50 | DecodeMulti are added as replacement. 51 | - Added EncodeInt8/16/32/64 and EncodeUint8/16/32/64. 52 | - Encoder changed to preserve type of numbers instead of chosing most compact encoding. The old 53 | behavior can be achieved with Encoder.UseCompactEncoding. 54 | 55 | ## v3.3 56 | 57 | - `msgpack:",inline"` tag is restored to force inlining structs. 58 | 59 | ## v3.2 60 | 61 | - Decoding extension types returns pointer to the value instead of the value. Fixes #153 62 | 63 | ## v3 64 | 65 | - gopkg.in is not supported any more. Update import path to github.com/vmihailenco/msgpack. 66 | - Msgpack maps are decoded into map[string]interface{} by default. 67 | - EncodeSliceLen is removed in favor of EncodeArrayLen. DecodeSliceLen is removed in favor of 68 | DecodeArrayLen. 69 | - Embedded structs are automatically inlined where possible. 70 | - Time is encoded using extension as described in https://github.com/msgpack/msgpack/pull/209. Old 71 | format is supported as well. 72 | - EncodeInt8/16/32/64 is replaced with EncodeInt. EncodeUint8/16/32/64 is replaced with EncodeUint. 73 | There should be no performance differences. 74 | - DecodeInterface can now return int8/16/32 and uint8/16/32. 75 | - PeekCode returns codes.Code instead of byte. 76 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 The github.com/vmihailenco/msgpack Authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following disclaimer 12 | in the documentation and/or other materials provided with the 13 | distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | go test ./... 3 | go test ./... -short -race 4 | go test ./... -run=NONE -bench=. -benchmem 5 | env GOOS=linux GOARCH=386 go test ./... 6 | go vet 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MessagePack encoding for Golang 2 | 3 | [![Build Status](https://travis-ci.org/vmihailenco/msgpack.svg)](https://travis-ci.org/vmihailenco/msgpack) 4 | [![PkgGoDev](https://pkg.go.dev/badge/github.com/vmihailenco/msgpack/v5)](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) 5 | [![Documentation](https://img.shields.io/badge/msgpack-documentation-informational)](https://msgpack.uptrace.dev/) 6 | [![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj) 7 | 8 | > msgpack is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace). 9 | > Uptrace is an [open source APM](https://uptrace.dev/get/open-source-apm.html) and blazingly fast 10 | > [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered 11 | > by OpenTelemetry and ClickHouse. Give it a star as well! 12 | 13 | ## Resources 14 | 15 | - [Documentation](https://msgpack.uptrace.dev) 16 | - [Chat](https://discord.gg/rWtp5Aj) 17 | - [Reference](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) 18 | - [Examples](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#pkg-examples) 19 | 20 | ## Features 21 | 22 | - Primitives, arrays, maps, structs, time.Time and interface{}. 23 | - Appengine \*datastore.Key and datastore.Cursor. 24 | - [CustomEncoder]/[CustomDecoder] interfaces for custom encoding. 25 | - [Extensions](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-RegisterExt) to encode 26 | type information. 27 | - Renaming fields via `msgpack:"my_field_name"` and alias via `msgpack:"alias:another_name"`. 28 | - Omitting individual empty fields via `msgpack:",omitempty"` tag or all 29 | [empty fields in a struct](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-OmitEmpty). 30 | - [Map keys sorting](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetSortMapKeys). 31 | - Encoding/decoding all 32 | [structs as arrays](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.UseArrayEncodedStructs) 33 | or 34 | [individual structs](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Marshal-AsArray). 35 | - [Encoder.SetCustomStructTag] with [Decoder.SetCustomStructTag] can turn msgpack into drop-in 36 | replacement for any tag. 37 | - Simple but very fast and efficient 38 | [queries](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#example-Decoder.Query). 39 | 40 | [customencoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomEncoder 41 | [customdecoder]: https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#CustomDecoder 42 | [encoder.setcustomstructtag]: 43 | https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Encoder.SetCustomStructTag 44 | [decoder.setcustomstructtag]: 45 | https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#Decoder.SetCustomStructTag 46 | 47 | ## Installation 48 | 49 | msgpack supports 2 last Go versions and requires support for 50 | [Go modules](https://github.com/golang/go/wiki/Modules). So make sure to initialize a Go module: 51 | 52 | ```shell 53 | go mod init github.com/my/repo 54 | ``` 55 | 56 | And then install msgpack/v5 (note _v5_ in the import; omitting it is a popular mistake): 57 | 58 | ```shell 59 | go get github.com/vmihailenco/msgpack/v5 60 | ``` 61 | 62 | ## Quickstart 63 | 64 | ```go 65 | import "github.com/vmihailenco/msgpack/v5" 66 | 67 | func ExampleMarshal() { 68 | type Item struct { 69 | Foo string 70 | } 71 | 72 | b, err := msgpack.Marshal(&Item{Foo: "bar"}) 73 | if err != nil { 74 | panic(err) 75 | } 76 | 77 | var item Item 78 | err = msgpack.Unmarshal(b, &item) 79 | if err != nil { 80 | panic(err) 81 | } 82 | fmt.Println(item.Foo) 83 | // Output: bar 84 | } 85 | ``` 86 | 87 | ## See also 88 | 89 | - [Golang ORM](https://github.com/uptrace/bun) for PostgreSQL, MySQL, MSSQL, and SQLite 90 | - [Golang PostgreSQL](https://bun.uptrace.dev/postgres/) 91 | - [Golang HTTP router](https://github.com/uptrace/bunrouter) 92 | - [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse) 93 | 94 | ## Contributors 95 | 96 | Thanks to all the people who already contributed! 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "io/ioutil" 7 | "math" 8 | "testing" 9 | "time" 10 | 11 | "github.com/vmihailenco/msgpack/v5" 12 | ) 13 | 14 | func BenchmarkDiscard(b *testing.B) { 15 | enc := msgpack.NewEncoder(ioutil.Discard) 16 | 17 | b.ResetTimer() 18 | 19 | for i := 0; i < b.N; i++ { 20 | if err := enc.Encode(nil); err != nil { 21 | b.Fatal(err) 22 | } 23 | if err := enc.Encode("hello"); err != nil { 24 | b.Fatal(err) 25 | } 26 | } 27 | } 28 | 29 | func benchmarkEncodeDecode(b *testing.B, src, dst interface{}) { 30 | var buf bytes.Buffer 31 | enc := msgpack.NewEncoder(&buf) 32 | dec := msgpack.NewDecoder(&buf) 33 | 34 | b.ResetTimer() 35 | 36 | for i := 0; i < b.N; i++ { 37 | if err := enc.Encode(src); err != nil { 38 | b.Fatal(err) 39 | } 40 | if err := dec.Decode(dst); err != nil { 41 | b.Fatal(err) 42 | } 43 | } 44 | } 45 | 46 | func benchmarkJSONEncodeDecode(b *testing.B, src, dst interface{}) { 47 | var buf bytes.Buffer 48 | enc := json.NewEncoder(&buf) 49 | dec := json.NewDecoder(&buf) 50 | 51 | b.ResetTimer() 52 | 53 | for i := 0; i < b.N; i++ { 54 | if err := enc.Encode(src); err != nil { 55 | b.Fatal(err) 56 | } 57 | if err := dec.Decode(dst); err != nil { 58 | b.Fatal(err) 59 | } 60 | } 61 | } 62 | 63 | func BenchmarkBool(b *testing.B) { 64 | var dst bool 65 | benchmarkEncodeDecode(b, true, &dst) 66 | } 67 | 68 | func BenchmarkInt0(b *testing.B) { 69 | var dst int 70 | benchmarkEncodeDecode(b, 1, &dst) 71 | } 72 | 73 | func BenchmarkInt1(b *testing.B) { 74 | var dst int 75 | benchmarkEncodeDecode(b, -33, &dst) 76 | } 77 | 78 | func BenchmarkInt2(b *testing.B) { 79 | var dst int 80 | benchmarkEncodeDecode(b, 128, &dst) 81 | } 82 | 83 | func BenchmarkInt4(b *testing.B) { 84 | var dst int 85 | benchmarkEncodeDecode(b, 32768, &dst) 86 | } 87 | 88 | func BenchmarkInt8(b *testing.B) { 89 | var dst int 90 | benchmarkEncodeDecode(b, int64(2147483648), &dst) 91 | } 92 | 93 | func BenchmarkInt32(b *testing.B) { 94 | var dst int32 95 | benchmarkEncodeDecode(b, int32(0), &dst) 96 | } 97 | 98 | func BenchmarkFloat32(b *testing.B) { 99 | var dst float32 100 | benchmarkEncodeDecode(b, float32(0), &dst) 101 | } 102 | 103 | func BenchmarkFloat32_Max(b *testing.B) { 104 | var dst float32 105 | benchmarkEncodeDecode(b, float32(math.MaxFloat32), &dst) 106 | } 107 | 108 | func BenchmarkFloat64(b *testing.B) { 109 | var dst float64 110 | benchmarkEncodeDecode(b, float64(0), &dst) 111 | } 112 | 113 | func BenchmarkFloat64_Max(b *testing.B) { 114 | var dst float64 115 | benchmarkEncodeDecode(b, float64(math.MaxFloat64), &dst) 116 | } 117 | 118 | func BenchmarkTime(b *testing.B) { 119 | var dst time.Time 120 | benchmarkEncodeDecode(b, time.Now(), &dst) 121 | } 122 | 123 | func BenchmarkDuration(b *testing.B) { 124 | var dst time.Duration 125 | benchmarkEncodeDecode(b, time.Hour, &dst) 126 | } 127 | 128 | func BenchmarkByteSlice(b *testing.B) { 129 | src := make([]byte, 1024) 130 | var dst []byte 131 | benchmarkEncodeDecode(b, src, &dst) 132 | } 133 | 134 | func BenchmarkByteArray(b *testing.B) { 135 | var src [1024]byte 136 | var dst [1024]byte 137 | benchmarkEncodeDecode(b, src, &dst) 138 | } 139 | 140 | func BenchmarkByteArrayPtr(b *testing.B) { 141 | var src [1024]byte 142 | var dst [1024]byte 143 | benchmarkEncodeDecode(b, &src, &dst) 144 | } 145 | 146 | func BenchmarkMapStringString(b *testing.B) { 147 | src := map[string]string{ 148 | "hello": "world", 149 | "foo": "bar", 150 | } 151 | var dst map[string]string 152 | benchmarkEncodeDecode(b, src, &dst) 153 | } 154 | 155 | func BenchmarkMapStringStringPtr(b *testing.B) { 156 | src := map[string]string{ 157 | "hello": "world", 158 | "foo": "bar", 159 | } 160 | dst := new(map[string]string) 161 | benchmarkEncodeDecode(b, src, &dst) 162 | } 163 | 164 | func BenchmarkMapStringInterfaceMsgpack(b *testing.B) { 165 | src := map[string]interface{}{ 166 | "hello": "world", 167 | "foo": "bar", 168 | "one": 1111111, 169 | "two": 2222222, 170 | } 171 | var dst map[string]interface{} 172 | benchmarkEncodeDecode(b, src, &dst) 173 | } 174 | 175 | func BenchmarkMapStringInterfaceJSON(b *testing.B) { 176 | src := map[string]interface{}{ 177 | "hello": "world", 178 | "foo": "bar", 179 | "one": 1111111, 180 | "two": 2222222, 181 | } 182 | var dst map[string]interface{} 183 | benchmarkJSONEncodeDecode(b, src, &dst) 184 | } 185 | 186 | func BenchmarkMapIntInt(b *testing.B) { 187 | src := map[int]int{ 188 | 1: 10, 189 | 2: 20, 190 | } 191 | var dst map[int]int 192 | benchmarkEncodeDecode(b, src, &dst) 193 | } 194 | 195 | func BenchmarkStringSlice(b *testing.B) { 196 | src := []string{"hello", "world"} 197 | var dst []string 198 | benchmarkEncodeDecode(b, src, &dst) 199 | } 200 | 201 | func BenchmarkStringSlicePtr(b *testing.B) { 202 | src := []string{"hello", "world"} 203 | var dst []string 204 | dstptr := &dst 205 | benchmarkEncodeDecode(b, src, &dstptr) 206 | } 207 | 208 | type benchmarkStruct struct { 209 | Name string 210 | Age int 211 | Colors []string 212 | Data []byte 213 | CreatedAt time.Time 214 | UpdatedAt time.Time 215 | } 216 | 217 | type benchmarkStruct2 struct { 218 | Name string 219 | Age int 220 | Colors []string 221 | Data []byte 222 | CreatedAt time.Time 223 | UpdatedAt time.Time 224 | } 225 | 226 | var ( 227 | _ msgpack.CustomEncoder = (*benchmarkStruct2)(nil) 228 | _ msgpack.CustomDecoder = (*benchmarkStruct2)(nil) 229 | ) 230 | 231 | func (s *benchmarkStruct2) EncodeMsgpack(enc *msgpack.Encoder) error { 232 | return enc.EncodeMulti( 233 | s.Name, 234 | s.Colors, 235 | s.Age, 236 | s.Data, 237 | s.CreatedAt, 238 | s.UpdatedAt, 239 | ) 240 | } 241 | 242 | func (s *benchmarkStruct2) DecodeMsgpack(dec *msgpack.Decoder) error { 243 | return dec.DecodeMulti( 244 | &s.Name, 245 | &s.Colors, 246 | &s.Age, 247 | &s.Data, 248 | &s.CreatedAt, 249 | &s.UpdatedAt, 250 | ) 251 | } 252 | 253 | func structForBenchmark() *benchmarkStruct { 254 | return &benchmarkStruct{ 255 | Name: "Hello World", 256 | Colors: []string{"red", "orange", "yellow", "green", "blue", "violet"}, 257 | Age: math.MaxInt32, 258 | Data: make([]byte, 1024), 259 | CreatedAt: time.Now(), 260 | UpdatedAt: time.Now(), 261 | } 262 | } 263 | 264 | func structForBenchmark2() *benchmarkStruct2 { 265 | return &benchmarkStruct2{ 266 | Name: "Hello World", 267 | Colors: []string{"red", "orange", "yellow", "green", "blue", "violet"}, 268 | Age: math.MaxInt32, 269 | Data: make([]byte, 1024), 270 | CreatedAt: time.Now(), 271 | UpdatedAt: time.Now(), 272 | } 273 | } 274 | 275 | func BenchmarkStructVmihailencoMsgpack(b *testing.B) { 276 | in := structForBenchmark() 277 | out := new(benchmarkStruct) 278 | 279 | b.ResetTimer() 280 | 281 | for i := 0; i < b.N; i++ { 282 | buf, err := msgpack.Marshal(in) 283 | if err != nil { 284 | b.Fatal(err) 285 | } 286 | 287 | err = msgpack.Unmarshal(buf, out) 288 | if err != nil { 289 | b.Fatal(err) 290 | } 291 | } 292 | } 293 | 294 | func BenchmarkStructMarshal(b *testing.B) { 295 | in := structForBenchmark() 296 | 297 | b.ResetTimer() 298 | 299 | for i := 0; i < b.N; i++ { 300 | _, err := msgpack.Marshal(in) 301 | if err != nil { 302 | b.Fatal(err) 303 | } 304 | } 305 | } 306 | 307 | func BenchmarkStructUnmarshal(b *testing.B) { 308 | in := structForBenchmark() 309 | buf, err := msgpack.Marshal(in) 310 | if err != nil { 311 | b.Fatal(err) 312 | } 313 | out := new(benchmarkStruct) 314 | 315 | b.ResetTimer() 316 | 317 | for i := 0; i < b.N; i++ { 318 | err = msgpack.Unmarshal(buf, out) 319 | if err != nil { 320 | b.Fatal(err) 321 | } 322 | } 323 | } 324 | 325 | func BenchmarkStructManual(b *testing.B) { 326 | in := structForBenchmark2() 327 | out := new(benchmarkStruct2) 328 | 329 | b.ResetTimer() 330 | 331 | for i := 0; i < b.N; i++ { 332 | buf, err := msgpack.Marshal(in) 333 | if err != nil { 334 | b.Fatal(err) 335 | } 336 | 337 | err = msgpack.Unmarshal(buf, out) 338 | if err != nil { 339 | b.Fatal(err) 340 | } 341 | } 342 | } 343 | 344 | type benchmarkStructPartially struct { 345 | Name string 346 | Age int 347 | } 348 | 349 | func BenchmarkStructUnmarshalPartially(b *testing.B) { 350 | in := structForBenchmark() 351 | buf, err := msgpack.Marshal(in) 352 | if err != nil { 353 | b.Fatal(err) 354 | } 355 | out := new(benchmarkStructPartially) 356 | 357 | b.ResetTimer() 358 | 359 | for i := 0; i < b.N; i++ { 360 | err = msgpack.Unmarshal(buf, out) 361 | if err != nil { 362 | b.Fatal(err) 363 | } 364 | } 365 | } 366 | 367 | func BenchmarkQuery(b *testing.B) { 368 | var records []map[string]interface{} 369 | for i := 0; i < 1000; i++ { 370 | record := map[string]interface{}{ 371 | "id": int64(i), 372 | "attrs": map[string]interface{}{"phone": int64(i)}, 373 | } 374 | records = append(records, record) 375 | } 376 | 377 | bs, err := msgpack.Marshal(records) 378 | if err != nil { 379 | b.Fatal(err) 380 | } 381 | 382 | dec := msgpack.NewDecoder(bytes.NewBuffer(bs)) 383 | 384 | b.ResetTimer() 385 | 386 | for i := 0; i < b.N; i++ { 387 | dec.Reset(bytes.NewBuffer(bs)) 388 | 389 | values, err := dec.Query("10.attrs.phone") 390 | if err != nil { 391 | b.Fatal(err) 392 | } 393 | if values[0].(int64) != 10 { 394 | b.Fatalf("%v != %d", values[0], 10) 395 | } 396 | } 397 | } 398 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] } 2 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "reflect" 10 | "sync" 11 | "time" 12 | 13 | "github.com/vmihailenco/msgpack/v5/msgpcode" 14 | ) 15 | 16 | const ( 17 | bytesAllocLimit = 1 << 20 // 1mb 18 | sliceAllocLimit = 1e6 // 1m elements 19 | maxMapSize = 1e6 // 1m elements 20 | ) 21 | 22 | const ( 23 | looseInterfaceDecodingFlag uint32 = 1 << iota 24 | disallowUnknownFieldsFlag 25 | usePreallocateValues 26 | disableAllocLimitFlag 27 | ) 28 | 29 | type bufReader interface { 30 | io.Reader 31 | io.ByteScanner 32 | } 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | var decPool = sync.Pool{ 37 | New: func() interface{} { 38 | return NewDecoder(nil) 39 | }, 40 | } 41 | 42 | func GetDecoder() *Decoder { 43 | return decPool.Get().(*Decoder) 44 | } 45 | 46 | func PutDecoder(dec *Decoder) { 47 | dec.r = nil 48 | dec.s = nil 49 | decPool.Put(dec) 50 | } 51 | 52 | //------------------------------------------------------------------------------ 53 | 54 | // Unmarshal decodes the MessagePack-encoded data and stores the result 55 | // in the value pointed to by v. 56 | func Unmarshal(data []byte, v interface{}) error { 57 | dec := GetDecoder() 58 | dec.UsePreallocateValues(true) 59 | dec.Reset(bytes.NewReader(data)) 60 | err := dec.Decode(v) 61 | 62 | PutDecoder(dec) 63 | 64 | return err 65 | } 66 | 67 | // A Decoder reads and decodes MessagePack values from an input stream. 68 | type Decoder struct { 69 | r io.Reader 70 | s io.ByteScanner 71 | mapDecoder func(*Decoder) (interface{}, error) 72 | structTag string 73 | buf []byte 74 | rec []byte 75 | dict []string 76 | flags uint32 77 | } 78 | 79 | // NewDecoder returns a new decoder that reads from r. 80 | // 81 | // The decoder introduces its own buffering and may read data from r 82 | // beyond the requested msgpack values. Buffering can be disabled 83 | // by passing a reader that implements io.ByteScanner interface. 84 | func NewDecoder(r io.Reader) *Decoder { 85 | d := new(Decoder) 86 | d.Reset(r) 87 | return d 88 | } 89 | 90 | // Reset discards any buffered data, resets all state, and switches the buffered 91 | // reader to read from r. 92 | func (d *Decoder) Reset(r io.Reader) { 93 | d.ResetDict(r, nil) 94 | } 95 | 96 | // ResetDict is like Reset, but also resets the dict. 97 | func (d *Decoder) ResetDict(r io.Reader, dict []string) { 98 | d.ResetReader(r) 99 | d.flags = 0 100 | d.structTag = "" 101 | d.dict = dict 102 | } 103 | 104 | func (d *Decoder) WithDict(dict []string, fn func(*Decoder) error) error { 105 | oldDict := d.dict 106 | d.dict = dict 107 | err := fn(d) 108 | d.dict = oldDict 109 | return err 110 | } 111 | 112 | func (d *Decoder) ResetReader(r io.Reader) { 113 | d.mapDecoder = nil 114 | d.dict = nil 115 | 116 | if br, ok := r.(bufReader); ok { 117 | d.r = br 118 | d.s = br 119 | } else if r == nil { 120 | d.r = nil 121 | d.s = nil 122 | } else { 123 | br := bufio.NewReader(r) 124 | d.r = br 125 | d.s = br 126 | } 127 | } 128 | 129 | func (d *Decoder) SetMapDecoder(fn func(*Decoder) (interface{}, error)) { 130 | d.mapDecoder = fn 131 | } 132 | 133 | // UseLooseInterfaceDecoding causes decoder to use DecodeInterfaceLoose 134 | // to decode msgpack value into Go interface{}. 135 | func (d *Decoder) UseLooseInterfaceDecoding(on bool) { 136 | if on { 137 | d.flags |= looseInterfaceDecodingFlag 138 | } else { 139 | d.flags &= ^looseInterfaceDecodingFlag 140 | } 141 | } 142 | 143 | // SetCustomStructTag causes the decoder to use the supplied tag as a fallback option 144 | // if there is no msgpack tag. 145 | func (d *Decoder) SetCustomStructTag(tag string) { 146 | d.structTag = tag 147 | } 148 | 149 | // DisallowUnknownFields causes the Decoder to return an error when the destination 150 | // is a struct and the input contains object keys which do not match any 151 | // non-ignored, exported fields in the destination. 152 | func (d *Decoder) DisallowUnknownFields(on bool) { 153 | if on { 154 | d.flags |= disallowUnknownFieldsFlag 155 | } else { 156 | d.flags &= ^disallowUnknownFieldsFlag 157 | } 158 | } 159 | 160 | // UseInternedStrings enables support for decoding interned strings. 161 | func (d *Decoder) UseInternedStrings(on bool) { 162 | if on { 163 | d.flags |= useInternedStringsFlag 164 | } else { 165 | d.flags &= ^useInternedStringsFlag 166 | } 167 | } 168 | 169 | // UsePreallocateValues enables preallocating values in chunks 170 | func (d *Decoder) UsePreallocateValues(on bool) { 171 | if on { 172 | d.flags |= usePreallocateValues 173 | } else { 174 | d.flags &= ^usePreallocateValues 175 | } 176 | } 177 | 178 | // DisableAllocLimit enables fully allocating slices/maps when the size is known 179 | func (d *Decoder) DisableAllocLimit(on bool) { 180 | if on { 181 | d.flags |= disableAllocLimitFlag 182 | } else { 183 | d.flags &= ^disableAllocLimitFlag 184 | } 185 | } 186 | 187 | // Buffered returns a reader of the data remaining in the Decoder's buffer. 188 | // The reader is valid until the next call to Decode. 189 | func (d *Decoder) Buffered() io.Reader { 190 | return d.r 191 | } 192 | 193 | //nolint:gocyclo 194 | func (d *Decoder) Decode(v interface{}) error { 195 | var err error 196 | switch v := v.(type) { 197 | case *string: 198 | if v != nil { 199 | *v, err = d.DecodeString() 200 | return err 201 | } 202 | case *[]byte: 203 | if v != nil { 204 | return d.decodeBytesPtr(v) 205 | } 206 | case *int: 207 | if v != nil { 208 | *v, err = d.DecodeInt() 209 | return err 210 | } 211 | case *int8: 212 | if v != nil { 213 | *v, err = d.DecodeInt8() 214 | return err 215 | } 216 | case *int16: 217 | if v != nil { 218 | *v, err = d.DecodeInt16() 219 | return err 220 | } 221 | case *int32: 222 | if v != nil { 223 | *v, err = d.DecodeInt32() 224 | return err 225 | } 226 | case *int64: 227 | if v != nil { 228 | *v, err = d.DecodeInt64() 229 | return err 230 | } 231 | case *uint: 232 | if v != nil { 233 | *v, err = d.DecodeUint() 234 | return err 235 | } 236 | case *uint8: 237 | if v != nil { 238 | *v, err = d.DecodeUint8() 239 | return err 240 | } 241 | case *uint16: 242 | if v != nil { 243 | *v, err = d.DecodeUint16() 244 | return err 245 | } 246 | case *uint32: 247 | if v != nil { 248 | *v, err = d.DecodeUint32() 249 | return err 250 | } 251 | case *uint64: 252 | if v != nil { 253 | *v, err = d.DecodeUint64() 254 | return err 255 | } 256 | case *bool: 257 | if v != nil { 258 | *v, err = d.DecodeBool() 259 | return err 260 | } 261 | case *float32: 262 | if v != nil { 263 | *v, err = d.DecodeFloat32() 264 | return err 265 | } 266 | case *float64: 267 | if v != nil { 268 | *v, err = d.DecodeFloat64() 269 | return err 270 | } 271 | case *[]string: 272 | return d.decodeStringSlicePtr(v) 273 | case *map[string]string: 274 | return d.decodeMapStringStringPtr(v) 275 | case *map[string]interface{}: 276 | return d.decodeMapStringInterfacePtr(v) 277 | case *time.Duration: 278 | if v != nil { 279 | vv, err := d.DecodeInt64() 280 | *v = time.Duration(vv) 281 | return err 282 | } 283 | case *time.Time: 284 | if v != nil { 285 | *v, err = d.DecodeTime() 286 | return err 287 | } 288 | } 289 | 290 | vv := reflect.ValueOf(v) 291 | if !vv.IsValid() { 292 | return errors.New("msgpack: Decode(nil)") 293 | } 294 | if vv.Kind() != reflect.Ptr { 295 | return fmt.Errorf("msgpack: Decode(non-pointer %T)", v) 296 | } 297 | if vv.IsNil() { 298 | return fmt.Errorf("msgpack: Decode(non-settable %T)", v) 299 | } 300 | 301 | vv = vv.Elem() 302 | if vv.Kind() == reflect.Interface { 303 | if !vv.IsNil() { 304 | vv = vv.Elem() 305 | if vv.Kind() != reflect.Ptr { 306 | return fmt.Errorf("msgpack: Decode(non-pointer %s)", vv.Type().String()) 307 | } 308 | } 309 | } 310 | 311 | return d.DecodeValue(vv) 312 | } 313 | 314 | func (d *Decoder) DecodeMulti(v ...interface{}) error { 315 | for _, vv := range v { 316 | if err := d.Decode(vv); err != nil { 317 | return err 318 | } 319 | } 320 | return nil 321 | } 322 | 323 | func (d *Decoder) decodeInterfaceCond() (interface{}, error) { 324 | if d.flags&looseInterfaceDecodingFlag != 0 { 325 | return d.DecodeInterfaceLoose() 326 | } 327 | return d.DecodeInterface() 328 | } 329 | 330 | func (d *Decoder) DecodeValue(v reflect.Value) error { 331 | decode := getDecoder(v.Type()) 332 | return decode(d, v) 333 | } 334 | 335 | func (d *Decoder) DecodeNil() error { 336 | c, err := d.readCode() 337 | if err != nil { 338 | return err 339 | } 340 | if c != msgpcode.Nil { 341 | return fmt.Errorf("msgpack: invalid code=%x decoding nil", c) 342 | } 343 | return nil 344 | } 345 | 346 | func (d *Decoder) decodeNilValue(v reflect.Value) error { 347 | err := d.DecodeNil() 348 | if v.IsNil() { 349 | return err 350 | } 351 | if v.Kind() == reflect.Ptr { 352 | v = v.Elem() 353 | } 354 | v.Set(reflect.Zero(v.Type())) 355 | return err 356 | } 357 | 358 | func (d *Decoder) DecodeBool() (bool, error) { 359 | c, err := d.readCode() 360 | if err != nil { 361 | return false, err 362 | } 363 | return d.bool(c) 364 | } 365 | 366 | func (d *Decoder) bool(c byte) (bool, error) { 367 | if c == msgpcode.Nil { 368 | return false, nil 369 | } 370 | if c == msgpcode.False { 371 | return false, nil 372 | } 373 | if c == msgpcode.True { 374 | return true, nil 375 | } 376 | return false, fmt.Errorf("msgpack: invalid code=%x decoding bool", c) 377 | } 378 | 379 | func (d *Decoder) DecodeDuration() (time.Duration, error) { 380 | n, err := d.DecodeInt64() 381 | if err != nil { 382 | return 0, err 383 | } 384 | return time.Duration(n), nil 385 | } 386 | 387 | // DecodeInterface decodes value into interface. It returns following types: 388 | // - nil, 389 | // - bool, 390 | // - int8, int16, int32, int64, 391 | // - uint8, uint16, uint32, uint64, 392 | // - float32 and float64, 393 | // - string, 394 | // - []byte, 395 | // - slices of any of the above, 396 | // - maps of any of the above. 397 | // 398 | // DecodeInterface should be used only when you don't know the type of value 399 | // you are decoding. For example, if you are decoding number it is better to use 400 | // DecodeInt64 for negative numbers and DecodeUint64 for positive numbers. 401 | func (d *Decoder) DecodeInterface() (interface{}, error) { 402 | c, err := d.readCode() 403 | if err != nil { 404 | return nil, err 405 | } 406 | 407 | if msgpcode.IsFixedNum(c) { 408 | return int8(c), nil 409 | } 410 | if msgpcode.IsFixedMap(c) { 411 | err = d.s.UnreadByte() 412 | if err != nil { 413 | return nil, err 414 | } 415 | return d.decodeMapDefault() 416 | } 417 | if msgpcode.IsFixedArray(c) { 418 | return d.decodeSlice(c) 419 | } 420 | if msgpcode.IsFixedString(c) { 421 | return d.string(c) 422 | } 423 | 424 | switch c { 425 | case msgpcode.Nil: 426 | return nil, nil 427 | case msgpcode.False, msgpcode.True: 428 | return d.bool(c) 429 | case msgpcode.Float: 430 | return d.float32(c) 431 | case msgpcode.Double: 432 | return d.float64(c) 433 | case msgpcode.Uint8: 434 | return d.uint8() 435 | case msgpcode.Uint16: 436 | return d.uint16() 437 | case msgpcode.Uint32: 438 | return d.uint32() 439 | case msgpcode.Uint64: 440 | return d.uint64() 441 | case msgpcode.Int8: 442 | return d.int8() 443 | case msgpcode.Int16: 444 | return d.int16() 445 | case msgpcode.Int32: 446 | return d.int32() 447 | case msgpcode.Int64: 448 | return d.int64() 449 | case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: 450 | return d.bytes(c, nil) 451 | case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32: 452 | return d.string(c) 453 | case msgpcode.Array16, msgpcode.Array32: 454 | return d.decodeSlice(c) 455 | case msgpcode.Map16, msgpcode.Map32: 456 | err = d.s.UnreadByte() 457 | if err != nil { 458 | return nil, err 459 | } 460 | return d.decodeMapDefault() 461 | case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, 462 | msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: 463 | return d.decodeInterfaceExt(c) 464 | } 465 | 466 | return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c) 467 | } 468 | 469 | // DecodeInterfaceLoose is like DecodeInterface except that: 470 | // - int8, int16, and int32 are converted to int64, 471 | // - uint8, uint16, and uint32 are converted to uint64, 472 | // - float32 is converted to float64. 473 | // - []byte is converted to string. 474 | func (d *Decoder) DecodeInterfaceLoose() (interface{}, error) { 475 | c, err := d.readCode() 476 | if err != nil { 477 | return nil, err 478 | } 479 | 480 | if msgpcode.IsFixedNum(c) { 481 | return int64(int8(c)), nil 482 | } 483 | if msgpcode.IsFixedMap(c) { 484 | err = d.s.UnreadByte() 485 | if err != nil { 486 | return nil, err 487 | } 488 | return d.decodeMapDefault() 489 | } 490 | if msgpcode.IsFixedArray(c) { 491 | return d.decodeSlice(c) 492 | } 493 | if msgpcode.IsFixedString(c) { 494 | return d.string(c) 495 | } 496 | 497 | switch c { 498 | case msgpcode.Nil: 499 | return nil, nil 500 | case msgpcode.False, msgpcode.True: 501 | return d.bool(c) 502 | case msgpcode.Float, msgpcode.Double: 503 | return d.float64(c) 504 | case msgpcode.Uint8, msgpcode.Uint16, msgpcode.Uint32, msgpcode.Uint64: 505 | return d.uint(c) 506 | case msgpcode.Int8, msgpcode.Int16, msgpcode.Int32, msgpcode.Int64: 507 | return d.int(c) 508 | case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32, 509 | msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: 510 | return d.string(c) 511 | case msgpcode.Array16, msgpcode.Array32: 512 | return d.decodeSlice(c) 513 | case msgpcode.Map16, msgpcode.Map32: 514 | err = d.s.UnreadByte() 515 | if err != nil { 516 | return nil, err 517 | } 518 | return d.decodeMapDefault() 519 | case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, 520 | msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: 521 | return d.decodeInterfaceExt(c) 522 | } 523 | 524 | return 0, fmt.Errorf("msgpack: unknown code %x decoding interface{}", c) 525 | } 526 | 527 | // Skip skips next value. 528 | func (d *Decoder) Skip() error { 529 | c, err := d.readCode() 530 | if err != nil { 531 | return err 532 | } 533 | 534 | if msgpcode.IsFixedNum(c) { 535 | return nil 536 | } 537 | if msgpcode.IsFixedMap(c) { 538 | return d.skipMap(c) 539 | } 540 | if msgpcode.IsFixedArray(c) { 541 | return d.skipSlice(c) 542 | } 543 | if msgpcode.IsFixedString(c) { 544 | return d.skipBytes(c) 545 | } 546 | 547 | switch c { 548 | case msgpcode.Nil, msgpcode.False, msgpcode.True: 549 | return nil 550 | case msgpcode.Uint8, msgpcode.Int8: 551 | return d.skipN(1) 552 | case msgpcode.Uint16, msgpcode.Int16: 553 | return d.skipN(2) 554 | case msgpcode.Uint32, msgpcode.Int32, msgpcode.Float: 555 | return d.skipN(4) 556 | case msgpcode.Uint64, msgpcode.Int64, msgpcode.Double: 557 | return d.skipN(8) 558 | case msgpcode.Bin8, msgpcode.Bin16, msgpcode.Bin32: 559 | return d.skipBytes(c) 560 | case msgpcode.Str8, msgpcode.Str16, msgpcode.Str32: 561 | return d.skipBytes(c) 562 | case msgpcode.Array16, msgpcode.Array32: 563 | return d.skipSlice(c) 564 | case msgpcode.Map16, msgpcode.Map32: 565 | return d.skipMap(c) 566 | case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4, msgpcode.FixExt8, msgpcode.FixExt16, 567 | msgpcode.Ext8, msgpcode.Ext16, msgpcode.Ext32: 568 | return d.skipExt(c) 569 | } 570 | 571 | return fmt.Errorf("msgpack: unknown code %x", c) 572 | } 573 | 574 | func (d *Decoder) DecodeRaw() (RawMessage, error) { 575 | d.rec = make([]byte, 0) 576 | if err := d.Skip(); err != nil { 577 | return nil, err 578 | } 579 | msg := RawMessage(d.rec) 580 | d.rec = nil 581 | return msg, nil 582 | } 583 | 584 | // PeekCode returns the next MessagePack code without advancing the reader. 585 | // Subpackage msgpack/codes defines the list of available msgpcode. 586 | func (d *Decoder) PeekCode() (byte, error) { 587 | c, err := d.s.ReadByte() 588 | if err != nil { 589 | return 0, err 590 | } 591 | return c, d.s.UnreadByte() 592 | } 593 | 594 | // ReadFull reads exactly len(buf) bytes into the buf. 595 | func (d *Decoder) ReadFull(buf []byte) error { 596 | _, err := readN(d.r, buf, len(buf)) 597 | return err 598 | } 599 | 600 | func (d *Decoder) hasNilCode() bool { 601 | code, err := d.PeekCode() 602 | return err == nil && code == msgpcode.Nil 603 | } 604 | 605 | func (d *Decoder) readCode() (byte, error) { 606 | c, err := d.s.ReadByte() 607 | if err != nil { 608 | return 0, err 609 | } 610 | if d.rec != nil { 611 | d.rec = append(d.rec, c) 612 | } 613 | return c, nil 614 | } 615 | 616 | func (d *Decoder) readFull(b []byte) error { 617 | _, err := io.ReadFull(d.r, b) 618 | if err != nil { 619 | return err 620 | } 621 | if d.rec != nil { 622 | d.rec = append(d.rec, b...) 623 | } 624 | return nil 625 | } 626 | 627 | func (d *Decoder) readN(n int) ([]byte, error) { 628 | var err error 629 | if d.flags&disableAllocLimitFlag != 0 { 630 | d.buf, err = readN(d.r, d.buf, n) 631 | } else { 632 | d.buf, err = readNGrow(d.r, d.buf, n) 633 | } 634 | if err != nil { 635 | return nil, err 636 | } 637 | if d.rec != nil { 638 | // TODO: read directly into d.rec? 639 | d.rec = append(d.rec, d.buf...) 640 | } 641 | return d.buf, nil 642 | } 643 | 644 | func readN(r io.Reader, b []byte, n int) ([]byte, error) { 645 | if b == nil { 646 | if n == 0 { 647 | return make([]byte, 0), nil 648 | } 649 | b = make([]byte, 0, n) 650 | } 651 | 652 | if n > cap(b) { 653 | b = append(b, make([]byte, n-len(b))...) 654 | } else if n <= cap(b) { 655 | b = b[:n] 656 | } 657 | 658 | _, err := io.ReadFull(r, b) 659 | return b, err 660 | } 661 | 662 | func readNGrow(r io.Reader, b []byte, n int) ([]byte, error) { 663 | if b == nil { 664 | if n == 0 { 665 | return make([]byte, 0), nil 666 | } 667 | switch { 668 | case n < 64: 669 | b = make([]byte, 0, 64) 670 | case n <= bytesAllocLimit: 671 | b = make([]byte, 0, n) 672 | default: 673 | b = make([]byte, 0, bytesAllocLimit) 674 | } 675 | } 676 | 677 | if n <= cap(b) { 678 | b = b[:n] 679 | _, err := io.ReadFull(r, b) 680 | return b, err 681 | } 682 | b = b[:cap(b)] 683 | 684 | var pos int 685 | for { 686 | alloc := min(n-len(b), bytesAllocLimit) 687 | b = append(b, make([]byte, alloc)...) 688 | 689 | _, err := io.ReadFull(r, b[pos:]) 690 | if err != nil { 691 | return b, err 692 | } 693 | 694 | if len(b) == n { 695 | break 696 | } 697 | pos = len(b) 698 | } 699 | 700 | return b, nil 701 | } 702 | 703 | func min(a, b int) int { //nolint:unparam 704 | if a <= b { 705 | return a 706 | } 707 | return b 708 | } 709 | -------------------------------------------------------------------------------- /decode_map.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "reflect" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | var errArrayStruct = errors.New("msgpack: number of fields in array-encoded struct has changed") 12 | 13 | var ( 14 | mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil)) 15 | mapStringStringType = mapStringStringPtrType.Elem() 16 | mapStringBoolPtrType = reflect.TypeOf((*map[string]bool)(nil)) 17 | mapStringBoolType = mapStringBoolPtrType.Elem() 18 | ) 19 | 20 | var ( 21 | mapStringInterfacePtrType = reflect.TypeOf((*map[string]interface{})(nil)) 22 | mapStringInterfaceType = mapStringInterfacePtrType.Elem() 23 | ) 24 | 25 | func decodeMapValue(d *Decoder, v reflect.Value) error { 26 | n, err := d.DecodeMapLen() 27 | if err != nil { 28 | return err 29 | } 30 | 31 | typ := v.Type() 32 | if n == -1 { 33 | v.Set(reflect.Zero(typ)) 34 | return nil 35 | } 36 | 37 | if v.IsNil() { 38 | ln := n 39 | if d.flags&disableAllocLimitFlag == 0 { 40 | ln = min(ln, maxMapSize) 41 | } 42 | v.Set(reflect.MakeMapWithSize(typ, ln)) 43 | } 44 | if n == 0 { 45 | return nil 46 | } 47 | 48 | return d.decodeTypedMapValue(v, n) 49 | } 50 | 51 | func (d *Decoder) decodeMapDefault() (interface{}, error) { 52 | if d.mapDecoder != nil { 53 | return d.mapDecoder(d) 54 | } 55 | return d.DecodeMap() 56 | } 57 | 58 | // DecodeMapLen decodes map length. Length is -1 when map is nil. 59 | func (d *Decoder) DecodeMapLen() (int, error) { 60 | c, err := d.readCode() 61 | if err != nil { 62 | return 0, err 63 | } 64 | 65 | if msgpcode.IsExt(c) { 66 | if err = d.skipExtHeader(c); err != nil { 67 | return 0, err 68 | } 69 | 70 | c, err = d.readCode() 71 | if err != nil { 72 | return 0, err 73 | } 74 | } 75 | return d.mapLen(c) 76 | } 77 | 78 | func (d *Decoder) mapLen(c byte) (int, error) { 79 | if c == msgpcode.Nil { 80 | return -1, nil 81 | } 82 | if c >= msgpcode.FixedMapLow && c <= msgpcode.FixedMapHigh { 83 | return int(c & msgpcode.FixedMapMask), nil 84 | } 85 | if c == msgpcode.Map16 { 86 | size, err := d.uint16() 87 | return int(size), err 88 | } 89 | if c == msgpcode.Map32 { 90 | size, err := d.uint32() 91 | return int(size), err 92 | } 93 | return 0, unexpectedCodeError{code: c, hint: "map length"} 94 | } 95 | 96 | func decodeMapStringStringValue(d *Decoder, v reflect.Value) error { 97 | mptr := v.Addr().Convert(mapStringStringPtrType).Interface().(*map[string]string) 98 | return d.decodeMapStringStringPtr(mptr) 99 | } 100 | 101 | func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error { 102 | size, err := d.DecodeMapLen() 103 | if err != nil { 104 | return err 105 | } 106 | if size == -1 { 107 | *ptr = nil 108 | return nil 109 | } 110 | 111 | m := *ptr 112 | if m == nil { 113 | ln := size 114 | if d.flags&disableAllocLimitFlag == 0 { 115 | ln = min(size, maxMapSize) 116 | } 117 | *ptr = make(map[string]string, ln) 118 | m = *ptr 119 | } 120 | 121 | for i := 0; i < size; i++ { 122 | mk, err := d.DecodeString() 123 | if err != nil { 124 | return err 125 | } 126 | mv, err := d.DecodeString() 127 | if err != nil { 128 | return err 129 | } 130 | m[mk] = mv 131 | } 132 | 133 | return nil 134 | } 135 | 136 | func decodeMapStringInterfaceValue(d *Decoder, v reflect.Value) error { 137 | ptr := v.Addr().Convert(mapStringInterfacePtrType).Interface().(*map[string]interface{}) 138 | return d.decodeMapStringInterfacePtr(ptr) 139 | } 140 | 141 | func (d *Decoder) decodeMapStringInterfacePtr(ptr *map[string]interface{}) error { 142 | m, err := d.DecodeMap() 143 | if err != nil { 144 | return err 145 | } 146 | *ptr = m 147 | return nil 148 | } 149 | 150 | func (d *Decoder) DecodeMap() (map[string]interface{}, error) { 151 | n, err := d.DecodeMapLen() 152 | if err != nil { 153 | return nil, err 154 | } 155 | 156 | if n == -1 { 157 | return nil, nil 158 | } 159 | 160 | m := make(map[string]interface{}, n) 161 | 162 | for i := 0; i < n; i++ { 163 | mk, err := d.DecodeString() 164 | if err != nil { 165 | return nil, err 166 | } 167 | mv, err := d.decodeInterfaceCond() 168 | if err != nil { 169 | return nil, err 170 | } 171 | m[mk] = mv 172 | } 173 | 174 | return m, nil 175 | } 176 | 177 | func (d *Decoder) DecodeUntypedMap() (map[interface{}]interface{}, error) { 178 | n, err := d.DecodeMapLen() 179 | if err != nil { 180 | return nil, err 181 | } 182 | 183 | if n == -1 { 184 | return nil, nil 185 | } 186 | 187 | m := make(map[interface{}]interface{}, n) 188 | 189 | for i := 0; i < n; i++ { 190 | mk, err := d.decodeInterfaceCond() 191 | if err != nil { 192 | return nil, err 193 | } 194 | 195 | mv, err := d.decodeInterfaceCond() 196 | if err != nil { 197 | return nil, err 198 | } 199 | 200 | m[mk] = mv 201 | } 202 | 203 | return m, nil 204 | } 205 | 206 | // DecodeTypedMap decodes a typed map. Typed map is a map that has a fixed type for keys and values. 207 | // Key and value types may be different. 208 | func (d *Decoder) DecodeTypedMap() (interface{}, error) { 209 | n, err := d.DecodeMapLen() 210 | if err != nil { 211 | return nil, err 212 | } 213 | if n <= 0 { 214 | return nil, nil 215 | } 216 | 217 | key, err := d.decodeInterfaceCond() 218 | if err != nil { 219 | return nil, err 220 | } 221 | 222 | value, err := d.decodeInterfaceCond() 223 | if err != nil { 224 | return nil, err 225 | } 226 | 227 | keyType := reflect.TypeOf(key) 228 | valueType := reflect.TypeOf(value) 229 | 230 | if !keyType.Comparable() { 231 | return nil, fmt.Errorf("msgpack: unsupported map key: %s", keyType.String()) 232 | } 233 | 234 | mapType := reflect.MapOf(keyType, valueType) 235 | 236 | ln := n 237 | if d.flags&disableAllocLimitFlag == 0 { 238 | ln = min(ln, maxMapSize) 239 | } 240 | 241 | mapValue := reflect.MakeMapWithSize(mapType, ln) 242 | mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value)) 243 | 244 | n-- 245 | if err := d.decodeTypedMapValue(mapValue, n); err != nil { 246 | return nil, err 247 | } 248 | 249 | return mapValue.Interface(), nil 250 | } 251 | 252 | func (d *Decoder) decodeTypedMapValue(v reflect.Value, n int) error { 253 | var ( 254 | typ = v.Type() 255 | keyType = typ.Key() 256 | valueType = typ.Elem() 257 | ) 258 | for i := 0; i < n; i++ { 259 | mk := d.newValue(keyType).Elem() 260 | if err := d.DecodeValue(mk); err != nil { 261 | return err 262 | } 263 | 264 | mv := d.newValue(valueType).Elem() 265 | if err := d.DecodeValue(mv); err != nil { 266 | return err 267 | } 268 | 269 | v.SetMapIndex(mk, mv) 270 | } 271 | 272 | return nil 273 | } 274 | 275 | func (d *Decoder) skipMap(c byte) error { 276 | n, err := d.mapLen(c) 277 | if err != nil { 278 | return err 279 | } 280 | for i := 0; i < n; i++ { 281 | if err := d.Skip(); err != nil { 282 | return err 283 | } 284 | if err := d.Skip(); err != nil { 285 | return err 286 | } 287 | } 288 | return nil 289 | } 290 | 291 | func decodeStructValue(d *Decoder, v reflect.Value) error { 292 | c, err := d.readCode() 293 | if err != nil { 294 | return err 295 | } 296 | 297 | n, err := d.mapLen(c) 298 | if err == nil { 299 | return d.decodeStruct(v, n) 300 | } 301 | 302 | var err2 error 303 | n, err2 = d.arrayLen(c) 304 | if err2 != nil { 305 | return err 306 | } 307 | 308 | if n <= 0 { 309 | v.Set(reflect.Zero(v.Type())) 310 | return nil 311 | } 312 | 313 | fields := structs.Fields(v.Type(), d.structTag) 314 | if n != len(fields.List) { 315 | return errArrayStruct 316 | } 317 | 318 | for _, f := range fields.List { 319 | if err := f.DecodeValue(d, v); err != nil { 320 | return err 321 | } 322 | } 323 | 324 | return nil 325 | } 326 | 327 | func (d *Decoder) decodeStruct(v reflect.Value, n int) error { 328 | if n == -1 { 329 | v.Set(reflect.Zero(v.Type())) 330 | return nil 331 | } 332 | 333 | fields := structs.Fields(v.Type(), d.structTag) 334 | for i := 0; i < n; i++ { 335 | name, err := d.decodeStringTemp() 336 | if err != nil { 337 | return err 338 | } 339 | 340 | if f := fields.Map[name]; f != nil { 341 | if err := f.DecodeValue(d, v); err != nil { 342 | return err 343 | } 344 | continue 345 | } 346 | 347 | if d.flags&disallowUnknownFieldsFlag != 0 { 348 | return fmt.Errorf("msgpack: unknown field %q", name) 349 | } 350 | if err := d.Skip(); err != nil { 351 | return err 352 | } 353 | } 354 | 355 | return nil 356 | } 357 | -------------------------------------------------------------------------------- /decode_number.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "reflect" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | func (d *Decoder) skipN(n int) error { 12 | _, err := d.readN(n) 13 | return err 14 | } 15 | 16 | func (d *Decoder) uint8() (uint8, error) { 17 | c, err := d.readCode() 18 | if err != nil { 19 | return 0, err 20 | } 21 | return c, nil 22 | } 23 | 24 | func (d *Decoder) int8() (int8, error) { 25 | n, err := d.uint8() 26 | return int8(n), err 27 | } 28 | 29 | func (d *Decoder) uint16() (uint16, error) { 30 | b, err := d.readN(2) 31 | if err != nil { 32 | return 0, err 33 | } 34 | return (uint16(b[0]) << 8) | uint16(b[1]), nil 35 | } 36 | 37 | func (d *Decoder) int16() (int16, error) { 38 | n, err := d.uint16() 39 | return int16(n), err 40 | } 41 | 42 | func (d *Decoder) uint32() (uint32, error) { 43 | b, err := d.readN(4) 44 | if err != nil { 45 | return 0, err 46 | } 47 | n := (uint32(b[0]) << 24) | 48 | (uint32(b[1]) << 16) | 49 | (uint32(b[2]) << 8) | 50 | uint32(b[3]) 51 | return n, nil 52 | } 53 | 54 | func (d *Decoder) int32() (int32, error) { 55 | n, err := d.uint32() 56 | return int32(n), err 57 | } 58 | 59 | func (d *Decoder) uint64() (uint64, error) { 60 | b, err := d.readN(8) 61 | if err != nil { 62 | return 0, err 63 | } 64 | n := (uint64(b[0]) << 56) | 65 | (uint64(b[1]) << 48) | 66 | (uint64(b[2]) << 40) | 67 | (uint64(b[3]) << 32) | 68 | (uint64(b[4]) << 24) | 69 | (uint64(b[5]) << 16) | 70 | (uint64(b[6]) << 8) | 71 | uint64(b[7]) 72 | return n, nil 73 | } 74 | 75 | func (d *Decoder) int64() (int64, error) { 76 | n, err := d.uint64() 77 | return int64(n), err 78 | } 79 | 80 | // DecodeUint64 decodes msgpack int8/16/32/64 and uint8/16/32/64 81 | // into Go uint64. 82 | func (d *Decoder) DecodeUint64() (uint64, error) { 83 | c, err := d.readCode() 84 | if err != nil { 85 | return 0, err 86 | } 87 | return d.uint(c) 88 | } 89 | 90 | func (d *Decoder) uint(c byte) (uint64, error) { 91 | if c == msgpcode.Nil { 92 | return 0, nil 93 | } 94 | if msgpcode.IsFixedNum(c) { 95 | return uint64(int8(c)), nil 96 | } 97 | switch c { 98 | case msgpcode.Uint8: 99 | n, err := d.uint8() 100 | return uint64(n), err 101 | case msgpcode.Int8: 102 | n, err := d.int8() 103 | return uint64(n), err 104 | case msgpcode.Uint16: 105 | n, err := d.uint16() 106 | return uint64(n), err 107 | case msgpcode.Int16: 108 | n, err := d.int16() 109 | return uint64(n), err 110 | case msgpcode.Uint32: 111 | n, err := d.uint32() 112 | return uint64(n), err 113 | case msgpcode.Int32: 114 | n, err := d.int32() 115 | return uint64(n), err 116 | case msgpcode.Uint64, msgpcode.Int64: 117 | return d.uint64() 118 | } 119 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding uint64", c) 120 | } 121 | 122 | // DecodeInt64 decodes msgpack int8/16/32/64 and uint8/16/32/64 123 | // into Go int64. 124 | func (d *Decoder) DecodeInt64() (int64, error) { 125 | c, err := d.readCode() 126 | if err != nil { 127 | return 0, err 128 | } 129 | return d.int(c) 130 | } 131 | 132 | func (d *Decoder) int(c byte) (int64, error) { 133 | if c == msgpcode.Nil { 134 | return 0, nil 135 | } 136 | if msgpcode.IsFixedNum(c) { 137 | return int64(int8(c)), nil 138 | } 139 | switch c { 140 | case msgpcode.Uint8: 141 | n, err := d.uint8() 142 | return int64(n), err 143 | case msgpcode.Int8: 144 | n, err := d.uint8() 145 | return int64(int8(n)), err 146 | case msgpcode.Uint16: 147 | n, err := d.uint16() 148 | return int64(n), err 149 | case msgpcode.Int16: 150 | n, err := d.uint16() 151 | return int64(int16(n)), err 152 | case msgpcode.Uint32: 153 | n, err := d.uint32() 154 | return int64(n), err 155 | case msgpcode.Int32: 156 | n, err := d.uint32() 157 | return int64(int32(n)), err 158 | case msgpcode.Uint64, msgpcode.Int64: 159 | n, err := d.uint64() 160 | return int64(n), err 161 | } 162 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding int64", c) 163 | } 164 | 165 | func (d *Decoder) DecodeFloat32() (float32, error) { 166 | c, err := d.readCode() 167 | if err != nil { 168 | return 0, err 169 | } 170 | return d.float32(c) 171 | } 172 | 173 | func (d *Decoder) float32(c byte) (float32, error) { 174 | if c == msgpcode.Float { 175 | n, err := d.uint32() 176 | if err != nil { 177 | return 0, err 178 | } 179 | return math.Float32frombits(n), nil 180 | } 181 | 182 | n, err := d.int(c) 183 | if err != nil { 184 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) 185 | } 186 | return float32(n), nil 187 | } 188 | 189 | // DecodeFloat64 decodes msgpack float32/64 into Go float64. 190 | func (d *Decoder) DecodeFloat64() (float64, error) { 191 | c, err := d.readCode() 192 | if err != nil { 193 | return 0, err 194 | } 195 | return d.float64(c) 196 | } 197 | 198 | func (d *Decoder) float64(c byte) (float64, error) { 199 | switch c { 200 | case msgpcode.Float: 201 | n, err := d.float32(c) 202 | if err != nil { 203 | return 0, err 204 | } 205 | return float64(n), nil 206 | case msgpcode.Double: 207 | n, err := d.uint64() 208 | if err != nil { 209 | return 0, err 210 | } 211 | return math.Float64frombits(n), nil 212 | } 213 | 214 | n, err := d.int(c) 215 | if err != nil { 216 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding float32", c) 217 | } 218 | return float64(n), nil 219 | } 220 | 221 | func (d *Decoder) DecodeUint() (uint, error) { 222 | n, err := d.DecodeUint64() 223 | return uint(n), err 224 | } 225 | 226 | func (d *Decoder) DecodeUint8() (uint8, error) { 227 | n, err := d.DecodeUint64() 228 | return uint8(n), err 229 | } 230 | 231 | func (d *Decoder) DecodeUint16() (uint16, error) { 232 | n, err := d.DecodeUint64() 233 | return uint16(n), err 234 | } 235 | 236 | func (d *Decoder) DecodeUint32() (uint32, error) { 237 | n, err := d.DecodeUint64() 238 | return uint32(n), err 239 | } 240 | 241 | func (d *Decoder) DecodeInt() (int, error) { 242 | n, err := d.DecodeInt64() 243 | return int(n), err 244 | } 245 | 246 | func (d *Decoder) DecodeInt8() (int8, error) { 247 | n, err := d.DecodeInt64() 248 | return int8(n), err 249 | } 250 | 251 | func (d *Decoder) DecodeInt16() (int16, error) { 252 | n, err := d.DecodeInt64() 253 | return int16(n), err 254 | } 255 | 256 | func (d *Decoder) DecodeInt32() (int32, error) { 257 | n, err := d.DecodeInt64() 258 | return int32(n), err 259 | } 260 | 261 | func decodeFloat32Value(d *Decoder, v reflect.Value) error { 262 | f, err := d.DecodeFloat32() 263 | if err != nil { 264 | return err 265 | } 266 | v.SetFloat(float64(f)) 267 | return nil 268 | } 269 | 270 | func decodeFloat64Value(d *Decoder, v reflect.Value) error { 271 | f, err := d.DecodeFloat64() 272 | if err != nil { 273 | return err 274 | } 275 | v.SetFloat(f) 276 | return nil 277 | } 278 | 279 | func decodeInt64Value(d *Decoder, v reflect.Value) error { 280 | n, err := d.DecodeInt64() 281 | if err != nil { 282 | return err 283 | } 284 | v.SetInt(n) 285 | return nil 286 | } 287 | 288 | func decodeUint64Value(d *Decoder, v reflect.Value) error { 289 | n, err := d.DecodeUint64() 290 | if err != nil { 291 | return err 292 | } 293 | v.SetUint(n) 294 | return nil 295 | } 296 | -------------------------------------------------------------------------------- /decode_query.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | type queryResult struct { 12 | query string 13 | key string 14 | values []interface{} 15 | hasAsterisk bool 16 | } 17 | 18 | func (q *queryResult) nextKey() { 19 | ind := strings.IndexByte(q.query, '.') 20 | if ind == -1 { 21 | q.key = q.query 22 | q.query = "" 23 | return 24 | } 25 | q.key = q.query[:ind] 26 | q.query = q.query[ind+1:] 27 | } 28 | 29 | // Query extracts data specified by the query from the msgpack stream skipping 30 | // any other data. Query consists of map keys and array indexes separated with dot, 31 | // e.g. key1.0.key2. 32 | func (d *Decoder) Query(query string) ([]interface{}, error) { 33 | res := queryResult{ 34 | query: query, 35 | } 36 | if err := d.query(&res); err != nil { 37 | return nil, err 38 | } 39 | return res.values, nil 40 | } 41 | 42 | func (d *Decoder) query(q *queryResult) error { 43 | q.nextKey() 44 | if q.key == "" { 45 | v, err := d.decodeInterfaceCond() 46 | if err != nil { 47 | return err 48 | } 49 | q.values = append(q.values, v) 50 | return nil 51 | } 52 | 53 | code, err := d.PeekCode() 54 | if err != nil { 55 | return err 56 | } 57 | 58 | switch { 59 | case code == msgpcode.Map16 || code == msgpcode.Map32 || msgpcode.IsFixedMap(code): 60 | err = d.queryMapKey(q) 61 | case code == msgpcode.Array16 || code == msgpcode.Array32 || msgpcode.IsFixedArray(code): 62 | err = d.queryArrayIndex(q) 63 | default: 64 | err = fmt.Errorf("msgpack: unsupported code=%x decoding key=%q", code, q.key) 65 | } 66 | return err 67 | } 68 | 69 | func (d *Decoder) queryMapKey(q *queryResult) error { 70 | n, err := d.DecodeMapLen() 71 | if err != nil { 72 | return err 73 | } 74 | if n == -1 { 75 | return nil 76 | } 77 | 78 | for i := 0; i < n; i++ { 79 | key, err := d.decodeStringTemp() 80 | if err != nil { 81 | return err 82 | } 83 | 84 | if key == q.key { 85 | if err := d.query(q); err != nil { 86 | return err 87 | } 88 | if q.hasAsterisk { 89 | return d.skipNext((n - i - 1) * 2) 90 | } 91 | return nil 92 | } 93 | 94 | if err := d.Skip(); err != nil { 95 | return err 96 | } 97 | } 98 | 99 | return nil 100 | } 101 | 102 | func (d *Decoder) queryArrayIndex(q *queryResult) error { 103 | n, err := d.DecodeArrayLen() 104 | if err != nil { 105 | return err 106 | } 107 | if n == -1 { 108 | return nil 109 | } 110 | 111 | if q.key == "*" { 112 | q.hasAsterisk = true 113 | 114 | query := q.query 115 | for i := 0; i < n; i++ { 116 | q.query = query 117 | if err := d.query(q); err != nil { 118 | return err 119 | } 120 | } 121 | 122 | q.hasAsterisk = false 123 | return nil 124 | } 125 | 126 | ind, err := strconv.Atoi(q.key) 127 | if err != nil { 128 | return err 129 | } 130 | 131 | for i := 0; i < n; i++ { 132 | if i == ind { 133 | if err := d.query(q); err != nil { 134 | return err 135 | } 136 | if q.hasAsterisk { 137 | return d.skipNext(n - i - 1) 138 | } 139 | return nil 140 | } 141 | 142 | if err := d.Skip(); err != nil { 143 | return err 144 | } 145 | } 146 | 147 | return nil 148 | } 149 | 150 | func (d *Decoder) skipNext(n int) error { 151 | for i := 0; i < n; i++ { 152 | if err := d.Skip(); err != nil { 153 | return err 154 | } 155 | } 156 | return nil 157 | } 158 | -------------------------------------------------------------------------------- /decode_slice.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/v5/msgpcode" 8 | ) 9 | 10 | var sliceStringPtrType = reflect.TypeOf((*[]string)(nil)) 11 | 12 | // DecodeArrayLen decodes array length. Length is -1 when array is nil. 13 | func (d *Decoder) DecodeArrayLen() (int, error) { 14 | c, err := d.readCode() 15 | if err != nil { 16 | return 0, err 17 | } 18 | return d.arrayLen(c) 19 | } 20 | 21 | func (d *Decoder) arrayLen(c byte) (int, error) { 22 | if c == msgpcode.Nil { 23 | return -1, nil 24 | } else if c >= msgpcode.FixedArrayLow && c <= msgpcode.FixedArrayHigh { 25 | return int(c & msgpcode.FixedArrayMask), nil 26 | } 27 | switch c { 28 | case msgpcode.Array16: 29 | n, err := d.uint16() 30 | return int(n), err 31 | case msgpcode.Array32: 32 | n, err := d.uint32() 33 | return int(n), err 34 | } 35 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding array length", c) 36 | } 37 | 38 | func decodeStringSliceValue(d *Decoder, v reflect.Value) error { 39 | ptr := v.Addr().Convert(sliceStringPtrType).Interface().(*[]string) 40 | return d.decodeStringSlicePtr(ptr) 41 | } 42 | 43 | func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error { 44 | n, err := d.DecodeArrayLen() 45 | if err != nil { 46 | return err 47 | } 48 | if n == -1 { 49 | return nil 50 | } 51 | 52 | ss := makeStrings(*ptr, n, d.flags&disableAllocLimitFlag != 0) 53 | for i := 0; i < n; i++ { 54 | s, err := d.DecodeString() 55 | if err != nil { 56 | return err 57 | } 58 | ss = append(ss, s) 59 | } 60 | *ptr = ss 61 | 62 | return nil 63 | } 64 | 65 | func makeStrings(s []string, n int, noLimit bool) []string { 66 | if !noLimit && n > sliceAllocLimit { 67 | n = sliceAllocLimit 68 | } 69 | 70 | if s == nil { 71 | return make([]string, 0, n) 72 | } 73 | 74 | if cap(s) >= n { 75 | return s[:0] 76 | } 77 | 78 | s = s[:cap(s)] 79 | s = append(s, make([]string, n-len(s))...) 80 | return s[:0] 81 | } 82 | 83 | func decodeSliceValue(d *Decoder, v reflect.Value) error { 84 | n, err := d.DecodeArrayLen() 85 | if err != nil { 86 | return err 87 | } 88 | 89 | if n == -1 { 90 | v.Set(reflect.Zero(v.Type())) 91 | return nil 92 | } 93 | if n == 0 && v.IsNil() { 94 | v.Set(reflect.MakeSlice(v.Type(), 0, 0)) 95 | return nil 96 | } 97 | 98 | if v.Cap() >= n { 99 | v.Set(v.Slice(0, n)) 100 | } else if v.Len() < v.Cap() { 101 | v.Set(v.Slice(0, v.Cap())) 102 | } 103 | 104 | noLimit := d.flags&disableAllocLimitFlag != 1 105 | 106 | if noLimit && n > v.Len() { 107 | v.Set(growSliceValue(v, n, noLimit)) 108 | } 109 | 110 | for i := 0; i < n; i++ { 111 | if !noLimit && i >= v.Len() { 112 | v.Set(growSliceValue(v, n, noLimit)) 113 | } 114 | 115 | elem := v.Index(i) 116 | if err := d.DecodeValue(elem); err != nil { 117 | return err 118 | } 119 | } 120 | 121 | return nil 122 | } 123 | 124 | func growSliceValue(v reflect.Value, n int, noLimit bool) reflect.Value { 125 | diff := n - v.Len() 126 | if !noLimit && diff > sliceAllocLimit { 127 | diff = sliceAllocLimit 128 | } 129 | v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff)) 130 | return v 131 | } 132 | 133 | func decodeArrayValue(d *Decoder, v reflect.Value) error { 134 | n, err := d.DecodeArrayLen() 135 | if err != nil { 136 | return err 137 | } 138 | 139 | if n == -1 { 140 | return nil 141 | } 142 | if n > v.Len() { 143 | return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) 144 | } 145 | 146 | for i := 0; i < n; i++ { 147 | sv := v.Index(i) 148 | if err := d.DecodeValue(sv); err != nil { 149 | return err 150 | } 151 | } 152 | 153 | return nil 154 | } 155 | 156 | func (d *Decoder) DecodeSlice() ([]interface{}, error) { 157 | c, err := d.readCode() 158 | if err != nil { 159 | return nil, err 160 | } 161 | return d.decodeSlice(c) 162 | } 163 | 164 | func (d *Decoder) decodeSlice(c byte) ([]interface{}, error) { 165 | n, err := d.arrayLen(c) 166 | if err != nil { 167 | return nil, err 168 | } 169 | if n == -1 { 170 | return nil, nil 171 | } 172 | 173 | s := make([]interface{}, 0, n) 174 | for i := 0; i < n; i++ { 175 | v, err := d.decodeInterfaceCond() 176 | if err != nil { 177 | return nil, err 178 | } 179 | s = append(s, v) 180 | } 181 | 182 | return s, nil 183 | } 184 | 185 | func (d *Decoder) skipSlice(c byte) error { 186 | n, err := d.arrayLen(c) 187 | if err != nil { 188 | return err 189 | } 190 | 191 | for i := 0; i < n; i++ { 192 | if err := d.Skip(); err != nil { 193 | return err 194 | } 195 | } 196 | 197 | return nil 198 | } 199 | -------------------------------------------------------------------------------- /decode_string.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/v5/msgpcode" 8 | ) 9 | 10 | func (d *Decoder) bytesLen(c byte) (int, error) { 11 | if c == msgpcode.Nil { 12 | return -1, nil 13 | } 14 | 15 | if msgpcode.IsFixedString(c) { 16 | return int(c & msgpcode.FixedStrMask), nil 17 | } 18 | 19 | switch c { 20 | case msgpcode.Str8, msgpcode.Bin8: 21 | n, err := d.uint8() 22 | return int(n), err 23 | case msgpcode.Str16, msgpcode.Bin16: 24 | n, err := d.uint16() 25 | return int(n), err 26 | case msgpcode.Str32, msgpcode.Bin32: 27 | n, err := d.uint32() 28 | return int(n), err 29 | } 30 | 31 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding string/bytes length", c) 32 | } 33 | 34 | func (d *Decoder) DecodeString() (string, error) { 35 | if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 { 36 | return d.decodeInternedString(intern) 37 | } 38 | 39 | c, err := d.readCode() 40 | if err != nil { 41 | return "", err 42 | } 43 | return d.string(c) 44 | } 45 | 46 | func (d *Decoder) string(c byte) (string, error) { 47 | n, err := d.bytesLen(c) 48 | if err != nil { 49 | return "", err 50 | } 51 | return d.stringWithLen(n) 52 | } 53 | 54 | func (d *Decoder) stringWithLen(n int) (string, error) { 55 | if n <= 0 { 56 | return "", nil 57 | } 58 | b, err := d.readN(n) 59 | return string(b), err 60 | } 61 | 62 | func decodeStringValue(d *Decoder, v reflect.Value) error { 63 | s, err := d.DecodeString() 64 | if err != nil { 65 | return err 66 | } 67 | v.SetString(s) 68 | return nil 69 | } 70 | 71 | func (d *Decoder) DecodeBytesLen() (int, error) { 72 | c, err := d.readCode() 73 | if err != nil { 74 | return 0, err 75 | } 76 | return d.bytesLen(c) 77 | } 78 | 79 | func (d *Decoder) DecodeBytes() ([]byte, error) { 80 | c, err := d.readCode() 81 | if err != nil { 82 | return nil, err 83 | } 84 | return d.bytes(c, nil) 85 | } 86 | 87 | func (d *Decoder) bytes(c byte, b []byte) ([]byte, error) { 88 | n, err := d.bytesLen(c) 89 | if err != nil { 90 | return nil, err 91 | } 92 | if n == -1 { 93 | return nil, nil 94 | } 95 | return readN(d.r, b, n) 96 | } 97 | 98 | func (d *Decoder) decodeStringTemp() (string, error) { 99 | if intern := d.flags&useInternedStringsFlag != 0; intern || len(d.dict) > 0 { 100 | return d.decodeInternedString(intern) 101 | } 102 | 103 | c, err := d.readCode() 104 | if err != nil { 105 | return "", err 106 | } 107 | 108 | n, err := d.bytesLen(c) 109 | if err != nil { 110 | return "", err 111 | } 112 | if n == -1 { 113 | return "", nil 114 | } 115 | 116 | b, err := d.readN(n) 117 | if err != nil { 118 | return "", err 119 | } 120 | 121 | return bytesToString(b), nil 122 | } 123 | 124 | func (d *Decoder) decodeBytesPtr(ptr *[]byte) error { 125 | c, err := d.readCode() 126 | if err != nil { 127 | return err 128 | } 129 | return d.bytesPtr(c, ptr) 130 | } 131 | 132 | func (d *Decoder) bytesPtr(c byte, ptr *[]byte) error { 133 | n, err := d.bytesLen(c) 134 | if err != nil { 135 | return err 136 | } 137 | if n == -1 { 138 | *ptr = nil 139 | return nil 140 | } 141 | 142 | *ptr, err = readN(d.r, *ptr, n) 143 | return err 144 | } 145 | 146 | func (d *Decoder) skipBytes(c byte) error { 147 | n, err := d.bytesLen(c) 148 | if err != nil { 149 | return err 150 | } 151 | if n <= 0 { 152 | return nil 153 | } 154 | return d.skipN(n) 155 | } 156 | 157 | func decodeBytesValue(d *Decoder, v reflect.Value) error { 158 | c, err := d.readCode() 159 | if err != nil { 160 | return err 161 | } 162 | 163 | b, err := d.bytes(c, v.Bytes()) 164 | if err != nil { 165 | return err 166 | } 167 | 168 | v.SetBytes(b) 169 | 170 | return nil 171 | } 172 | 173 | func decodeByteArrayValue(d *Decoder, v reflect.Value) error { 174 | c, err := d.readCode() 175 | if err != nil { 176 | return err 177 | } 178 | 179 | n, err := d.bytesLen(c) 180 | if err != nil { 181 | return err 182 | } 183 | if n == -1 { 184 | return nil 185 | } 186 | if n > v.Len() { 187 | return fmt.Errorf("%s len is %d, but msgpack has %d elements", v.Type(), v.Len(), n) 188 | } 189 | 190 | b := v.Slice(0, n).Bytes() 191 | return d.readFull(b) 192 | } 193 | -------------------------------------------------------------------------------- /decode_typgen.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "reflect" 5 | "sync" 6 | ) 7 | 8 | var cachedValues struct { 9 | m map[reflect.Type]chan reflect.Value 10 | sync.RWMutex 11 | } 12 | 13 | func cachedValue(t reflect.Type) reflect.Value { 14 | cachedValues.RLock() 15 | ch := cachedValues.m[t] 16 | cachedValues.RUnlock() 17 | if ch != nil { 18 | return <-ch 19 | } 20 | 21 | cachedValues.Lock() 22 | defer cachedValues.Unlock() 23 | if ch = cachedValues.m[t]; ch != nil { 24 | return <-ch 25 | } 26 | 27 | ch = make(chan reflect.Value, 256) 28 | go func() { 29 | for { 30 | ch <- reflect.New(t) 31 | } 32 | }() 33 | if cachedValues.m == nil { 34 | cachedValues.m = make(map[reflect.Type]chan reflect.Value, 8) 35 | } 36 | cachedValues.m[t] = ch 37 | return <-ch 38 | } 39 | 40 | func (d *Decoder) newValue(t reflect.Type) reflect.Value { 41 | if d.flags&usePreallocateValues == 0 { 42 | return reflect.New(t) 43 | } 44 | 45 | return cachedValue(t) 46 | } 47 | -------------------------------------------------------------------------------- /decode_value.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "encoding" 5 | "errors" 6 | "fmt" 7 | "reflect" 8 | ) 9 | 10 | var ( 11 | interfaceType = reflect.TypeOf((*interface{})(nil)).Elem() 12 | stringType = reflect.TypeOf((*string)(nil)).Elem() 13 | boolType = reflect.TypeOf((*bool)(nil)).Elem() 14 | ) 15 | 16 | var valueDecoders []decoderFunc 17 | 18 | //nolint:gochecknoinits 19 | func init() { 20 | valueDecoders = []decoderFunc{ 21 | reflect.Bool: decodeBoolValue, 22 | reflect.Int: decodeInt64Value, 23 | reflect.Int8: decodeInt64Value, 24 | reflect.Int16: decodeInt64Value, 25 | reflect.Int32: decodeInt64Value, 26 | reflect.Int64: decodeInt64Value, 27 | reflect.Uint: decodeUint64Value, 28 | reflect.Uint8: decodeUint64Value, 29 | reflect.Uint16: decodeUint64Value, 30 | reflect.Uint32: decodeUint64Value, 31 | reflect.Uint64: decodeUint64Value, 32 | reflect.Float32: decodeFloat32Value, 33 | reflect.Float64: decodeFloat64Value, 34 | reflect.Complex64: decodeUnsupportedValue, 35 | reflect.Complex128: decodeUnsupportedValue, 36 | reflect.Array: decodeArrayValue, 37 | reflect.Chan: decodeUnsupportedValue, 38 | reflect.Func: decodeUnsupportedValue, 39 | reflect.Interface: decodeInterfaceValue, 40 | reflect.Map: decodeMapValue, 41 | reflect.Ptr: decodeUnsupportedValue, 42 | reflect.Slice: decodeSliceValue, 43 | reflect.String: decodeStringValue, 44 | reflect.Struct: decodeStructValue, 45 | reflect.UnsafePointer: decodeUnsupportedValue, 46 | } 47 | } 48 | 49 | func getDecoder(typ reflect.Type) decoderFunc { 50 | if v, ok := typeDecMap.Load(typ); ok { 51 | return v.(decoderFunc) 52 | } 53 | fn := _getDecoder(typ) 54 | typeDecMap.Store(typ, fn) 55 | return fn 56 | } 57 | 58 | func _getDecoder(typ reflect.Type) decoderFunc { 59 | kind := typ.Kind() 60 | 61 | if kind == reflect.Ptr { 62 | if _, ok := typeDecMap.Load(typ.Elem()); ok { 63 | return ptrValueDecoder(typ) 64 | } 65 | } 66 | 67 | if typ.Implements(customDecoderType) { 68 | return nilAwareDecoder(typ, decodeCustomValue) 69 | } 70 | if typ.Implements(unmarshalerType) { 71 | return nilAwareDecoder(typ, unmarshalValue) 72 | } 73 | if typ.Implements(binaryUnmarshalerType) { 74 | return nilAwareDecoder(typ, unmarshalBinaryValue) 75 | } 76 | if typ.Implements(textUnmarshalerType) { 77 | return nilAwareDecoder(typ, unmarshalTextValue) 78 | } 79 | 80 | // Addressable struct field value. 81 | if kind != reflect.Ptr { 82 | ptr := reflect.PtrTo(typ) 83 | if ptr.Implements(customDecoderType) { 84 | return addrDecoder(nilAwareDecoder(typ, decodeCustomValue)) 85 | } 86 | if ptr.Implements(unmarshalerType) { 87 | return addrDecoder(nilAwareDecoder(typ, unmarshalValue)) 88 | } 89 | if ptr.Implements(binaryUnmarshalerType) { 90 | return addrDecoder(nilAwareDecoder(typ, unmarshalBinaryValue)) 91 | } 92 | if ptr.Implements(textUnmarshalerType) { 93 | return addrDecoder(nilAwareDecoder(typ, unmarshalTextValue)) 94 | } 95 | } 96 | 97 | switch kind { 98 | case reflect.Ptr: 99 | return ptrValueDecoder(typ) 100 | case reflect.Slice: 101 | elem := typ.Elem() 102 | if elem.Kind() == reflect.Uint8 { 103 | return decodeBytesValue 104 | } 105 | if elem == stringType { 106 | return decodeStringSliceValue 107 | } 108 | case reflect.Array: 109 | if typ.Elem().Kind() == reflect.Uint8 { 110 | return decodeByteArrayValue 111 | } 112 | case reflect.Map: 113 | if typ.Key() == stringType { 114 | switch typ.Elem() { 115 | case stringType: 116 | return decodeMapStringStringValue 117 | case interfaceType: 118 | return decodeMapStringInterfaceValue 119 | } 120 | } 121 | } 122 | 123 | return valueDecoders[kind] 124 | } 125 | 126 | func ptrValueDecoder(typ reflect.Type) decoderFunc { 127 | decoder := getDecoder(typ.Elem()) 128 | return func(d *Decoder, v reflect.Value) error { 129 | if d.hasNilCode() { 130 | if !v.IsNil() { 131 | v.Set(d.newValue(typ).Elem()) 132 | } 133 | return d.DecodeNil() 134 | } 135 | if v.IsNil() { 136 | v.Set(d.newValue(typ.Elem())) 137 | } 138 | return decoder(d, v.Elem()) 139 | } 140 | } 141 | 142 | func addrDecoder(fn decoderFunc) decoderFunc { 143 | return func(d *Decoder, v reflect.Value) error { 144 | if !v.CanAddr() { 145 | return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface()) 146 | } 147 | return fn(d, v.Addr()) 148 | } 149 | } 150 | 151 | func nilAwareDecoder(typ reflect.Type, fn decoderFunc) decoderFunc { 152 | if nilable(typ.Kind()) { 153 | return func(d *Decoder, v reflect.Value) error { 154 | if d.hasNilCode() { 155 | return d.decodeNilValue(v) 156 | } 157 | if v.IsNil() { 158 | v.Set(d.newValue(typ.Elem())) 159 | } 160 | return fn(d, v) 161 | } 162 | } 163 | 164 | return func(d *Decoder, v reflect.Value) error { 165 | if d.hasNilCode() { 166 | return d.decodeNilValue(v) 167 | } 168 | return fn(d, v) 169 | } 170 | } 171 | 172 | func decodeBoolValue(d *Decoder, v reflect.Value) error { 173 | flag, err := d.DecodeBool() 174 | if err != nil { 175 | return err 176 | } 177 | v.SetBool(flag) 178 | return nil 179 | } 180 | 181 | func decodeInterfaceValue(d *Decoder, v reflect.Value) error { 182 | if v.IsNil() { 183 | return d.interfaceValue(v) 184 | } 185 | return d.DecodeValue(v.Elem()) 186 | } 187 | 188 | func (d *Decoder) interfaceValue(v reflect.Value) error { 189 | vv, err := d.decodeInterfaceCond() 190 | if err != nil { 191 | return err 192 | } 193 | 194 | if vv != nil { 195 | if v.Type() == errorType { 196 | if vv, ok := vv.(string); ok { 197 | v.Set(reflect.ValueOf(errors.New(vv))) 198 | return nil 199 | } 200 | } 201 | 202 | v.Set(reflect.ValueOf(vv)) 203 | } 204 | 205 | return nil 206 | } 207 | 208 | func decodeUnsupportedValue(d *Decoder, v reflect.Value) error { 209 | return fmt.Errorf("msgpack: Decode(unsupported %s)", v.Type()) 210 | } 211 | 212 | //------------------------------------------------------------------------------ 213 | 214 | func decodeCustomValue(d *Decoder, v reflect.Value) error { 215 | decoder := v.Interface().(CustomDecoder) 216 | return decoder.DecodeMsgpack(d) 217 | } 218 | 219 | func unmarshalValue(d *Decoder, v reflect.Value) error { 220 | var b []byte 221 | 222 | d.rec = make([]byte, 0, 64) 223 | if err := d.Skip(); err != nil { 224 | return err 225 | } 226 | b = d.rec 227 | d.rec = nil 228 | 229 | unmarshaler := v.Interface().(Unmarshaler) 230 | return unmarshaler.UnmarshalMsgpack(b) 231 | } 232 | 233 | func unmarshalBinaryValue(d *Decoder, v reflect.Value) error { 234 | data, err := d.DecodeBytes() 235 | if err != nil { 236 | return err 237 | } 238 | 239 | unmarshaler := v.Interface().(encoding.BinaryUnmarshaler) 240 | return unmarshaler.UnmarshalBinary(data) 241 | } 242 | 243 | func unmarshalTextValue(d *Decoder, v reflect.Value) error { 244 | data, err := d.DecodeBytes() 245 | if err != nil { 246 | return err 247 | } 248 | 249 | unmarshaler := v.Interface().(encoding.TextUnmarshaler) 250 | return unmarshaler.UnmarshalText(data) 251 | } 252 | -------------------------------------------------------------------------------- /encode.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "reflect" 7 | "sync" 8 | "time" 9 | 10 | "github.com/vmihailenco/msgpack/v5/msgpcode" 11 | ) 12 | 13 | const ( 14 | sortMapKeysFlag uint32 = 1 << iota 15 | arrayEncodedStructsFlag 16 | useCompactIntsFlag 17 | useCompactFloatsFlag 18 | useInternedStringsFlag 19 | omitEmptyFlag 20 | ) 21 | 22 | type writer interface { 23 | io.Writer 24 | WriteByte(byte) error 25 | } 26 | 27 | type byteWriter struct { 28 | io.Writer 29 | } 30 | 31 | func newByteWriter(w io.Writer) byteWriter { 32 | return byteWriter{ 33 | Writer: w, 34 | } 35 | } 36 | 37 | func (bw byteWriter) WriteByte(c byte) error { 38 | _, err := bw.Write([]byte{c}) 39 | return err 40 | } 41 | 42 | //------------------------------------------------------------------------------ 43 | 44 | var encPool = sync.Pool{ 45 | New: func() interface{} { 46 | return NewEncoder(nil) 47 | }, 48 | } 49 | 50 | func GetEncoder() *Encoder { 51 | return encPool.Get().(*Encoder) 52 | } 53 | 54 | func PutEncoder(enc *Encoder) { 55 | enc.w = nil 56 | encPool.Put(enc) 57 | } 58 | 59 | // Marshal returns the MessagePack encoding of v. 60 | func Marshal(v interface{}) ([]byte, error) { 61 | enc := GetEncoder() 62 | 63 | var buf bytes.Buffer 64 | enc.Reset(&buf) 65 | 66 | err := enc.Encode(v) 67 | b := buf.Bytes() 68 | 69 | PutEncoder(enc) 70 | 71 | if err != nil { 72 | return nil, err 73 | } 74 | return b, err 75 | } 76 | 77 | type Encoder struct { 78 | w writer 79 | dict map[string]int 80 | structTag string 81 | buf []byte 82 | timeBuf []byte 83 | flags uint32 84 | } 85 | 86 | // NewEncoder returns a new encoder that writes to w. 87 | func NewEncoder(w io.Writer) *Encoder { 88 | e := &Encoder{ 89 | buf: make([]byte, 9), 90 | } 91 | e.Reset(w) 92 | return e 93 | } 94 | 95 | // Writer returns the Encoder's writer. 96 | func (e *Encoder) Writer() io.Writer { 97 | return e.w 98 | } 99 | 100 | // Reset discards any buffered data, resets all state, and switches the writer to write to w. 101 | func (e *Encoder) Reset(w io.Writer) { 102 | e.ResetDict(w, nil) 103 | } 104 | 105 | // ResetDict is like Reset, but also resets the dict. 106 | func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) { 107 | e.ResetWriter(w) 108 | e.flags = 0 109 | e.structTag = "" 110 | e.dict = dict 111 | } 112 | 113 | func (e *Encoder) WithDict(dict map[string]int, fn func(*Encoder) error) error { 114 | oldDict := e.dict 115 | e.dict = dict 116 | err := fn(e) 117 | e.dict = oldDict 118 | return err 119 | } 120 | 121 | func (e *Encoder) ResetWriter(w io.Writer) { 122 | e.dict = nil 123 | if bw, ok := w.(writer); ok { 124 | e.w = bw 125 | } else if w == nil { 126 | e.w = nil 127 | } else { 128 | e.w = newByteWriter(w) 129 | } 130 | } 131 | 132 | // SetSortMapKeys causes the Encoder to encode map keys in increasing order. 133 | // Supported map types are: 134 | // - map[string]string 135 | // - map[string]bool 136 | // - map[string]interface{} 137 | func (e *Encoder) SetSortMapKeys(on bool) *Encoder { 138 | if on { 139 | e.flags |= sortMapKeysFlag 140 | } else { 141 | e.flags &= ^sortMapKeysFlag 142 | } 143 | return e 144 | } 145 | 146 | // SetCustomStructTag causes the Encoder to use a custom struct tag as 147 | // fallback option if there is no msgpack tag. 148 | func (e *Encoder) SetCustomStructTag(tag string) { 149 | e.structTag = tag 150 | } 151 | 152 | // SetOmitEmpty causes the Encoder to omit empty values by default. 153 | func (e *Encoder) SetOmitEmpty(on bool) { 154 | if on { 155 | e.flags |= omitEmptyFlag 156 | } else { 157 | e.flags &= ^omitEmptyFlag 158 | } 159 | } 160 | 161 | // UseArrayEncodedStructs causes the Encoder to encode Go structs as msgpack arrays. 162 | func (e *Encoder) UseArrayEncodedStructs(on bool) { 163 | if on { 164 | e.flags |= arrayEncodedStructsFlag 165 | } else { 166 | e.flags &= ^arrayEncodedStructsFlag 167 | } 168 | } 169 | 170 | // UseCompactEncoding causes the Encoder to chose the most compact encoding. 171 | // For example, it allows to encode small Go int64 as msgpack int8 saving 7 bytes. 172 | func (e *Encoder) UseCompactInts(on bool) { 173 | if on { 174 | e.flags |= useCompactIntsFlag 175 | } else { 176 | e.flags &= ^useCompactIntsFlag 177 | } 178 | } 179 | 180 | // UseCompactFloats causes the Encoder to chose a compact integer encoding 181 | // for floats that can be represented as integers. 182 | func (e *Encoder) UseCompactFloats(on bool) { 183 | if on { 184 | e.flags |= useCompactFloatsFlag 185 | } else { 186 | e.flags &= ^useCompactFloatsFlag 187 | } 188 | } 189 | 190 | // UseInternedStrings causes the Encoder to intern strings. 191 | func (e *Encoder) UseInternedStrings(on bool) { 192 | if on { 193 | e.flags |= useInternedStringsFlag 194 | } else { 195 | e.flags &= ^useInternedStringsFlag 196 | } 197 | } 198 | 199 | func (e *Encoder) Encode(v interface{}) error { 200 | switch v := v.(type) { 201 | case nil: 202 | return e.EncodeNil() 203 | case string: 204 | return e.EncodeString(v) 205 | case []byte: 206 | return e.EncodeBytes(v) 207 | case int: 208 | return e.EncodeInt(int64(v)) 209 | case int64: 210 | return e.encodeInt64Cond(v) 211 | case uint: 212 | return e.EncodeUint(uint64(v)) 213 | case uint64: 214 | return e.encodeUint64Cond(v) 215 | case bool: 216 | return e.EncodeBool(v) 217 | case float32: 218 | return e.EncodeFloat32(v) 219 | case float64: 220 | return e.EncodeFloat64(v) 221 | case time.Duration: 222 | return e.encodeInt64Cond(int64(v)) 223 | case time.Time: 224 | return e.EncodeTime(v) 225 | } 226 | return e.EncodeValue(reflect.ValueOf(v)) 227 | } 228 | 229 | func (e *Encoder) EncodeMulti(v ...interface{}) error { 230 | for _, vv := range v { 231 | if err := e.Encode(vv); err != nil { 232 | return err 233 | } 234 | } 235 | return nil 236 | } 237 | 238 | func (e *Encoder) EncodeValue(v reflect.Value) error { 239 | fn := getEncoder(v.Type()) 240 | return fn(e, v) 241 | } 242 | 243 | func (e *Encoder) EncodeNil() error { 244 | return e.writeCode(msgpcode.Nil) 245 | } 246 | 247 | func (e *Encoder) EncodeBool(value bool) error { 248 | if value { 249 | return e.writeCode(msgpcode.True) 250 | } 251 | return e.writeCode(msgpcode.False) 252 | } 253 | 254 | func (e *Encoder) EncodeDuration(d time.Duration) error { 255 | return e.EncodeInt(int64(d)) 256 | } 257 | 258 | func (e *Encoder) writeCode(c byte) error { 259 | return e.w.WriteByte(c) 260 | } 261 | 262 | func (e *Encoder) write(b []byte) error { 263 | _, err := e.w.Write(b) 264 | return err 265 | } 266 | 267 | func (e *Encoder) writeString(s string) error { 268 | _, err := e.w.Write(stringToBytes(s)) 269 | return err 270 | } 271 | -------------------------------------------------------------------------------- /encode_map.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "math" 5 | "reflect" 6 | "sort" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | func encodeMapValue(e *Encoder, v reflect.Value) error { 12 | if v.IsNil() { 13 | return e.EncodeNil() 14 | } 15 | 16 | if err := e.EncodeMapLen(v.Len()); err != nil { 17 | return err 18 | } 19 | 20 | iter := v.MapRange() 21 | for iter.Next() { 22 | if err := e.EncodeValue(iter.Key()); err != nil { 23 | return err 24 | } 25 | if err := e.EncodeValue(iter.Value()); err != nil { 26 | return err 27 | } 28 | } 29 | 30 | return nil 31 | } 32 | 33 | func encodeMapStringBoolValue(e *Encoder, v reflect.Value) error { 34 | if v.IsNil() { 35 | return e.EncodeNil() 36 | } 37 | 38 | if err := e.EncodeMapLen(v.Len()); err != nil { 39 | return err 40 | } 41 | 42 | m := v.Convert(mapStringBoolType).Interface().(map[string]bool) 43 | if e.flags&sortMapKeysFlag != 0 { 44 | return e.encodeSortedMapStringBool(m) 45 | } 46 | 47 | for mk, mv := range m { 48 | if err := e.EncodeString(mk); err != nil { 49 | return err 50 | } 51 | if err := e.EncodeBool(mv); err != nil { 52 | return err 53 | } 54 | } 55 | 56 | return nil 57 | } 58 | 59 | func encodeMapStringStringValue(e *Encoder, v reflect.Value) error { 60 | if v.IsNil() { 61 | return e.EncodeNil() 62 | } 63 | 64 | if err := e.EncodeMapLen(v.Len()); err != nil { 65 | return err 66 | } 67 | 68 | m := v.Convert(mapStringStringType).Interface().(map[string]string) 69 | if e.flags&sortMapKeysFlag != 0 { 70 | return e.encodeSortedMapStringString(m) 71 | } 72 | 73 | for mk, mv := range m { 74 | if err := e.EncodeString(mk); err != nil { 75 | return err 76 | } 77 | if err := e.EncodeString(mv); err != nil { 78 | return err 79 | } 80 | } 81 | 82 | return nil 83 | } 84 | 85 | func encodeMapStringInterfaceValue(e *Encoder, v reflect.Value) error { 86 | if v.IsNil() { 87 | return e.EncodeNil() 88 | } 89 | m := v.Convert(mapStringInterfaceType).Interface().(map[string]interface{}) 90 | if e.flags&sortMapKeysFlag != 0 { 91 | return e.EncodeMapSorted(m) 92 | } 93 | return e.EncodeMap(m) 94 | } 95 | 96 | func (e *Encoder) EncodeMap(m map[string]interface{}) error { 97 | if m == nil { 98 | return e.EncodeNil() 99 | } 100 | if err := e.EncodeMapLen(len(m)); err != nil { 101 | return err 102 | } 103 | for mk, mv := range m { 104 | if err := e.EncodeString(mk); err != nil { 105 | return err 106 | } 107 | if err := e.Encode(mv); err != nil { 108 | return err 109 | } 110 | } 111 | return nil 112 | } 113 | 114 | func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error { 115 | if m == nil { 116 | return e.EncodeNil() 117 | } 118 | if err := e.EncodeMapLen(len(m)); err != nil { 119 | return err 120 | } 121 | 122 | keys := make([]string, 0, len(m)) 123 | 124 | for k := range m { 125 | keys = append(keys, k) 126 | } 127 | 128 | sort.Strings(keys) 129 | 130 | for _, k := range keys { 131 | if err := e.EncodeString(k); err != nil { 132 | return err 133 | } 134 | if err := e.Encode(m[k]); err != nil { 135 | return err 136 | } 137 | } 138 | 139 | return nil 140 | } 141 | 142 | func (e *Encoder) encodeSortedMapStringBool(m map[string]bool) error { 143 | keys := make([]string, 0, len(m)) 144 | for k := range m { 145 | keys = append(keys, k) 146 | } 147 | sort.Strings(keys) 148 | 149 | for _, k := range keys { 150 | err := e.EncodeString(k) 151 | if err != nil { 152 | return err 153 | } 154 | if err = e.EncodeBool(m[k]); err != nil { 155 | return err 156 | } 157 | } 158 | 159 | return nil 160 | } 161 | 162 | func (e *Encoder) encodeSortedMapStringString(m map[string]string) error { 163 | keys := make([]string, 0, len(m)) 164 | for k := range m { 165 | keys = append(keys, k) 166 | } 167 | sort.Strings(keys) 168 | 169 | for _, k := range keys { 170 | err := e.EncodeString(k) 171 | if err != nil { 172 | return err 173 | } 174 | if err = e.EncodeString(m[k]); err != nil { 175 | return err 176 | } 177 | } 178 | 179 | return nil 180 | } 181 | 182 | func (e *Encoder) EncodeMapLen(l int) error { 183 | if l < 16 { 184 | return e.writeCode(msgpcode.FixedMapLow | byte(l)) 185 | } 186 | if l <= math.MaxUint16 { 187 | return e.write2(msgpcode.Map16, uint16(l)) 188 | } 189 | return e.write4(msgpcode.Map32, uint32(l)) 190 | } 191 | 192 | func encodeStructValue(e *Encoder, strct reflect.Value) error { 193 | structFields := structs.Fields(strct.Type(), e.structTag) 194 | if e.flags&arrayEncodedStructsFlag != 0 || structFields.AsArray { 195 | return encodeStructValueAsArray(e, strct, structFields.List) 196 | } 197 | fields := structFields.OmitEmpty(e, strct) 198 | 199 | if err := e.EncodeMapLen(len(fields)); err != nil { 200 | return err 201 | } 202 | 203 | for _, f := range fields { 204 | if err := e.EncodeString(f.name); err != nil { 205 | return err 206 | } 207 | if err := f.EncodeValue(e, strct); err != nil { 208 | return err 209 | } 210 | } 211 | 212 | return nil 213 | } 214 | 215 | func encodeStructValueAsArray(e *Encoder, strct reflect.Value, fields []*field) error { 216 | if err := e.EncodeArrayLen(len(fields)); err != nil { 217 | return err 218 | } 219 | for _, f := range fields { 220 | if err := f.EncodeValue(e, strct); err != nil { 221 | return err 222 | } 223 | } 224 | return nil 225 | } 226 | -------------------------------------------------------------------------------- /encode_number.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "math" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/v5/msgpcode" 8 | ) 9 | 10 | // EncodeUint8 encodes an uint8 in 2 bytes preserving type of the number. 11 | func (e *Encoder) EncodeUint8(n uint8) error { 12 | return e.write1(msgpcode.Uint8, n) 13 | } 14 | 15 | func (e *Encoder) encodeUint8Cond(n uint8) error { 16 | if e.flags&useCompactIntsFlag != 0 { 17 | return e.EncodeUint(uint64(n)) 18 | } 19 | return e.EncodeUint8(n) 20 | } 21 | 22 | // EncodeUint16 encodes an uint16 in 3 bytes preserving type of the number. 23 | func (e *Encoder) EncodeUint16(n uint16) error { 24 | return e.write2(msgpcode.Uint16, n) 25 | } 26 | 27 | func (e *Encoder) encodeUint16Cond(n uint16) error { 28 | if e.flags&useCompactIntsFlag != 0 { 29 | return e.EncodeUint(uint64(n)) 30 | } 31 | return e.EncodeUint16(n) 32 | } 33 | 34 | // EncodeUint32 encodes an uint16 in 5 bytes preserving type of the number. 35 | func (e *Encoder) EncodeUint32(n uint32) error { 36 | return e.write4(msgpcode.Uint32, n) 37 | } 38 | 39 | func (e *Encoder) encodeUint32Cond(n uint32) error { 40 | if e.flags&useCompactIntsFlag != 0 { 41 | return e.EncodeUint(uint64(n)) 42 | } 43 | return e.EncodeUint32(n) 44 | } 45 | 46 | // EncodeUint64 encodes an uint16 in 9 bytes preserving type of the number. 47 | func (e *Encoder) EncodeUint64(n uint64) error { 48 | return e.write8(msgpcode.Uint64, n) 49 | } 50 | 51 | func (e *Encoder) encodeUint64Cond(n uint64) error { 52 | if e.flags&useCompactIntsFlag != 0 { 53 | return e.EncodeUint(n) 54 | } 55 | return e.EncodeUint64(n) 56 | } 57 | 58 | // EncodeInt8 encodes an int8 in 2 bytes preserving type of the number. 59 | func (e *Encoder) EncodeInt8(n int8) error { 60 | return e.write1(msgpcode.Int8, uint8(n)) 61 | } 62 | 63 | func (e *Encoder) encodeInt8Cond(n int8) error { 64 | if e.flags&useCompactIntsFlag != 0 { 65 | return e.EncodeInt(int64(n)) 66 | } 67 | return e.EncodeInt8(n) 68 | } 69 | 70 | // EncodeInt16 encodes an int16 in 3 bytes preserving type of the number. 71 | func (e *Encoder) EncodeInt16(n int16) error { 72 | return e.write2(msgpcode.Int16, uint16(n)) 73 | } 74 | 75 | func (e *Encoder) encodeInt16Cond(n int16) error { 76 | if e.flags&useCompactIntsFlag != 0 { 77 | return e.EncodeInt(int64(n)) 78 | } 79 | return e.EncodeInt16(n) 80 | } 81 | 82 | // EncodeInt32 encodes an int32 in 5 bytes preserving type of the number. 83 | func (e *Encoder) EncodeInt32(n int32) error { 84 | return e.write4(msgpcode.Int32, uint32(n)) 85 | } 86 | 87 | func (e *Encoder) encodeInt32Cond(n int32) error { 88 | if e.flags&useCompactIntsFlag != 0 { 89 | return e.EncodeInt(int64(n)) 90 | } 91 | return e.EncodeInt32(n) 92 | } 93 | 94 | // EncodeInt64 encodes an int64 in 9 bytes preserving type of the number. 95 | func (e *Encoder) EncodeInt64(n int64) error { 96 | return e.write8(msgpcode.Int64, uint64(n)) 97 | } 98 | 99 | func (e *Encoder) encodeInt64Cond(n int64) error { 100 | if e.flags&useCompactIntsFlag != 0 { 101 | return e.EncodeInt(n) 102 | } 103 | return e.EncodeInt64(n) 104 | } 105 | 106 | // EncodeUnsignedNumber encodes an uint64 in 1, 2, 3, 5, or 9 bytes. 107 | // Type of the number is lost during encoding. 108 | func (e *Encoder) EncodeUint(n uint64) error { 109 | if n <= math.MaxInt8 { 110 | return e.w.WriteByte(byte(n)) 111 | } 112 | if n <= math.MaxUint8 { 113 | return e.EncodeUint8(uint8(n)) 114 | } 115 | if n <= math.MaxUint16 { 116 | return e.EncodeUint16(uint16(n)) 117 | } 118 | if n <= math.MaxUint32 { 119 | return e.EncodeUint32(uint32(n)) 120 | } 121 | return e.EncodeUint64(n) 122 | } 123 | 124 | // EncodeNumber encodes an int64 in 1, 2, 3, 5, or 9 bytes. 125 | // Type of the number is lost during encoding. 126 | func (e *Encoder) EncodeInt(n int64) error { 127 | if n >= 0 { 128 | return e.EncodeUint(uint64(n)) 129 | } 130 | if n >= int64(int8(msgpcode.NegFixedNumLow)) { 131 | return e.w.WriteByte(byte(n)) 132 | } 133 | if n >= math.MinInt8 { 134 | return e.EncodeInt8(int8(n)) 135 | } 136 | if n >= math.MinInt16 { 137 | return e.EncodeInt16(int16(n)) 138 | } 139 | if n >= math.MinInt32 { 140 | return e.EncodeInt32(int32(n)) 141 | } 142 | return e.EncodeInt64(n) 143 | } 144 | 145 | func (e *Encoder) EncodeFloat32(n float32) error { 146 | if e.flags&useCompactFloatsFlag != 0 { 147 | if float32(int64(n)) == n { 148 | return e.EncodeInt(int64(n)) 149 | } 150 | } 151 | return e.write4(msgpcode.Float, math.Float32bits(n)) 152 | } 153 | 154 | func (e *Encoder) EncodeFloat64(n float64) error { 155 | if e.flags&useCompactFloatsFlag != 0 { 156 | // Both NaN and Inf convert to int64(-0x8000000000000000) 157 | // If n is NaN then it never compares true with any other value 158 | // If n is Inf then it doesn't convert from int64 back to +/-Inf 159 | // In both cases the comparison works. 160 | if float64(int64(n)) == n { 161 | return e.EncodeInt(int64(n)) 162 | } 163 | } 164 | return e.write8(msgpcode.Double, math.Float64bits(n)) 165 | } 166 | 167 | func (e *Encoder) write1(code byte, n uint8) error { 168 | e.buf = e.buf[:2] 169 | e.buf[0] = code 170 | e.buf[1] = n 171 | return e.write(e.buf) 172 | } 173 | 174 | func (e *Encoder) write2(code byte, n uint16) error { 175 | e.buf = e.buf[:3] 176 | e.buf[0] = code 177 | e.buf[1] = byte(n >> 8) 178 | e.buf[2] = byte(n) 179 | return e.write(e.buf) 180 | } 181 | 182 | func (e *Encoder) write4(code byte, n uint32) error { 183 | e.buf = e.buf[:5] 184 | e.buf[0] = code 185 | e.buf[1] = byte(n >> 24) 186 | e.buf[2] = byte(n >> 16) 187 | e.buf[3] = byte(n >> 8) 188 | e.buf[4] = byte(n) 189 | return e.write(e.buf) 190 | } 191 | 192 | func (e *Encoder) write8(code byte, n uint64) error { 193 | e.buf = e.buf[:9] 194 | e.buf[0] = code 195 | e.buf[1] = byte(n >> 56) 196 | e.buf[2] = byte(n >> 48) 197 | e.buf[3] = byte(n >> 40) 198 | e.buf[4] = byte(n >> 32) 199 | e.buf[5] = byte(n >> 24) 200 | e.buf[6] = byte(n >> 16) 201 | e.buf[7] = byte(n >> 8) 202 | e.buf[8] = byte(n) 203 | return e.write(e.buf) 204 | } 205 | 206 | func encodeUintValue(e *Encoder, v reflect.Value) error { 207 | return e.EncodeUint(v.Uint()) 208 | } 209 | 210 | func encodeIntValue(e *Encoder, v reflect.Value) error { 211 | return e.EncodeInt(v.Int()) 212 | } 213 | 214 | func encodeUint8CondValue(e *Encoder, v reflect.Value) error { 215 | return e.encodeUint8Cond(uint8(v.Uint())) 216 | } 217 | 218 | func encodeUint16CondValue(e *Encoder, v reflect.Value) error { 219 | return e.encodeUint16Cond(uint16(v.Uint())) 220 | } 221 | 222 | func encodeUint32CondValue(e *Encoder, v reflect.Value) error { 223 | return e.encodeUint32Cond(uint32(v.Uint())) 224 | } 225 | 226 | func encodeUint64CondValue(e *Encoder, v reflect.Value) error { 227 | return e.encodeUint64Cond(v.Uint()) 228 | } 229 | 230 | func encodeInt8CondValue(e *Encoder, v reflect.Value) error { 231 | return e.encodeInt8Cond(int8(v.Int())) 232 | } 233 | 234 | func encodeInt16CondValue(e *Encoder, v reflect.Value) error { 235 | return e.encodeInt16Cond(int16(v.Int())) 236 | } 237 | 238 | func encodeInt32CondValue(e *Encoder, v reflect.Value) error { 239 | return e.encodeInt32Cond(int32(v.Int())) 240 | } 241 | 242 | func encodeInt64CondValue(e *Encoder, v reflect.Value) error { 243 | return e.encodeInt64Cond(v.Int()) 244 | } 245 | 246 | func encodeFloat32Value(e *Encoder, v reflect.Value) error { 247 | return e.EncodeFloat32(float32(v.Float())) 248 | } 249 | 250 | func encodeFloat64Value(e *Encoder, v reflect.Value) error { 251 | return e.EncodeFloat64(v.Float()) 252 | } 253 | -------------------------------------------------------------------------------- /encode_slice.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "math" 5 | "reflect" 6 | 7 | "github.com/vmihailenco/msgpack/v5/msgpcode" 8 | ) 9 | 10 | var stringSliceType = reflect.TypeOf(([]string)(nil)) 11 | 12 | func encodeStringValue(e *Encoder, v reflect.Value) error { 13 | return e.EncodeString(v.String()) 14 | } 15 | 16 | func encodeByteSliceValue(e *Encoder, v reflect.Value) error { 17 | return e.EncodeBytes(v.Bytes()) 18 | } 19 | 20 | func encodeByteArrayValue(e *Encoder, v reflect.Value) error { 21 | if err := e.EncodeBytesLen(v.Len()); err != nil { 22 | return err 23 | } 24 | 25 | if v.CanAddr() { 26 | b := v.Slice(0, v.Len()).Bytes() 27 | return e.write(b) 28 | } 29 | 30 | e.buf = grow(e.buf, v.Len()) 31 | reflect.Copy(reflect.ValueOf(e.buf), v) 32 | return e.write(e.buf) 33 | } 34 | 35 | func grow(b []byte, n int) []byte { 36 | if cap(b) >= n { 37 | return b[:n] 38 | } 39 | b = b[:cap(b)] 40 | b = append(b, make([]byte, n-len(b))...) 41 | return b 42 | } 43 | 44 | func (e *Encoder) EncodeBytesLen(l int) error { 45 | if l < 256 { 46 | return e.write1(msgpcode.Bin8, uint8(l)) 47 | } 48 | if l <= math.MaxUint16 { 49 | return e.write2(msgpcode.Bin16, uint16(l)) 50 | } 51 | return e.write4(msgpcode.Bin32, uint32(l)) 52 | } 53 | 54 | func (e *Encoder) encodeStringLen(l int) error { 55 | if l < 32 { 56 | return e.writeCode(msgpcode.FixedStrLow | byte(l)) 57 | } 58 | if l < 256 { 59 | return e.write1(msgpcode.Str8, uint8(l)) 60 | } 61 | if l <= math.MaxUint16 { 62 | return e.write2(msgpcode.Str16, uint16(l)) 63 | } 64 | return e.write4(msgpcode.Str32, uint32(l)) 65 | } 66 | 67 | func (e *Encoder) EncodeString(v string) error { 68 | if intern := e.flags&useInternedStringsFlag != 0; intern || len(e.dict) > 0 { 69 | return e.encodeInternedString(v, intern) 70 | } 71 | return e.encodeNormalString(v) 72 | } 73 | 74 | func (e *Encoder) encodeNormalString(v string) error { 75 | if err := e.encodeStringLen(len(v)); err != nil { 76 | return err 77 | } 78 | return e.writeString(v) 79 | } 80 | 81 | func (e *Encoder) EncodeBytes(v []byte) error { 82 | if v == nil { 83 | return e.EncodeNil() 84 | } 85 | if err := e.EncodeBytesLen(len(v)); err != nil { 86 | return err 87 | } 88 | return e.write(v) 89 | } 90 | 91 | func (e *Encoder) EncodeArrayLen(l int) error { 92 | if l < 16 { 93 | return e.writeCode(msgpcode.FixedArrayLow | byte(l)) 94 | } 95 | if l <= math.MaxUint16 { 96 | return e.write2(msgpcode.Array16, uint16(l)) 97 | } 98 | return e.write4(msgpcode.Array32, uint32(l)) 99 | } 100 | 101 | func encodeStringSliceValue(e *Encoder, v reflect.Value) error { 102 | ss := v.Convert(stringSliceType).Interface().([]string) 103 | return e.encodeStringSlice(ss) 104 | } 105 | 106 | func (e *Encoder) encodeStringSlice(s []string) error { 107 | if s == nil { 108 | return e.EncodeNil() 109 | } 110 | if err := e.EncodeArrayLen(len(s)); err != nil { 111 | return err 112 | } 113 | for _, v := range s { 114 | if err := e.EncodeString(v); err != nil { 115 | return err 116 | } 117 | } 118 | return nil 119 | } 120 | 121 | func encodeSliceValue(e *Encoder, v reflect.Value) error { 122 | if v.IsNil() { 123 | return e.EncodeNil() 124 | } 125 | return encodeArrayValue(e, v) 126 | } 127 | 128 | func encodeArrayValue(e *Encoder, v reflect.Value) error { 129 | l := v.Len() 130 | if err := e.EncodeArrayLen(l); err != nil { 131 | return err 132 | } 133 | for i := 0; i < l; i++ { 134 | if err := e.EncodeValue(v.Index(i)); err != nil { 135 | return err 136 | } 137 | } 138 | return nil 139 | } 140 | -------------------------------------------------------------------------------- /encode_value.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "encoding" 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | var valueEncoders []encoderFunc 10 | 11 | //nolint:gochecknoinits 12 | func init() { 13 | valueEncoders = []encoderFunc{ 14 | reflect.Bool: encodeBoolValue, 15 | reflect.Int: encodeIntValue, 16 | reflect.Int8: encodeInt8CondValue, 17 | reflect.Int16: encodeInt16CondValue, 18 | reflect.Int32: encodeInt32CondValue, 19 | reflect.Int64: encodeInt64CondValue, 20 | reflect.Uint: encodeUintValue, 21 | reflect.Uint8: encodeUint8CondValue, 22 | reflect.Uint16: encodeUint16CondValue, 23 | reflect.Uint32: encodeUint32CondValue, 24 | reflect.Uint64: encodeUint64CondValue, 25 | reflect.Float32: encodeFloat32Value, 26 | reflect.Float64: encodeFloat64Value, 27 | reflect.Complex64: encodeUnsupportedValue, 28 | reflect.Complex128: encodeUnsupportedValue, 29 | reflect.Array: encodeArrayValue, 30 | reflect.Chan: encodeUnsupportedValue, 31 | reflect.Func: encodeUnsupportedValue, 32 | reflect.Interface: encodeInterfaceValue, 33 | reflect.Map: encodeMapValue, 34 | reflect.Ptr: encodeUnsupportedValue, 35 | reflect.Slice: encodeSliceValue, 36 | reflect.String: encodeStringValue, 37 | reflect.Struct: encodeStructValue, 38 | reflect.UnsafePointer: encodeUnsupportedValue, 39 | } 40 | } 41 | 42 | func getEncoder(typ reflect.Type) encoderFunc { 43 | if v, ok := typeEncMap.Load(typ); ok { 44 | return v.(encoderFunc) 45 | } 46 | fn := _getEncoder(typ) 47 | typeEncMap.Store(typ, fn) 48 | return fn 49 | } 50 | 51 | func _getEncoder(typ reflect.Type) encoderFunc { 52 | kind := typ.Kind() 53 | 54 | if kind == reflect.Ptr { 55 | if _, ok := typeEncMap.Load(typ.Elem()); ok { 56 | return ptrEncoderFunc(typ) 57 | } 58 | } 59 | 60 | if typ.Implements(customEncoderType) { 61 | return encodeCustomValue 62 | } 63 | if typ.Implements(marshalerType) { 64 | return marshalValue 65 | } 66 | if typ.Implements(binaryMarshalerType) { 67 | return marshalBinaryValue 68 | } 69 | if typ.Implements(textMarshalerType) { 70 | return marshalTextValue 71 | } 72 | 73 | // Addressable struct field value. 74 | if kind != reflect.Ptr { 75 | ptr := reflect.PtrTo(typ) 76 | if ptr.Implements(customEncoderType) { 77 | return encodeCustomValuePtr 78 | } 79 | if ptr.Implements(marshalerType) { 80 | return marshalValuePtr 81 | } 82 | if ptr.Implements(binaryMarshalerType) { 83 | return marshalBinaryValueAddr 84 | } 85 | if ptr.Implements(textMarshalerType) { 86 | return marshalTextValueAddr 87 | } 88 | } 89 | 90 | if typ == errorType { 91 | return encodeErrorValue 92 | } 93 | 94 | switch kind { 95 | case reflect.Ptr: 96 | return ptrEncoderFunc(typ) 97 | case reflect.Slice: 98 | elem := typ.Elem() 99 | if elem.Kind() == reflect.Uint8 { 100 | return encodeByteSliceValue 101 | } 102 | if elem == stringType { 103 | return encodeStringSliceValue 104 | } 105 | case reflect.Array: 106 | if typ.Elem().Kind() == reflect.Uint8 { 107 | return encodeByteArrayValue 108 | } 109 | case reflect.Map: 110 | if typ.Key() == stringType { 111 | switch typ.Elem() { 112 | case stringType: 113 | return encodeMapStringStringValue 114 | case boolType: 115 | return encodeMapStringBoolValue 116 | case interfaceType: 117 | return encodeMapStringInterfaceValue 118 | } 119 | } 120 | } 121 | 122 | return valueEncoders[kind] 123 | } 124 | 125 | func ptrEncoderFunc(typ reflect.Type) encoderFunc { 126 | encoder := getEncoder(typ.Elem()) 127 | return func(e *Encoder, v reflect.Value) error { 128 | if v.IsNil() { 129 | return e.EncodeNil() 130 | } 131 | return encoder(e, v.Elem()) 132 | } 133 | } 134 | 135 | func encodeCustomValuePtr(e *Encoder, v reflect.Value) error { 136 | if !v.CanAddr() { 137 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 138 | } 139 | encoder := v.Addr().Interface().(CustomEncoder) 140 | return encoder.EncodeMsgpack(e) 141 | } 142 | 143 | func encodeCustomValue(e *Encoder, v reflect.Value) error { 144 | if nilable(v.Kind()) && v.IsNil() { 145 | return e.EncodeNil() 146 | } 147 | 148 | encoder := v.Interface().(CustomEncoder) 149 | return encoder.EncodeMsgpack(e) 150 | } 151 | 152 | func marshalValuePtr(e *Encoder, v reflect.Value) error { 153 | if !v.CanAddr() { 154 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 155 | } 156 | return marshalValue(e, v.Addr()) 157 | } 158 | 159 | func marshalValue(e *Encoder, v reflect.Value) error { 160 | if nilable(v.Kind()) && v.IsNil() { 161 | return e.EncodeNil() 162 | } 163 | 164 | marshaler := v.Interface().(Marshaler) 165 | b, err := marshaler.MarshalMsgpack() 166 | if err != nil { 167 | return err 168 | } 169 | _, err = e.w.Write(b) 170 | return err 171 | } 172 | 173 | func encodeBoolValue(e *Encoder, v reflect.Value) error { 174 | return e.EncodeBool(v.Bool()) 175 | } 176 | 177 | func encodeInterfaceValue(e *Encoder, v reflect.Value) error { 178 | if v.IsNil() { 179 | return e.EncodeNil() 180 | } 181 | return e.EncodeValue(v.Elem()) 182 | } 183 | 184 | func encodeErrorValue(e *Encoder, v reflect.Value) error { 185 | if v.IsNil() { 186 | return e.EncodeNil() 187 | } 188 | return e.EncodeString(v.Interface().(error).Error()) 189 | } 190 | 191 | func encodeUnsupportedValue(e *Encoder, v reflect.Value) error { 192 | return fmt.Errorf("msgpack: Encode(unsupported %s)", v.Type()) 193 | } 194 | 195 | func nilable(kind reflect.Kind) bool { 196 | switch kind { 197 | case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: 198 | return true 199 | } 200 | return false 201 | } 202 | 203 | func nilableType(t reflect.Type) bool { 204 | if t.Kind() == reflect.Ptr { 205 | t = t.Elem() 206 | } 207 | return nilable(t.Kind()) 208 | } 209 | 210 | //------------------------------------------------------------------------------ 211 | 212 | func marshalBinaryValueAddr(e *Encoder, v reflect.Value) error { 213 | if !v.CanAddr() { 214 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 215 | } 216 | return marshalBinaryValue(e, v.Addr()) 217 | } 218 | 219 | func marshalBinaryValue(e *Encoder, v reflect.Value) error { 220 | if nilable(v.Kind()) && v.IsNil() { 221 | return e.EncodeNil() 222 | } 223 | 224 | marshaler := v.Interface().(encoding.BinaryMarshaler) 225 | data, err := marshaler.MarshalBinary() 226 | if err != nil { 227 | return err 228 | } 229 | 230 | return e.EncodeBytes(data) 231 | } 232 | 233 | //------------------------------------------------------------------------------ 234 | 235 | func marshalTextValueAddr(e *Encoder, v reflect.Value) error { 236 | if !v.CanAddr() { 237 | return fmt.Errorf("msgpack: Encode(non-addressable %T)", v.Interface()) 238 | } 239 | return marshalTextValue(e, v.Addr()) 240 | } 241 | 242 | func marshalTextValue(e *Encoder, v reflect.Value) error { 243 | if nilable(v.Kind()) && v.IsNil() { 244 | return e.EncodeNil() 245 | } 246 | 247 | marshaler := v.Interface().(encoding.TextMarshaler) 248 | data, err := marshaler.MarshalText() 249 | if err != nil { 250 | return err 251 | } 252 | 253 | return e.EncodeBytes(data) 254 | } 255 | -------------------------------------------------------------------------------- /example_CustomEncoder_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/vmihailenco/msgpack/v5" 7 | ) 8 | 9 | type customStruct struct { 10 | S string 11 | N int 12 | } 13 | 14 | var _ msgpack.CustomEncoder = (*customStruct)(nil) 15 | var _ msgpack.CustomDecoder = (*customStruct)(nil) 16 | 17 | func (s *customStruct) EncodeMsgpack(enc *msgpack.Encoder) error { 18 | return enc.EncodeMulti(s.S, s.N) 19 | } 20 | 21 | func (s *customStruct) DecodeMsgpack(dec *msgpack.Decoder) error { 22 | return dec.DecodeMulti(&s.S, &s.N) 23 | } 24 | 25 | func ExampleCustomEncoder() { 26 | b, err := msgpack.Marshal(&customStruct{S: "hello", N: 42}) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | var v customStruct 32 | err = msgpack.Unmarshal(b, &v) 33 | if err != nil { 34 | panic(err) 35 | } 36 | fmt.Printf("%#v", v) 37 | // Output: msgpack_test.customStruct{S:"hello", N:42} 38 | } 39 | -------------------------------------------------------------------------------- /example_registerExt_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/vmihailenco/msgpack/v5" 9 | ) 10 | 11 | // https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1#eventtime-ext-format 12 | type EventTime struct { 13 | time.Time 14 | } 15 | 16 | type OneMoreSecondEventTime struct { 17 | EventTime 18 | } 19 | 20 | var ( 21 | _ msgpack.Marshaler = (*EventTime)(nil) 22 | _ msgpack.Unmarshaler = (*EventTime)(nil) 23 | _ msgpack.Marshaler = (*OneMoreSecondEventTime)(nil) 24 | _ msgpack.Unmarshaler = (*OneMoreSecondEventTime)(nil) 25 | ) 26 | 27 | func (tm *EventTime) MarshalMsgpack() ([]byte, error) { 28 | b := make([]byte, 8) 29 | binary.BigEndian.PutUint32(b, uint32(tm.Unix())) 30 | binary.BigEndian.PutUint32(b[4:], uint32(tm.Nanosecond())) 31 | return b, nil 32 | } 33 | 34 | func (tm *EventTime) UnmarshalMsgpack(b []byte) error { 35 | if len(b) != 8 { 36 | return fmt.Errorf("invalid data length: got %d, wanted 8", len(b)) 37 | } 38 | sec := binary.BigEndian.Uint32(b) 39 | usec := binary.BigEndian.Uint32(b[4:]) 40 | tm.Time = time.Unix(int64(sec), int64(usec)) 41 | return nil 42 | } 43 | 44 | func (tm *OneMoreSecondEventTime) MarshalMsgpack() ([]byte, error) { 45 | b := make([]byte, 8) 46 | binary.BigEndian.PutUint32(b, uint32(tm.Unix()+1)) 47 | binary.BigEndian.PutUint32(b[4:], uint32(tm.Nanosecond())) 48 | return b, nil 49 | } 50 | 51 | func (tm *OneMoreSecondEventTime) UnmarshalMsgpack(b []byte) error { 52 | if len(b) != 8 { 53 | return fmt.Errorf("invalid data length: got %d, wanted 8", len(b)) 54 | } 55 | sec := binary.BigEndian.Uint32(b) 56 | usec := binary.BigEndian.Uint32(b[4:]) 57 | tm.Time = time.Unix(int64(sec+1), int64(usec)) 58 | return nil 59 | } 60 | 61 | func ExampleRegisterExt() { 62 | t := time.Unix(123456789, 123) 63 | 64 | { 65 | msgpack.RegisterExt(1, (*EventTime)(nil)) 66 | b, err := msgpack.Marshal(&EventTime{t}) 67 | if err != nil { 68 | panic(err) 69 | } 70 | 71 | var v interface{} 72 | err = msgpack.Unmarshal(b, &v) 73 | if err != nil { 74 | panic(err) 75 | } 76 | fmt.Println(v.(*EventTime).UTC()) 77 | 78 | tm := new(EventTime) 79 | err = msgpack.Unmarshal(b, &tm) 80 | if err != nil { 81 | panic(err) 82 | } 83 | fmt.Println(tm.UTC()) 84 | } 85 | 86 | { 87 | msgpack.RegisterExt(1, (*EventTime)(nil)) 88 | b, err := msgpack.Marshal(&EventTime{t}) 89 | if err != nil { 90 | panic(err) 91 | } 92 | 93 | // override ext 94 | msgpack.RegisterExt(1, (*OneMoreSecondEventTime)(nil)) 95 | 96 | var v interface{} 97 | err = msgpack.Unmarshal(b, &v) 98 | if err != nil { 99 | panic(err) 100 | } 101 | fmt.Println(v.(*OneMoreSecondEventTime).UTC()) 102 | } 103 | 104 | { 105 | msgpack.RegisterExt(1, (*OneMoreSecondEventTime)(nil)) 106 | b, err := msgpack.Marshal(&OneMoreSecondEventTime{ 107 | EventTime{t}, 108 | }) 109 | if err != nil { 110 | panic(err) 111 | } 112 | 113 | // override ext 114 | msgpack.RegisterExt(1, (*EventTime)(nil)) 115 | var v interface{} 116 | err = msgpack.Unmarshal(b, &v) 117 | if err != nil { 118 | panic(err) 119 | } 120 | fmt.Println(v.(*EventTime).UTC()) 121 | } 122 | 123 | // Output: 1973-11-29 21:33:09.000000123 +0000 UTC 124 | // 1973-11-29 21:33:09.000000123 +0000 UTC 125 | // 1973-11-29 21:33:10.000000123 +0000 UTC 126 | // 1973-11-29 21:33:10.000000123 +0000 UTC 127 | } 128 | 129 | func ExampleUnregisterExt() { 130 | t := time.Unix(123456789, 123) 131 | 132 | { 133 | msgpack.RegisterExt(1, (*EventTime)(nil)) 134 | b, err := msgpack.Marshal(&EventTime{t}) 135 | if err != nil { 136 | panic(err) 137 | } 138 | 139 | msgpack.UnregisterExt(1) 140 | 141 | var v interface{} 142 | err = msgpack.Unmarshal(b, &v) 143 | wanted := "msgpack: unknown ext id=1" 144 | if err.Error() != wanted { 145 | panic(err) 146 | } 147 | 148 | msgpack.RegisterExt(1, (*OneMoreSecondEventTime)(nil)) 149 | err = msgpack.Unmarshal(b, &v) 150 | if err != nil { 151 | panic(err) 152 | } 153 | fmt.Println(v.(*OneMoreSecondEventTime).UTC()) 154 | } 155 | 156 | { 157 | msgpack.RegisterExt(1, (*OneMoreSecondEventTime)(nil)) 158 | b, err := msgpack.Marshal(&OneMoreSecondEventTime{ 159 | EventTime{t}, 160 | }) 161 | if err != nil { 162 | panic(err) 163 | } 164 | 165 | msgpack.UnregisterExt(1) 166 | var v interface{} 167 | err = msgpack.Unmarshal(b, &v) 168 | wanted := "msgpack: unknown ext id=1" 169 | if err.Error() != wanted { 170 | panic(err) 171 | } 172 | 173 | msgpack.RegisterExt(1, (*EventTime)(nil)) 174 | err = msgpack.Unmarshal(b, &v) 175 | if err != nil { 176 | panic(err) 177 | } 178 | fmt.Println(v.(*EventTime).UTC()) 179 | } 180 | 181 | // Output: 1973-11-29 21:33:10.000000123 +0000 UTC 182 | // 1973-11-29 21:33:10.000000123 +0000 UTC 183 | } 184 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | 7 | "github.com/vmihailenco/msgpack/v5" 8 | ) 9 | 10 | func ExampleMarshal() { 11 | type Item struct { 12 | Foo string 13 | } 14 | 15 | b, err := msgpack.Marshal(&Item{Foo: "bar"}) 16 | if err != nil { 17 | panic(err) 18 | } 19 | 20 | var item Item 21 | err = msgpack.Unmarshal(b, &item) 22 | if err != nil { 23 | panic(err) 24 | } 25 | fmt.Println(item.Foo) 26 | // Output: bar 27 | } 28 | 29 | func ExampleMarshal_mapStringInterface() { 30 | in := map[string]interface{}{"foo": 1, "hello": "world"} 31 | b, err := msgpack.Marshal(in) 32 | if err != nil { 33 | panic(err) 34 | } 35 | 36 | var out map[string]interface{} 37 | err = msgpack.Unmarshal(b, &out) 38 | if err != nil { 39 | panic(err) 40 | } 41 | 42 | fmt.Println("foo =", out["foo"]) 43 | fmt.Println("hello =", out["hello"]) 44 | 45 | // Output: 46 | // foo = 1 47 | // hello = world 48 | } 49 | 50 | func ExampleDecoder_SetMapDecoder() { 51 | buf := new(bytes.Buffer) 52 | 53 | enc := msgpack.NewEncoder(buf) 54 | in := map[string]string{"hello": "world"} 55 | err := enc.Encode(in) 56 | if err != nil { 57 | panic(err) 58 | } 59 | 60 | dec := msgpack.NewDecoder(buf) 61 | 62 | // Causes decoder to produce map[string]string instead of map[string]interface{}. 63 | dec.SetMapDecoder(func(d *msgpack.Decoder) (interface{}, error) { 64 | n, err := d.DecodeMapLen() 65 | if err != nil { 66 | return nil, err 67 | } 68 | 69 | m := make(map[string]string, n) 70 | for i := 0; i < n; i++ { 71 | mk, err := d.DecodeString() 72 | if err != nil { 73 | return nil, err 74 | } 75 | 76 | mv, err := d.DecodeString() 77 | if err != nil { 78 | return nil, err 79 | } 80 | 81 | m[mk] = mv 82 | } 83 | return m, nil 84 | }) 85 | 86 | out, err := dec.DecodeInterface() 87 | if err != nil { 88 | panic(err) 89 | } 90 | fmt.Printf("%#v", out) 91 | // Output: map[string]string{"hello":"world"} 92 | } 93 | 94 | func ExampleDecoder_Query() { 95 | b, err := msgpack.Marshal([]map[string]interface{}{ 96 | {"id": 1, "attrs": map[string]interface{}{"phone": 12345}}, 97 | {"id": 2, "attrs": map[string]interface{}{"phone": 54321}}, 98 | }) 99 | if err != nil { 100 | panic(err) 101 | } 102 | 103 | dec := msgpack.NewDecoder(bytes.NewBuffer(b)) 104 | values, err := dec.Query("*.attrs.phone") 105 | if err != nil { 106 | panic(err) 107 | } 108 | fmt.Println("phones are", values) 109 | 110 | dec.Reset(bytes.NewBuffer(b)) 111 | values, err = dec.Query("1.attrs.phone") 112 | if err != nil { 113 | panic(err) 114 | } 115 | fmt.Println("2nd phone is", values[0]) 116 | // Output: phones are [12345 54321] 117 | // 2nd phone is 54321 118 | } 119 | 120 | func ExampleEncoder_UseArrayEncodedStructs() { 121 | type Item struct { 122 | Foo string 123 | Bar string 124 | } 125 | 126 | var buf bytes.Buffer 127 | enc := msgpack.NewEncoder(&buf) 128 | enc.UseArrayEncodedStructs(true) 129 | 130 | err := enc.Encode(&Item{Foo: "foo", Bar: "bar"}) 131 | if err != nil { 132 | panic(err) 133 | } 134 | 135 | dec := msgpack.NewDecoder(&buf) 136 | v, err := dec.DecodeInterface() 137 | if err != nil { 138 | panic(err) 139 | } 140 | fmt.Println(v) 141 | // Output: [foo bar] 142 | } 143 | 144 | func ExampleMarshal_asArray() { 145 | type Item struct { 146 | _msgpack struct{} `msgpack:",as_array"` 147 | Foo string 148 | Bar string 149 | } 150 | 151 | var buf bytes.Buffer 152 | enc := msgpack.NewEncoder(&buf) 153 | err := enc.Encode(&Item{Foo: "foo", Bar: "bar"}) 154 | if err != nil { 155 | panic(err) 156 | } 157 | 158 | dec := msgpack.NewDecoder(&buf) 159 | v, err := dec.DecodeInterface() 160 | if err != nil { 161 | panic(err) 162 | } 163 | fmt.Println(v) 164 | // Output: [foo bar] 165 | } 166 | 167 | func ExampleMarshal_omitEmpty() { 168 | type Item struct { 169 | Foo string 170 | Bar string 171 | } 172 | 173 | item := &Item{ 174 | Foo: "hello", 175 | } 176 | b, err := msgpack.Marshal(item) 177 | if err != nil { 178 | panic(err) 179 | } 180 | fmt.Printf("item: %q\n", b) 181 | 182 | type ItemOmitEmpty struct { 183 | _msgpack struct{} `msgpack:",omitempty"` 184 | Foo string 185 | Bar string 186 | } 187 | 188 | itemOmitEmpty := &ItemOmitEmpty{ 189 | Foo: "hello", 190 | } 191 | b, err = msgpack.Marshal(itemOmitEmpty) 192 | if err != nil { 193 | panic(err) 194 | } 195 | fmt.Printf("item2: %q\n", b) 196 | 197 | // Output: item: "\x82\xa3Foo\xa5hello\xa3Bar\xa0" 198 | // item2: "\x81\xa3Foo\xa5hello" 199 | } 200 | 201 | func ExampleMarshal_escapedNames() { 202 | og := map[string]interface{}{ 203 | "something:special": uint(123), 204 | "hello, world": "hello!", 205 | } 206 | raw, err := msgpack.Marshal(og) 207 | if err != nil { 208 | panic(err) 209 | } 210 | 211 | type Item struct { 212 | SomethingSpecial uint `msgpack:"'something:special'"` 213 | HelloWorld string `msgpack:"'hello, world'"` 214 | } 215 | var item Item 216 | if err := msgpack.Unmarshal(raw, &item); err != nil { 217 | panic(err) 218 | } 219 | fmt.Printf("%#v\n", item) 220 | //output: msgpack_test.Item{SomethingSpecial:0x7b, HelloWorld:"hello!"} 221 | } 222 | -------------------------------------------------------------------------------- /ext.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "reflect" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | type extInfo struct { 12 | Type reflect.Type 13 | Decoder func(d *Decoder, v reflect.Value, extLen int) error 14 | } 15 | 16 | var extTypes = make(map[int8]*extInfo) 17 | 18 | type MarshalerUnmarshaler interface { 19 | Marshaler 20 | Unmarshaler 21 | } 22 | 23 | func RegisterExt(extID int8, value MarshalerUnmarshaler) { 24 | RegisterExtEncoder(extID, value, func(e *Encoder, v reflect.Value) ([]byte, error) { 25 | marshaler := v.Interface().(Marshaler) 26 | return marshaler.MarshalMsgpack() 27 | }) 28 | RegisterExtDecoder(extID, value, func(d *Decoder, v reflect.Value, extLen int) error { 29 | b, err := d.readN(extLen) 30 | if err != nil { 31 | return err 32 | } 33 | return v.Interface().(Unmarshaler).UnmarshalMsgpack(b) 34 | }) 35 | } 36 | 37 | func UnregisterExt(extID int8) { 38 | unregisterExtEncoder(extID) 39 | unregisterExtDecoder(extID) 40 | } 41 | 42 | func RegisterExtEncoder( 43 | extID int8, 44 | value interface{}, 45 | encoder func(enc *Encoder, v reflect.Value) ([]byte, error), 46 | ) { 47 | unregisterExtEncoder(extID) 48 | 49 | typ := reflect.TypeOf(value) 50 | extEncoder := makeExtEncoder(extID, typ, encoder) 51 | typeEncMap.Store(extID, typ) 52 | typeEncMap.Store(typ, extEncoder) 53 | if typ.Kind() == reflect.Ptr { 54 | typeEncMap.Store(typ.Elem(), makeExtEncoderAddr(extEncoder)) 55 | } 56 | } 57 | 58 | func unregisterExtEncoder(extID int8) { 59 | t, ok := typeEncMap.Load(extID) 60 | if !ok { 61 | return 62 | } 63 | typeEncMap.Delete(extID) 64 | typ := t.(reflect.Type) 65 | typeEncMap.Delete(typ) 66 | if typ.Kind() == reflect.Ptr { 67 | typeEncMap.Delete(typ.Elem()) 68 | } 69 | } 70 | 71 | func makeExtEncoder( 72 | extID int8, 73 | typ reflect.Type, 74 | encoder func(enc *Encoder, v reflect.Value) ([]byte, error), 75 | ) encoderFunc { 76 | nilable := typ.Kind() == reflect.Ptr 77 | 78 | return func(e *Encoder, v reflect.Value) error { 79 | if nilable && v.IsNil() { 80 | return e.EncodeNil() 81 | } 82 | 83 | b, err := encoder(e, v) 84 | if err != nil { 85 | return err 86 | } 87 | 88 | if err := e.EncodeExtHeader(extID, len(b)); err != nil { 89 | return err 90 | } 91 | 92 | return e.write(b) 93 | } 94 | } 95 | 96 | func makeExtEncoderAddr(extEncoder encoderFunc) encoderFunc { 97 | return func(e *Encoder, v reflect.Value) error { 98 | if !v.CanAddr() { 99 | return fmt.Errorf("msgpack: EncodeExt(nonaddressable %T)", v.Interface()) 100 | } 101 | return extEncoder(e, v.Addr()) 102 | } 103 | } 104 | 105 | func RegisterExtDecoder( 106 | extID int8, 107 | value interface{}, 108 | decoder func(dec *Decoder, v reflect.Value, extLen int) error, 109 | ) { 110 | unregisterExtDecoder(extID) 111 | 112 | typ := reflect.TypeOf(value) 113 | extDecoder := makeExtDecoder(extID, typ, decoder) 114 | extTypes[extID] = &extInfo{ 115 | Type: typ, 116 | Decoder: decoder, 117 | } 118 | 119 | typeDecMap.Store(extID, typ) 120 | typeDecMap.Store(typ, extDecoder) 121 | if typ.Kind() == reflect.Ptr { 122 | typeDecMap.Store(typ.Elem(), makeExtDecoderAddr(extDecoder)) 123 | } 124 | } 125 | 126 | func unregisterExtDecoder(extID int8) { 127 | t, ok := typeDecMap.Load(extID) 128 | if !ok { 129 | return 130 | } 131 | typeDecMap.Delete(extID) 132 | delete(extTypes, extID) 133 | typ := t.(reflect.Type) 134 | typeDecMap.Delete(typ) 135 | if typ.Kind() == reflect.Ptr { 136 | typeDecMap.Delete(typ.Elem()) 137 | } 138 | } 139 | 140 | func makeExtDecoder( 141 | wantedExtID int8, 142 | typ reflect.Type, 143 | decoder func(d *Decoder, v reflect.Value, extLen int) error, 144 | ) decoderFunc { 145 | return nilAwareDecoder(typ, func(d *Decoder, v reflect.Value) error { 146 | extID, extLen, err := d.DecodeExtHeader() 147 | if err != nil { 148 | return err 149 | } 150 | if extID != wantedExtID { 151 | return fmt.Errorf("msgpack: got ext type=%d, wanted %d", extID, wantedExtID) 152 | } 153 | return decoder(d, v, extLen) 154 | }) 155 | } 156 | 157 | func makeExtDecoderAddr(extDecoder decoderFunc) decoderFunc { 158 | return func(d *Decoder, v reflect.Value) error { 159 | if !v.CanAddr() { 160 | return fmt.Errorf("msgpack: DecodeExt(nonaddressable %T)", v.Interface()) 161 | } 162 | return extDecoder(d, v.Addr()) 163 | } 164 | } 165 | 166 | func (e *Encoder) EncodeExtHeader(extID int8, extLen int) error { 167 | if err := e.encodeExtLen(extLen); err != nil { 168 | return err 169 | } 170 | if err := e.w.WriteByte(byte(extID)); err != nil { 171 | return err 172 | } 173 | return nil 174 | } 175 | 176 | func (e *Encoder) encodeExtLen(l int) error { 177 | switch l { 178 | case 1: 179 | return e.writeCode(msgpcode.FixExt1) 180 | case 2: 181 | return e.writeCode(msgpcode.FixExt2) 182 | case 4: 183 | return e.writeCode(msgpcode.FixExt4) 184 | case 8: 185 | return e.writeCode(msgpcode.FixExt8) 186 | case 16: 187 | return e.writeCode(msgpcode.FixExt16) 188 | } 189 | if l <= math.MaxUint8 { 190 | return e.write1(msgpcode.Ext8, uint8(l)) 191 | } 192 | if l <= math.MaxUint16 { 193 | return e.write2(msgpcode.Ext16, uint16(l)) 194 | } 195 | return e.write4(msgpcode.Ext32, uint32(l)) 196 | } 197 | 198 | func (d *Decoder) DecodeExtHeader() (extID int8, extLen int, err error) { 199 | c, err := d.readCode() 200 | if err != nil { 201 | return 202 | } 203 | return d.extHeader(c) 204 | } 205 | 206 | func (d *Decoder) extHeader(c byte) (int8, int, error) { 207 | extLen, err := d.parseExtLen(c) 208 | if err != nil { 209 | return 0, 0, err 210 | } 211 | 212 | extID, err := d.readCode() 213 | if err != nil { 214 | return 0, 0, err 215 | } 216 | 217 | return int8(extID), extLen, nil 218 | } 219 | 220 | func (d *Decoder) parseExtLen(c byte) (int, error) { 221 | switch c { 222 | case msgpcode.FixExt1: 223 | return 1, nil 224 | case msgpcode.FixExt2: 225 | return 2, nil 226 | case msgpcode.FixExt4: 227 | return 4, nil 228 | case msgpcode.FixExt8: 229 | return 8, nil 230 | case msgpcode.FixExt16: 231 | return 16, nil 232 | case msgpcode.Ext8: 233 | n, err := d.uint8() 234 | return int(n), err 235 | case msgpcode.Ext16: 236 | n, err := d.uint16() 237 | return int(n), err 238 | case msgpcode.Ext32: 239 | n, err := d.uint32() 240 | return int(n), err 241 | default: 242 | return 0, fmt.Errorf("msgpack: invalid code=%x decoding ext len", c) 243 | } 244 | } 245 | 246 | func (d *Decoder) decodeInterfaceExt(c byte) (interface{}, error) { 247 | extID, extLen, err := d.extHeader(c) 248 | if err != nil { 249 | return nil, err 250 | } 251 | 252 | info, ok := extTypes[extID] 253 | if !ok { 254 | return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID) 255 | } 256 | 257 | v := d.newValue(info.Type).Elem() 258 | if nilable(v.Kind()) && v.IsNil() { 259 | v.Set(d.newValue(info.Type.Elem())) 260 | } 261 | 262 | if err := info.Decoder(d, v, extLen); err != nil { 263 | return nil, err 264 | } 265 | 266 | return v.Interface(), nil 267 | } 268 | 269 | func (d *Decoder) skipExt(c byte) error { 270 | n, err := d.parseExtLen(c) 271 | if err != nil { 272 | return err 273 | } 274 | return d.skipN(n + 1) 275 | } 276 | 277 | func (d *Decoder) skipExtHeader(c byte) error { 278 | // Read ext type. 279 | _, err := d.readCode() 280 | if err != nil { 281 | return err 282 | } 283 | // Read ext body len. 284 | for i := 0; i < extHeaderLen(c); i++ { 285 | _, err := d.readCode() 286 | if err != nil { 287 | return err 288 | } 289 | } 290 | return nil 291 | } 292 | 293 | func extHeaderLen(c byte) int { 294 | switch c { 295 | case msgpcode.Ext8: 296 | return 1 297 | case msgpcode.Ext16: 298 | return 2 299 | case msgpcode.Ext32: 300 | return 4 301 | } 302 | return 0 303 | } 304 | -------------------------------------------------------------------------------- /ext_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "testing" 7 | "time" 8 | 9 | "github.com/stretchr/testify/require" 10 | "github.com/vmihailenco/msgpack/v5" 11 | "github.com/vmihailenco/msgpack/v5/msgpcode" 12 | ) 13 | 14 | func init() { 15 | msgpack.RegisterExt(9, (*ExtTest)(nil)) 16 | } 17 | 18 | type ExtTest struct { 19 | S string 20 | } 21 | 22 | var ( 23 | _ msgpack.Marshaler = (*ExtTest)(nil) 24 | _ msgpack.Unmarshaler = (*ExtTest)(nil) 25 | ) 26 | 27 | func (ext ExtTest) MarshalMsgpack() ([]byte, error) { 28 | return msgpack.Marshal("hello " + ext.S) 29 | } 30 | 31 | func (ext *ExtTest) UnmarshalMsgpack(b []byte) error { 32 | return msgpack.Unmarshal(b, &ext.S) 33 | } 34 | 35 | func TestEncodeDecodeExtHeader(t *testing.T) { 36 | v := &ExtTest{"world"} 37 | 38 | payload, err := v.MarshalMsgpack() 39 | require.Nil(t, err) 40 | 41 | var buf bytes.Buffer 42 | enc := msgpack.NewEncoder(&buf) 43 | err = enc.EncodeExtHeader(9, len(payload)) 44 | require.Nil(t, err) 45 | 46 | _, err = buf.Write(payload) 47 | require.Nil(t, err) 48 | 49 | var dst interface{} 50 | err = msgpack.Unmarshal(buf.Bytes(), &dst) 51 | require.Nil(t, err) 52 | 53 | v = dst.(*ExtTest) 54 | wanted := "hello world" 55 | require.Equal(t, v.S, wanted) 56 | 57 | dec := msgpack.NewDecoder(&buf) 58 | extID, extLen, err := dec.DecodeExtHeader() 59 | require.Nil(t, err) 60 | require.Equal(t, int8(9), extID) 61 | require.Equal(t, len(payload), extLen) 62 | 63 | data := make([]byte, extLen) 64 | err = dec.ReadFull(data) 65 | require.Nil(t, err) 66 | 67 | v = &ExtTest{} 68 | err = v.UnmarshalMsgpack(data) 69 | require.Nil(t, err) 70 | require.Equal(t, wanted, v.S) 71 | } 72 | 73 | func TestExt(t *testing.T) { 74 | v := &ExtTest{"world"} 75 | b, err := msgpack.Marshal(v) 76 | if err != nil { 77 | t.Fatal(err) 78 | } 79 | 80 | var dst interface{} 81 | err = msgpack.Unmarshal(b, &dst) 82 | if err != nil { 83 | t.Fatal(err) 84 | } 85 | 86 | v, ok := dst.(*ExtTest) 87 | if !ok { 88 | t.Fatalf("got %#v, wanted ExtTest", dst) 89 | } 90 | 91 | wanted := "hello world" 92 | if v.S != wanted { 93 | t.Fatalf("got %q, wanted %q", v.S, wanted) 94 | } 95 | 96 | ext := new(ExtTest) 97 | err = msgpack.Unmarshal(b, &ext) 98 | if err != nil { 99 | t.Fatal(err) 100 | } 101 | if ext.S != wanted { 102 | t.Fatalf("got %q, wanted %q", ext.S, wanted) 103 | } 104 | } 105 | 106 | func TestUnknownExt(t *testing.T) { 107 | b := []byte{byte(msgpcode.FixExt1), 2, 0} 108 | 109 | var dst interface{} 110 | err := msgpack.Unmarshal(b, &dst) 111 | if err == nil { 112 | t.Fatalf("got nil, wanted error") 113 | } 114 | got := err.Error() 115 | wanted := "msgpack: unknown ext id=2" 116 | if got != wanted { 117 | t.Fatalf("got %q, wanted %q", got, wanted) 118 | } 119 | } 120 | 121 | func TestSliceOfTime(t *testing.T) { 122 | in := []interface{}{time.Now()} 123 | b, err := msgpack.Marshal(in) 124 | if err != nil { 125 | t.Fatal(err) 126 | } 127 | 128 | var out []interface{} 129 | err = msgpack.Unmarshal(b, &out) 130 | if err != nil { 131 | t.Fatal(err) 132 | } 133 | 134 | outTime := out[0].(time.Time) 135 | inTime := in[0].(time.Time) 136 | if outTime.Unix() != inTime.Unix() { 137 | t.Fatalf("got %v, wanted %v", outTime, inTime) 138 | } 139 | } 140 | 141 | type customPayload struct { 142 | payload []byte 143 | } 144 | 145 | func (cp *customPayload) MarshalMsgpack() ([]byte, error) { 146 | return cp.payload, nil 147 | } 148 | 149 | func (cp *customPayload) UnmarshalMsgpack(b []byte) error { 150 | cp.payload = b 151 | return nil 152 | } 153 | 154 | func TestDecodeCustomPayload(t *testing.T) { 155 | b, err := hex.DecodeString("c70500c09eec3100") 156 | if err != nil { 157 | t.Fatal(err) 158 | } 159 | 160 | msgpack.RegisterExt(0, (*customPayload)(nil)) 161 | 162 | var cp *customPayload 163 | err = msgpack.Unmarshal(b, &cp) 164 | if err != nil { 165 | t.Fatal(err) 166 | } 167 | 168 | payload := hex.EncodeToString(cp.payload) 169 | wanted := "c09eec3100" 170 | if payload != wanted { 171 | t.Fatalf("got %q, wanted %q", payload, wanted) 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /extra/msgpappengine/appengine.go: -------------------------------------------------------------------------------- 1 | package msgpappengine 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/vmihailenco/msgpack/v5" 7 | ds "google.golang.org/appengine/datastore" 8 | ) 9 | 10 | func init() { 11 | msgpack.Register((*ds.Key)(nil), encodeDatastoreKeyValue, decodeDatastoreKeyValue) 12 | msgpack.Register((*ds.Cursor)(nil), encodeDatastoreCursorValue, decodeDatastoreCursorValue) 13 | } 14 | 15 | func EncodeDatastoreKey(e *msgpack.Encoder, key *ds.Key) error { 16 | if key == nil { 17 | return e.EncodeNil() 18 | } 19 | return e.EncodeString(key.Encode()) 20 | } 21 | 22 | func encodeDatastoreKeyValue(e *msgpack.Encoder, v reflect.Value) error { 23 | key := v.Interface().(*ds.Key) 24 | return EncodeDatastoreKey(e, key) 25 | } 26 | 27 | func DecodeDatastoreKey(d *msgpack.Decoder) (*ds.Key, error) { 28 | v, err := d.DecodeString() 29 | if err != nil { 30 | return nil, err 31 | } 32 | if v == "" { 33 | return nil, nil 34 | } 35 | return ds.DecodeKey(v) 36 | } 37 | 38 | func decodeDatastoreKeyValue(d *msgpack.Decoder, v reflect.Value) error { 39 | key, err := DecodeDatastoreKey(d) 40 | if err != nil { 41 | return err 42 | } 43 | v.Set(reflect.ValueOf(key)) 44 | return nil 45 | } 46 | 47 | func encodeDatastoreCursorValue(e *msgpack.Encoder, v reflect.Value) error { 48 | cursor := v.Interface().(ds.Cursor) 49 | return e.Encode(cursor.String()) 50 | } 51 | 52 | func decodeDatastoreCursorValue(d *msgpack.Decoder, v reflect.Value) error { 53 | s, err := d.DecodeString() 54 | if err != nil { 55 | return err 56 | } 57 | cursor, err := ds.DecodeCursor(s) 58 | if err != nil { 59 | return err 60 | } 61 | v.Set(reflect.ValueOf(cursor)) 62 | return nil 63 | } 64 | -------------------------------------------------------------------------------- /extra/msgpappengine/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/vmihailenco/msgpack/extra/appengine 2 | 3 | go 1.15 4 | 5 | replace github.com/vmihailenco/msgpack/v5 => ../.. 6 | 7 | require ( 8 | github.com/vmihailenco/msgpack/v5 v5.4.1 9 | google.golang.org/appengine v1.6.7 10 | ) 11 | -------------------------------------------------------------------------------- /extra/msgpappengine/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= 4 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 9 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 10 | github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= 11 | github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 12 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 13 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65 h1:+rhAzEzT3f4JtomfC371qB+0Ola2caSKcY69NUBZrRQ= 14 | golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= 15 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 16 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 17 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 18 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 19 | google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= 20 | google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= 21 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 22 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 23 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 25 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/vmihailenco/msgpack/v5 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/stretchr/testify v1.6.1 7 | github.com/vmihailenco/tagparser/v2 v2.0.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.0 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 7 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= 9 | github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= 10 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 11 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 12 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 14 | -------------------------------------------------------------------------------- /intern.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "reflect" 7 | 8 | "github.com/vmihailenco/msgpack/v5/msgpcode" 9 | ) 10 | 11 | const ( 12 | minInternedStringLen = 3 13 | maxDictLen = math.MaxUint16 14 | ) 15 | 16 | var internedStringExtID = int8(math.MinInt8) 17 | 18 | func init() { 19 | extTypes[internedStringExtID] = &extInfo{ 20 | Type: stringType, 21 | Decoder: decodeInternedStringExt, 22 | } 23 | } 24 | 25 | func decodeInternedStringExt(d *Decoder, v reflect.Value, extLen int) error { 26 | idx, err := d.decodeInternedStringIndex(extLen) 27 | if err != nil { 28 | return err 29 | } 30 | 31 | s, err := d.internedStringAtIndex(idx) 32 | if err != nil { 33 | return err 34 | } 35 | 36 | v.SetString(s) 37 | return nil 38 | } 39 | 40 | //------------------------------------------------------------------------------ 41 | 42 | func encodeInternedInterfaceValue(e *Encoder, v reflect.Value) error { 43 | if v.IsNil() { 44 | return e.EncodeNil() 45 | } 46 | 47 | v = v.Elem() 48 | if v.Kind() == reflect.String { 49 | return e.encodeInternedString(v.String(), true) 50 | } 51 | return e.EncodeValue(v) 52 | } 53 | 54 | func encodeInternedStringValue(e *Encoder, v reflect.Value) error { 55 | return e.encodeInternedString(v.String(), true) 56 | } 57 | 58 | func (e *Encoder) encodeInternedString(s string, intern bool) error { 59 | // Interned string takes at least 3 bytes. Plain string 1 byte + string len. 60 | if idx, ok := e.dict[s]; ok { 61 | return e.encodeInternedStringIndex(idx) 62 | } 63 | 64 | if intern && len(s) >= minInternedStringLen && len(e.dict) < maxDictLen { 65 | if e.dict == nil { 66 | e.dict = make(map[string]int) 67 | } 68 | idx := len(e.dict) 69 | e.dict[s] = idx 70 | } 71 | 72 | return e.encodeNormalString(s) 73 | } 74 | 75 | func (e *Encoder) encodeInternedStringIndex(idx int) error { 76 | if idx <= math.MaxUint8 { 77 | if err := e.writeCode(msgpcode.FixExt1); err != nil { 78 | return err 79 | } 80 | return e.write1(byte(internedStringExtID), uint8(idx)) 81 | } 82 | 83 | if idx <= math.MaxUint16 { 84 | if err := e.writeCode(msgpcode.FixExt2); err != nil { 85 | return err 86 | } 87 | return e.write2(byte(internedStringExtID), uint16(idx)) 88 | } 89 | 90 | if uint64(idx) <= math.MaxUint32 { 91 | if err := e.writeCode(msgpcode.FixExt4); err != nil { 92 | return err 93 | } 94 | return e.write4(byte(internedStringExtID), uint32(idx)) 95 | } 96 | 97 | return fmt.Errorf("msgpack: interned string index=%d is too large", idx) 98 | } 99 | 100 | //------------------------------------------------------------------------------ 101 | 102 | func decodeInternedInterfaceValue(d *Decoder, v reflect.Value) error { 103 | s, err := d.decodeInternedString(true) 104 | if err == nil { 105 | v.Set(reflect.ValueOf(s)) 106 | return nil 107 | } 108 | if err != nil { 109 | if _, ok := err.(unexpectedCodeError); !ok { 110 | return err 111 | } 112 | } 113 | 114 | if err := d.s.UnreadByte(); err != nil { 115 | return err 116 | } 117 | return decodeInterfaceValue(d, v) 118 | } 119 | 120 | func decodeInternedStringValue(d *Decoder, v reflect.Value) error { 121 | s, err := d.decodeInternedString(true) 122 | if err != nil { 123 | return err 124 | } 125 | 126 | v.SetString(s) 127 | return nil 128 | } 129 | 130 | func (d *Decoder) decodeInternedString(intern bool) (string, error) { 131 | c, err := d.readCode() 132 | if err != nil { 133 | return "", err 134 | } 135 | 136 | if msgpcode.IsFixedString(c) { 137 | n := int(c & msgpcode.FixedStrMask) 138 | return d.decodeInternedStringWithLen(n, intern) 139 | } 140 | 141 | switch c { 142 | case msgpcode.Nil: 143 | return "", nil 144 | case msgpcode.FixExt1, msgpcode.FixExt2, msgpcode.FixExt4: 145 | typeID, extLen, err := d.extHeader(c) 146 | if err != nil { 147 | return "", err 148 | } 149 | if typeID != internedStringExtID { 150 | err := fmt.Errorf("msgpack: got ext type=%d, wanted %d", 151 | typeID, internedStringExtID) 152 | return "", err 153 | } 154 | 155 | idx, err := d.decodeInternedStringIndex(extLen) 156 | if err != nil { 157 | return "", err 158 | } 159 | 160 | return d.internedStringAtIndex(idx) 161 | case msgpcode.Str8, msgpcode.Bin8: 162 | n, err := d.uint8() 163 | if err != nil { 164 | return "", err 165 | } 166 | return d.decodeInternedStringWithLen(int(n), intern) 167 | case msgpcode.Str16, msgpcode.Bin16: 168 | n, err := d.uint16() 169 | if err != nil { 170 | return "", err 171 | } 172 | return d.decodeInternedStringWithLen(int(n), intern) 173 | case msgpcode.Str32, msgpcode.Bin32: 174 | n, err := d.uint32() 175 | if err != nil { 176 | return "", err 177 | } 178 | return d.decodeInternedStringWithLen(int(n), intern) 179 | } 180 | 181 | return "", unexpectedCodeError{ 182 | code: c, 183 | hint: "interned string", 184 | } 185 | } 186 | 187 | func (d *Decoder) decodeInternedStringIndex(extLen int) (int, error) { 188 | switch extLen { 189 | case 1: 190 | n, err := d.uint8() 191 | if err != nil { 192 | return 0, err 193 | } 194 | return int(n), nil 195 | case 2: 196 | n, err := d.uint16() 197 | if err != nil { 198 | return 0, err 199 | } 200 | return int(n), nil 201 | case 4: 202 | n, err := d.uint32() 203 | if err != nil { 204 | return 0, err 205 | } 206 | return int(n), nil 207 | } 208 | 209 | err := fmt.Errorf("msgpack: unsupported ext len=%d decoding interned string", extLen) 210 | return 0, err 211 | } 212 | 213 | func (d *Decoder) internedStringAtIndex(idx int) (string, error) { 214 | if idx >= len(d.dict) { 215 | err := fmt.Errorf("msgpack: interned string at index=%d does not exist", idx) 216 | return "", err 217 | } 218 | return d.dict[idx], nil 219 | } 220 | 221 | func (d *Decoder) decodeInternedStringWithLen(n int, intern bool) (string, error) { 222 | if n <= 0 { 223 | return "", nil 224 | } 225 | 226 | s, err := d.stringWithLen(n) 227 | if err != nil { 228 | return "", err 229 | } 230 | 231 | if intern && len(s) >= minInternedStringLen && len(d.dict) < maxDictLen { 232 | d.dict = append(d.dict, s) 233 | } 234 | 235 | return s, nil 236 | } 237 | -------------------------------------------------------------------------------- /intern_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/require" 9 | "github.com/vmihailenco/msgpack/v5" 10 | ) 11 | 12 | type NoIntern struct { 13 | A string 14 | B string 15 | C interface{} 16 | } 17 | 18 | type Intern struct { 19 | A string `msgpack:",intern"` 20 | B string `msgpack:",intern"` 21 | C interface{} `msgpack:",intern"` 22 | } 23 | 24 | func TestInternedString(t *testing.T) { 25 | var buf bytes.Buffer 26 | 27 | enc := msgpack.NewEncoder(&buf) 28 | enc.UseInternedStrings(true) 29 | 30 | dec := msgpack.NewDecoder(&buf) 31 | dec.UseInternedStrings(true) 32 | 33 | for i := 0; i < 3; i++ { 34 | err := enc.EncodeString("hello") 35 | require.Nil(t, err) 36 | } 37 | 38 | for i := 0; i < 3; i++ { 39 | s, err := dec.DecodeString() 40 | require.Nil(t, err) 41 | require.Equal(t, "hello", s) 42 | } 43 | 44 | err := enc.Encode("hello") 45 | require.Nil(t, err) 46 | 47 | v, err := dec.DecodeInterface() 48 | require.Nil(t, err) 49 | require.Equal(t, "hello", v) 50 | 51 | _, err = dec.DecodeInterface() 52 | require.Equal(t, io.EOF, err) 53 | } 54 | 55 | func TestInternedStringTag(t *testing.T) { 56 | var buf bytes.Buffer 57 | enc := msgpack.NewEncoder(&buf) 58 | dec := msgpack.NewDecoder(&buf) 59 | 60 | in := []Intern{ 61 | {"f", "f", "f"}, 62 | {"fo", "fo", "fo"}, 63 | {"foo", "foo", "foo"}, 64 | {"f", "fo", "foo"}, 65 | } 66 | err := enc.Encode(in) 67 | require.Nil(t, err) 68 | 69 | var out []Intern 70 | err = dec.Decode(&out) 71 | require.Nil(t, err) 72 | require.Equal(t, in, out) 73 | } 74 | 75 | func TestResetDict(t *testing.T) { 76 | dict := []string{"hello world", "foo bar"} 77 | 78 | var buf bytes.Buffer 79 | enc := msgpack.NewEncoder(&buf) 80 | dec := msgpack.NewDecoder(&buf) 81 | 82 | { 83 | enc.ResetDict(&buf, dictMap(dict)) 84 | err := enc.EncodeString("hello world") 85 | require.Nil(t, err) 86 | require.Equal(t, 3, buf.Len()) 87 | 88 | dec.ResetDict(&buf, dict) 89 | s, err := dec.DecodeString() 90 | require.Nil(t, err) 91 | require.Equal(t, "hello world", s) 92 | } 93 | 94 | { 95 | enc.ResetDict(&buf, dictMap(dict)) 96 | err := enc.Encode("foo bar") 97 | require.Nil(t, err) 98 | require.Equal(t, 3, buf.Len()) 99 | 100 | dec.ResetDict(&buf, dict) 101 | s, err := dec.DecodeInterface() 102 | require.Nil(t, err) 103 | require.Equal(t, "foo bar", s) 104 | } 105 | 106 | dec.ResetDict(&buf, dict) 107 | _ = enc.EncodeString("xxxx") 108 | require.Equal(t, 5, buf.Len()) 109 | _ = enc.Encode("xxxx") 110 | require.Equal(t, 10, buf.Len()) 111 | } 112 | 113 | func TestMapWithInternedString(t *testing.T) { 114 | type M map[string]interface{} 115 | 116 | dict := []string{"hello world", "foo bar"} 117 | 118 | var buf bytes.Buffer 119 | 120 | enc := msgpack.NewEncoder(nil) 121 | enc.ResetDict(&buf, dictMap(dict)) 122 | 123 | dec := msgpack.NewDecoder(nil) 124 | dec.ResetDict(&buf, dict) 125 | 126 | for i := 0; i < 100; i++ { 127 | in := M{ 128 | "foo bar": "hello world", 129 | "hello world": "foo bar", 130 | "foo": "bar", 131 | } 132 | err := enc.Encode(in) 133 | require.Nil(t, err) 134 | 135 | _, err = dec.DecodeInterface() 136 | require.Nil(t, err) 137 | } 138 | } 139 | 140 | func dictMap(dict []string) map[string]int { 141 | m := make(map[string]int, len(dict)) 142 | for i, s := range dict { 143 | m[s] = i 144 | } 145 | return m 146 | } 147 | -------------------------------------------------------------------------------- /msgpack.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import "fmt" 4 | 5 | type Marshaler interface { 6 | MarshalMsgpack() ([]byte, error) 7 | } 8 | 9 | type Unmarshaler interface { 10 | UnmarshalMsgpack([]byte) error 11 | } 12 | 13 | type CustomEncoder interface { 14 | EncodeMsgpack(*Encoder) error 15 | } 16 | 17 | type CustomDecoder interface { 18 | DecodeMsgpack(*Decoder) error 19 | } 20 | 21 | //------------------------------------------------------------------------------ 22 | 23 | type RawMessage []byte 24 | 25 | var ( 26 | _ CustomEncoder = (RawMessage)(nil) 27 | _ CustomDecoder = (*RawMessage)(nil) 28 | ) 29 | 30 | func (m RawMessage) EncodeMsgpack(enc *Encoder) error { 31 | return enc.write(m) 32 | } 33 | 34 | func (m *RawMessage) DecodeMsgpack(dec *Decoder) error { 35 | msg, err := dec.DecodeRaw() 36 | if err != nil { 37 | return err 38 | } 39 | *m = msg 40 | return nil 41 | } 42 | 43 | //------------------------------------------------------------------------------ 44 | 45 | type unexpectedCodeError struct { 46 | hint string 47 | code byte 48 | } 49 | 50 | func (err unexpectedCodeError) Error() string { 51 | return fmt.Sprintf("msgpack: unexpected code=%x decoding %s", err.code, err.hint) 52 | } 53 | -------------------------------------------------------------------------------- /msgpack_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "math" 8 | "reflect" 9 | "testing" 10 | "time" 11 | 12 | "github.com/stretchr/testify/require" 13 | "github.com/stretchr/testify/suite" 14 | "github.com/vmihailenco/msgpack/v5" 15 | ) 16 | 17 | type nameStruct struct { 18 | Name string 19 | } 20 | 21 | type MsgpackTest struct { 22 | suite.Suite 23 | 24 | buf *bytes.Buffer 25 | enc *msgpack.Encoder 26 | dec *msgpack.Decoder 27 | } 28 | 29 | func (t *MsgpackTest) SetupTest() { 30 | t.buf = &bytes.Buffer{} 31 | t.enc = msgpack.NewEncoder(t.buf) 32 | t.dec = msgpack.NewDecoder(bufio.NewReader(t.buf)) 33 | } 34 | 35 | func TestMsgpackTestSuite(t *testing.T) { 36 | suite.Run(t, new(MsgpackTest)) 37 | } 38 | 39 | func (t *MsgpackTest) TestDecodeNil() { 40 | t.NotNil(t.dec.Decode(nil)) 41 | } 42 | 43 | func (t *MsgpackTest) TestTime() { 44 | in := time.Now() 45 | var out time.Time 46 | 47 | t.Nil(t.enc.Encode(in)) 48 | t.Nil(t.dec.Decode(&out)) 49 | t.True(out.Equal(in)) 50 | 51 | var zero time.Time 52 | t.Nil(t.enc.Encode(zero)) 53 | t.Nil(t.dec.Decode(&out)) 54 | t.True(out.Equal(zero)) 55 | t.True(out.IsZero()) 56 | } 57 | 58 | func (t *MsgpackTest) TestLargeBytes() { 59 | N := int(1e6) 60 | 61 | src := bytes.Repeat([]byte{'1'}, N) 62 | t.Nil(t.enc.Encode(src)) 63 | var dst []byte 64 | t.Nil(t.dec.Decode(&dst)) 65 | t.Equal(dst, src) 66 | } 67 | 68 | func (t *MsgpackTest) TestLargeString() { 69 | N := int(1e6) 70 | 71 | src := string(bytes.Repeat([]byte{'1'}, N)) 72 | t.Nil(t.enc.Encode(src)) 73 | var dst string 74 | t.Nil(t.dec.Decode(&dst)) 75 | t.Equal(dst, src) 76 | } 77 | 78 | func (t *MsgpackTest) TestSliceOfStructs() { 79 | in := []*nameStruct{{"hello"}} 80 | var out []*nameStruct 81 | t.Nil(t.enc.Encode(in)) 82 | t.Nil(t.dec.Decode(&out)) 83 | t.Equal(out, in) 84 | } 85 | 86 | func (t *MsgpackTest) TestMap() { 87 | for _, i := range []struct { 88 | m map[string]string 89 | b []byte 90 | }{ 91 | {map[string]string{}, []byte{0x80}}, 92 | {map[string]string{"hello": "world"}, []byte{0x81, 0xa5, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0xa5, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, 93 | } { 94 | t.Nil(t.enc.Encode(i.m)) 95 | t.Equal(t.buf.Bytes(), i.b, fmt.Errorf("err encoding %v", i.m)) 96 | var m map[string]string 97 | t.Nil(t.dec.Decode(&m)) 98 | t.Equal(m, i.m) 99 | } 100 | } 101 | 102 | func (t *MsgpackTest) TestStructNil() { 103 | var dst *nameStruct 104 | 105 | t.Nil(t.enc.Encode(nameStruct{Name: "foo"})) 106 | t.Nil(t.dec.Decode(&dst)) 107 | t.NotNil(dst) 108 | t.Equal(dst.Name, "foo") 109 | } 110 | 111 | func (t *MsgpackTest) TestStructUnknownField() { 112 | in := struct { 113 | Field1 string 114 | Field2 string 115 | Field3 string 116 | }{ 117 | Field1: "value1", 118 | Field2: "value2", 119 | Field3: "value3", 120 | } 121 | t.Nil(t.enc.Encode(in)) 122 | 123 | out := struct { 124 | Field2 string 125 | }{} 126 | t.Nil(t.dec.Decode(&out)) 127 | t.Equal(out.Field2, "value2") 128 | } 129 | 130 | //------------------------------------------------------------------------------ 131 | 132 | type coderStruct struct { 133 | name string 134 | } 135 | 136 | type wrapperStruct struct { 137 | coderStruct 138 | } 139 | 140 | var ( 141 | _ msgpack.CustomEncoder = (*coderStruct)(nil) 142 | _ msgpack.CustomDecoder = (*coderStruct)(nil) 143 | ) 144 | 145 | func (s *coderStruct) Name() string { 146 | return s.name 147 | } 148 | 149 | func (s *coderStruct) EncodeMsgpack(enc *msgpack.Encoder) error { 150 | return enc.Encode(s.name) 151 | } 152 | 153 | func (s *coderStruct) DecodeMsgpack(dec *msgpack.Decoder) error { 154 | return dec.Decode(&s.name) 155 | } 156 | 157 | func (t *MsgpackTest) TestCoder() { 158 | in := &coderStruct{name: "hello"} 159 | var out coderStruct 160 | t.Nil(t.enc.Encode(in)) 161 | t.Nil(t.dec.Decode(&out)) 162 | t.Equal(out.Name(), "hello") 163 | } 164 | 165 | func (t *MsgpackTest) TestNilCoder() { 166 | in := &coderStruct{name: "hello"} 167 | var out *coderStruct 168 | t.Nil(t.enc.Encode(in)) 169 | t.Nil(t.dec.Decode(&out)) 170 | t.Equal(out.Name(), "hello") 171 | } 172 | 173 | func (t *MsgpackTest) TestNilCoderValue() { 174 | in := &coderStruct{name: "hello"} 175 | var out *coderStruct 176 | t.Nil(t.enc.Encode(in)) 177 | t.Nil(t.dec.DecodeValue(reflect.ValueOf(&out))) 178 | t.Equal(out.Name(), "hello") 179 | } 180 | 181 | func (t *MsgpackTest) TestPtrToCoder() { 182 | in := &coderStruct{name: "hello"} 183 | var out coderStruct 184 | out2 := &out 185 | t.Nil(t.enc.Encode(in)) 186 | t.Nil(t.dec.Decode(&out2)) 187 | t.Equal(out.Name(), "hello") 188 | } 189 | 190 | func (t *MsgpackTest) TestWrappedCoder() { 191 | in := &wrapperStruct{coderStruct: coderStruct{name: "hello"}} 192 | var out wrapperStruct 193 | t.Nil(t.enc.Encode(in)) 194 | t.Nil(t.dec.Decode(&out)) 195 | t.Equal(out.Name(), "hello") 196 | } 197 | 198 | //------------------------------------------------------------------------------ 199 | 200 | type struct2 struct { 201 | Name string 202 | } 203 | 204 | type struct1 struct { 205 | Name string 206 | Struct2 struct2 207 | } 208 | 209 | func (t *MsgpackTest) TestNestedStructs() { 210 | in := &struct1{Name: "hello", Struct2: struct2{Name: "world"}} 211 | var out struct1 212 | t.Nil(t.enc.Encode(in)) 213 | t.Nil(t.dec.Decode(&out)) 214 | t.Equal(out.Name, in.Name) 215 | t.Equal(out.Struct2.Name, in.Struct2.Name) 216 | } 217 | 218 | type Struct4 struct { 219 | Name2 string 220 | } 221 | 222 | type Struct3 struct { 223 | Struct4 224 | Name1 string 225 | } 226 | 227 | func TestEmbedding(t *testing.T) { 228 | in := &Struct3{ 229 | Name1: "hello", 230 | Struct4: Struct4{ 231 | Name2: "world", 232 | }, 233 | } 234 | var out Struct3 235 | 236 | b, err := msgpack.Marshal(in) 237 | if err != nil { 238 | t.Fatal(err) 239 | } 240 | 241 | err = msgpack.Unmarshal(b, &out) 242 | if err != nil { 243 | t.Fatal(err) 244 | } 245 | if out.Name1 != in.Name1 { 246 | t.Fatalf("") 247 | } 248 | if out.Name2 != in.Name2 { 249 | t.Fatalf("") 250 | } 251 | } 252 | 253 | func TestEmptyTimeMarshalWithInterface(t *testing.T) { 254 | a := time.Time{} 255 | b, err := msgpack.Marshal(a) 256 | if err != nil { 257 | t.Fatal(err) 258 | } 259 | var out interface{} 260 | err = msgpack.Unmarshal(b, &out) 261 | if err != nil { 262 | t.Fatal(err) 263 | } 264 | name, _ := out.(time.Time).Zone() 265 | if name != "UTC" { 266 | t.Fatal("Got wrong timezone") 267 | } 268 | 269 | var out2 time.Time 270 | err = msgpack.Unmarshal(b, &out2) 271 | if err != nil { 272 | t.Fatal(err) 273 | } 274 | name, _ = out2.Zone() 275 | if name != "UTC" { 276 | t.Fatal("Got wrong timezone") 277 | } 278 | } 279 | 280 | func (t *MsgpackTest) TestSliceNil() { 281 | in := [][]*int{nil} 282 | var out [][]*int 283 | 284 | t.Nil(t.enc.Encode(in)) 285 | t.Nil(t.dec.Decode(&out)) 286 | t.Equal(out, in) 287 | } 288 | 289 | //------------------------------------------------------------------------------ 290 | 291 | //------------------------------------------------------------------------------ 292 | 293 | func TestNoPanicOnUnsupportedKey(t *testing.T) { 294 | data := []byte{0x81, 0x81, 0xa1, 0x78, 0xc3, 0xc3} 295 | 296 | _, err := msgpack.NewDecoder(bytes.NewReader(data)).DecodeTypedMap() 297 | require.EqualError(t, err, "msgpack: unsupported map key: map[string]interface {}") 298 | } 299 | 300 | func TestMapDefault(t *testing.T) { 301 | in := map[string]interface{}{ 302 | "foo": "bar", 303 | "hello": map[string]interface{}{ 304 | "foo": "bar", 305 | }, 306 | } 307 | b, err := msgpack.Marshal(in) 308 | require.Nil(t, err) 309 | 310 | var out map[string]interface{} 311 | err = msgpack.Unmarshal(b, &out) 312 | require.Nil(t, err) 313 | require.Equal(t, in, out) 314 | } 315 | 316 | func TestRawMessage(t *testing.T) { 317 | type In struct { 318 | Foo map[string]interface{} 319 | } 320 | 321 | type Out struct { 322 | Foo msgpack.RawMessage 323 | } 324 | 325 | type Out2 struct { 326 | Foo interface{} 327 | } 328 | 329 | b, err := msgpack.Marshal(&In{ 330 | Foo: map[string]interface{}{ 331 | "hello": "world", 332 | }, 333 | }) 334 | require.Nil(t, err) 335 | 336 | var out Out 337 | err = msgpack.Unmarshal(b, &out) 338 | require.Nil(t, err) 339 | 340 | var m map[string]string 341 | err = msgpack.Unmarshal(out.Foo, &m) 342 | require.Nil(t, err) 343 | require.Equal(t, map[string]string{ 344 | "hello": "world", 345 | }, m) 346 | 347 | msg := new(msgpack.RawMessage) 348 | out2 := Out2{ 349 | Foo: msg, 350 | } 351 | err = msgpack.Unmarshal(b, &out2) 352 | require.Nil(t, err) 353 | require.Equal(t, out.Foo, *msg) 354 | } 355 | 356 | func TestInterface(t *testing.T) { 357 | type Interface struct { 358 | Foo interface{} 359 | } 360 | 361 | in := Interface{Foo: "foo"} 362 | b, err := msgpack.Marshal(in) 363 | require.Nil(t, err) 364 | 365 | var str string 366 | out := Interface{Foo: &str} 367 | err = msgpack.Unmarshal(b, &out) 368 | require.Nil(t, err) 369 | require.Equal(t, "foo", str) 370 | } 371 | 372 | func TestNaN(t *testing.T) { 373 | in := float64(math.NaN()) 374 | b, err := msgpack.Marshal(in) 375 | require.Nil(t, err) 376 | 377 | var out float64 378 | err = msgpack.Unmarshal(b, &out) 379 | require.Nil(t, err) 380 | require.True(t, math.IsNaN(out)) 381 | } 382 | 383 | func TestSetSortMapKeys(t *testing.T) { 384 | in := map[string]interface{}{ 385 | "a": "a", 386 | "b": "b", 387 | "c": "c", 388 | "d": "d", 389 | } 390 | 391 | var buf bytes.Buffer 392 | enc := msgpack.NewEncoder(&buf) 393 | enc.SetSortMapKeys(true) 394 | dec := msgpack.NewDecoder(&buf) 395 | 396 | err := enc.Encode(in) 397 | require.Nil(t, err) 398 | 399 | wanted := make([]byte, buf.Len()) 400 | copy(wanted, buf.Bytes()) 401 | buf.Reset() 402 | 403 | for i := 0; i < 100; i++ { 404 | err := enc.Encode(in) 405 | require.Nil(t, err) 406 | require.Equal(t, wanted, buf.Bytes()) 407 | 408 | out, err := dec.DecodeMap() 409 | require.Nil(t, err) 410 | require.Equal(t, in, out) 411 | } 412 | } 413 | 414 | func TestSetOmitEmpty(t *testing.T) { 415 | var buf bytes.Buffer 416 | enc := msgpack.NewEncoder(&buf) 417 | enc.SetOmitEmpty(true) 418 | err := enc.Encode(EmbeddingPtrTest{}) 419 | require.Nil(t, err) 420 | 421 | var t2 *EmbeddingPtrTest 422 | dec := msgpack.NewDecoder(&buf) 423 | err = dec.Decode(&t2) 424 | require.Nil(t, err) 425 | require.Nil(t, t2.Exported) 426 | 427 | type Nested struct { 428 | Foo string 429 | Bar string 430 | } 431 | type Item struct { 432 | X Nested 433 | Y *Nested 434 | } 435 | i := Item{} 436 | buf.Reset() 437 | err = enc.Encode(i) 438 | require.Nil(t, err) 439 | require.NotContains(t, buf.Bytes(), byte('X')) 440 | require.NotContains(t, buf.Bytes(), byte('Y')) 441 | 442 | i = Item{Y: &Nested{}} 443 | buf.Reset() 444 | err = enc.Encode(i) 445 | require.Nil(t, err) 446 | require.NotContains(t, buf.Bytes(), byte('X')) 447 | require.Contains(t, buf.Bytes(), byte('Y')) 448 | } 449 | 450 | type NullInt struct { 451 | Valid bool 452 | Int int 453 | } 454 | 455 | func (i *NullInt) Set(j int) { 456 | i.Int = j 457 | i.Valid = true 458 | } 459 | 460 | func (i NullInt) IsZero() bool { 461 | return !i.Valid 462 | } 463 | 464 | func (i NullInt) MarshalMsgpack() ([]byte, error) { 465 | return msgpack.Marshal(i.Int) 466 | } 467 | 468 | func (i *NullInt) UnmarshalMsgpack(b []byte) error { 469 | if err := msgpack.Unmarshal(b, &i.Int); err != nil { 470 | return err 471 | } 472 | i.Valid = true 473 | return nil 474 | } 475 | 476 | type Secretive struct { 477 | Visible bool 478 | hidden bool 479 | } 480 | 481 | type T struct { 482 | I NullInt `msgpack:",omitempty"` 483 | J NullInt 484 | // Secretive is not a "simple" struct because it has an hidden field. 485 | S Secretive `msgpack:",omitempty"` 486 | } 487 | 488 | func ExampleMarshal_ignore_simple_zero_structs_when_tagged_with_omitempty() { 489 | var t1 T 490 | raw, err := msgpack.Marshal(t1) 491 | if err != nil { 492 | panic(err) 493 | } 494 | var t2 T 495 | if err = msgpack.Unmarshal(raw, &t2); err != nil { 496 | panic(err) 497 | } 498 | fmt.Printf("%#v\n", t2) 499 | 500 | t2.I.Set(42) 501 | t2.S.hidden = true // won't be included because it is a hidden field 502 | raw, err = msgpack.Marshal(t2) 503 | if err != nil { 504 | panic(err) 505 | } 506 | var t3 T 507 | if err = msgpack.Unmarshal(raw, &t3); err != nil { 508 | panic(err) 509 | } 510 | fmt.Printf("%#v\n", t3) 511 | // Output: msgpack_test.T{I:msgpack_test.NullInt{Valid:false, Int:0}, J:msgpack_test.NullInt{Valid:true, Int:0}, S:msgpack_test.Secretive{Visible:false, hidden:false}} 512 | // msgpack_test.T{I:msgpack_test.NullInt{Valid:true, Int:42}, J:msgpack_test.NullInt{Valid:true, Int:0}, S:msgpack_test.Secretive{Visible:false, hidden:false}} 513 | } 514 | 515 | type ( 516 | Value interface{} 517 | Wrapper struct { 518 | Value Value `msgpack:"v,omitempty"` 519 | } 520 | ) 521 | 522 | func TestEncodeWrappedValue(t *testing.T) { 523 | v := (*time.Time)(nil) 524 | c := &Wrapper{ 525 | Value: v, 526 | } 527 | var buf bytes.Buffer 528 | require.Nil(t, msgpack.NewEncoder(&buf).Encode(v)) 529 | require.Nil(t, msgpack.NewEncoder(&buf).Encode(c)) 530 | } 531 | 532 | func TestPtrValueDecode(t *testing.T) { 533 | type Foo struct { 534 | Bar *int 535 | } 536 | 537 | b, err := msgpack.Marshal(Foo{}) 538 | require.Nil(t, err) 539 | 540 | bar1 := 123 541 | foo := Foo{Bar: &bar1} 542 | 543 | err = msgpack.Unmarshal(b, &foo) 544 | require.Nil(t, err) 545 | require.Nil(t, foo.Bar) 546 | 547 | bar2 := 456 548 | b, err = msgpack.Marshal(Foo{Bar: &bar2}) 549 | require.Nil(t, err) 550 | 551 | err = msgpack.Unmarshal(b, &foo) 552 | require.Nil(t, err) 553 | require.NotNil(t, foo.Bar) 554 | require.Equal(t, *foo.Bar, bar2) 555 | } 556 | -------------------------------------------------------------------------------- /msgpcode/msgpcode.go: -------------------------------------------------------------------------------- 1 | package msgpcode 2 | 3 | var ( 4 | PosFixedNumHigh byte = 0x7f 5 | NegFixedNumLow byte = 0xe0 6 | 7 | Nil byte = 0xc0 8 | 9 | False byte = 0xc2 10 | True byte = 0xc3 11 | 12 | Float byte = 0xca 13 | Double byte = 0xcb 14 | 15 | Uint8 byte = 0xcc 16 | Uint16 byte = 0xcd 17 | Uint32 byte = 0xce 18 | Uint64 byte = 0xcf 19 | 20 | Int8 byte = 0xd0 21 | Int16 byte = 0xd1 22 | Int32 byte = 0xd2 23 | Int64 byte = 0xd3 24 | 25 | FixedStrLow byte = 0xa0 26 | FixedStrHigh byte = 0xbf 27 | FixedStrMask byte = 0x1f 28 | Str8 byte = 0xd9 29 | Str16 byte = 0xda 30 | Str32 byte = 0xdb 31 | 32 | Bin8 byte = 0xc4 33 | Bin16 byte = 0xc5 34 | Bin32 byte = 0xc6 35 | 36 | FixedArrayLow byte = 0x90 37 | FixedArrayHigh byte = 0x9f 38 | FixedArrayMask byte = 0xf 39 | Array16 byte = 0xdc 40 | Array32 byte = 0xdd 41 | 42 | FixedMapLow byte = 0x80 43 | FixedMapHigh byte = 0x8f 44 | FixedMapMask byte = 0xf 45 | Map16 byte = 0xde 46 | Map32 byte = 0xdf 47 | 48 | FixExt1 byte = 0xd4 49 | FixExt2 byte = 0xd5 50 | FixExt4 byte = 0xd6 51 | FixExt8 byte = 0xd7 52 | FixExt16 byte = 0xd8 53 | Ext8 byte = 0xc7 54 | Ext16 byte = 0xc8 55 | Ext32 byte = 0xc9 56 | ) 57 | 58 | func IsFixedNum(c byte) bool { 59 | return c <= PosFixedNumHigh || c >= NegFixedNumLow 60 | } 61 | 62 | func IsFixedMap(c byte) bool { 63 | return c >= FixedMapLow && c <= FixedMapHigh 64 | } 65 | 66 | func IsFixedArray(c byte) bool { 67 | return c >= FixedArrayLow && c <= FixedArrayHigh 68 | } 69 | 70 | func IsFixedString(c byte) bool { 71 | return c >= FixedStrLow && c <= FixedStrHigh 72 | } 73 | 74 | func IsString(c byte) bool { 75 | return IsFixedString(c) || c == Str8 || c == Str16 || c == Str32 76 | } 77 | 78 | func IsBin(c byte) bool { 79 | return c == Bin8 || c == Bin16 || c == Bin32 80 | } 81 | 82 | func IsFixedExt(c byte) bool { 83 | return c >= FixExt1 && c <= FixExt16 84 | } 85 | 86 | func IsExt(c byte) bool { 87 | return IsFixedExt(c) || c == Ext8 || c == Ext16 || c == Ext32 88 | } 89 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "msgpack", 3 | "version": "5.4.1" 4 | } 5 | -------------------------------------------------------------------------------- /safe.go: -------------------------------------------------------------------------------- 1 | // +build appengine 2 | 3 | package msgpack 4 | 5 | // bytesToString converts byte slice to string. 6 | func bytesToString(b []byte) string { 7 | return string(b) 8 | } 9 | 10 | // stringToBytes converts string to byte slice. 11 | func stringToBytes(s string) []byte { 12 | return []byte(s) 13 | } 14 | -------------------------------------------------------------------------------- /time.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "reflect" 7 | "time" 8 | 9 | "github.com/vmihailenco/msgpack/v5/msgpcode" 10 | ) 11 | 12 | var timeExtID int8 = -1 13 | 14 | func init() { 15 | RegisterExtEncoder(timeExtID, time.Time{}, timeEncoder) 16 | RegisterExtDecoder(timeExtID, time.Time{}, timeDecoder) 17 | } 18 | 19 | func timeEncoder(e *Encoder, v reflect.Value) ([]byte, error) { 20 | return e.encodeTime(v.Interface().(time.Time)), nil 21 | } 22 | 23 | func timeDecoder(d *Decoder, v reflect.Value, extLen int) error { 24 | tm, err := d.decodeTime(extLen) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | if tm.IsZero() { 30 | // Zero time does not have timezone information. 31 | tm = tm.UTC() 32 | } 33 | 34 | ptr := v.Addr().Interface().(*time.Time) 35 | *ptr = tm 36 | 37 | return nil 38 | } 39 | 40 | func (e *Encoder) EncodeTime(tm time.Time) error { 41 | b := e.encodeTime(tm) 42 | if err := e.encodeExtLen(len(b)); err != nil { 43 | return err 44 | } 45 | if err := e.w.WriteByte(byte(timeExtID)); err != nil { 46 | return err 47 | } 48 | return e.write(b) 49 | } 50 | 51 | func (e *Encoder) encodeTime(tm time.Time) []byte { 52 | if e.timeBuf == nil { 53 | e.timeBuf = make([]byte, 12) 54 | } 55 | 56 | secs := uint64(tm.Unix()) 57 | if secs>>34 == 0 { 58 | data := uint64(tm.Nanosecond())<<34 | secs 59 | 60 | if data&0xffffffff00000000 == 0 { 61 | b := e.timeBuf[:4] 62 | binary.BigEndian.PutUint32(b, uint32(data)) 63 | return b 64 | } 65 | 66 | b := e.timeBuf[:8] 67 | binary.BigEndian.PutUint64(b, data) 68 | return b 69 | } 70 | 71 | b := e.timeBuf[:12] 72 | binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond())) 73 | binary.BigEndian.PutUint64(b[4:], secs) 74 | return b 75 | } 76 | 77 | func (d *Decoder) DecodeTime() (time.Time, error) { 78 | c, err := d.readCode() 79 | if err != nil { 80 | return time.Time{}, err 81 | } 82 | 83 | // Legacy format. 84 | if c == msgpcode.FixedArrayLow|2 { 85 | sec, err := d.DecodeInt64() 86 | if err != nil { 87 | return time.Time{}, err 88 | } 89 | 90 | nsec, err := d.DecodeInt64() 91 | if err != nil { 92 | return time.Time{}, err 93 | } 94 | 95 | return time.Unix(sec, nsec), nil 96 | } 97 | 98 | if msgpcode.IsString(c) { 99 | s, err := d.string(c) 100 | if err != nil { 101 | return time.Time{}, err 102 | } 103 | return time.Parse(time.RFC3339Nano, s) 104 | } 105 | 106 | extID, extLen, err := d.extHeader(c) 107 | if err != nil { 108 | return time.Time{}, err 109 | } 110 | 111 | // NodeJS seems to use extID 13. 112 | if extID != timeExtID && extID != 13 { 113 | return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID) 114 | } 115 | 116 | tm, err := d.decodeTime(extLen) 117 | if err != nil { 118 | return tm, err 119 | } 120 | 121 | if tm.IsZero() { 122 | // Zero time does not have timezone information. 123 | return tm.UTC(), nil 124 | } 125 | return tm, nil 126 | } 127 | 128 | func (d *Decoder) decodeTime(extLen int) (time.Time, error) { 129 | b, err := d.readN(extLen) 130 | if err != nil { 131 | return time.Time{}, err 132 | } 133 | 134 | switch len(b) { 135 | case 4: 136 | sec := binary.BigEndian.Uint32(b) 137 | return time.Unix(int64(sec), 0), nil 138 | case 8: 139 | sec := binary.BigEndian.Uint64(b) 140 | nsec := int64(sec >> 34) 141 | sec &= 0x00000003ffffffff 142 | return time.Unix(int64(sec), nsec), nil 143 | case 12: 144 | nsec := binary.BigEndian.Uint32(b) 145 | sec := binary.BigEndian.Uint64(b[4:]) 146 | return time.Unix(int64(sec), int64(nsec)), nil 147 | default: 148 | err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen) 149 | return time.Time{}, err 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | import ( 4 | "encoding" 5 | "fmt" 6 | "log" 7 | "reflect" 8 | "sync" 9 | 10 | "github.com/vmihailenco/tagparser/v2" 11 | ) 12 | 13 | var errorType = reflect.TypeOf((*error)(nil)).Elem() 14 | 15 | var ( 16 | customEncoderType = reflect.TypeOf((*CustomEncoder)(nil)).Elem() 17 | customDecoderType = reflect.TypeOf((*CustomDecoder)(nil)).Elem() 18 | ) 19 | 20 | var ( 21 | marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() 22 | unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() 23 | ) 24 | 25 | var ( 26 | binaryMarshalerType = reflect.TypeOf((*encoding.BinaryMarshaler)(nil)).Elem() 27 | binaryUnmarshalerType = reflect.TypeOf((*encoding.BinaryUnmarshaler)(nil)).Elem() 28 | ) 29 | 30 | var ( 31 | textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() 32 | textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() 33 | ) 34 | 35 | type ( 36 | encoderFunc func(*Encoder, reflect.Value) error 37 | decoderFunc func(*Decoder, reflect.Value) error 38 | ) 39 | 40 | var ( 41 | typeEncMap sync.Map 42 | typeDecMap sync.Map 43 | ) 44 | 45 | // Register registers encoder and decoder functions for a value. 46 | // This is low level API and in most cases you should prefer implementing 47 | // CustomEncoder/CustomDecoder or Marshaler/Unmarshaler interfaces. 48 | func Register(value interface{}, enc encoderFunc, dec decoderFunc) { 49 | typ := reflect.TypeOf(value) 50 | if enc != nil { 51 | typeEncMap.Store(typ, enc) 52 | } 53 | if dec != nil { 54 | typeDecMap.Store(typ, dec) 55 | } 56 | } 57 | 58 | //------------------------------------------------------------------------------ 59 | 60 | const defaultStructTag = "msgpack" 61 | 62 | var structs = newStructCache() 63 | 64 | type structCache struct { 65 | m sync.Map 66 | } 67 | 68 | type structCacheKey struct { 69 | typ reflect.Type 70 | tag string 71 | } 72 | 73 | func newStructCache() *structCache { 74 | return new(structCache) 75 | } 76 | 77 | func (m *structCache) Fields(typ reflect.Type, tag string) *fields { 78 | key := structCacheKey{tag: tag, typ: typ} 79 | 80 | if v, ok := m.m.Load(key); ok { 81 | return v.(*fields) 82 | } 83 | 84 | fs := getFields(typ, tag) 85 | m.m.Store(key, fs) 86 | 87 | return fs 88 | } 89 | 90 | //------------------------------------------------------------------------------ 91 | 92 | type field struct { 93 | encoder encoderFunc 94 | decoder decoderFunc 95 | name string 96 | index []int 97 | omitEmpty bool 98 | } 99 | 100 | func (f *field) Omit(e *Encoder, strct reflect.Value) bool { 101 | v, ok := fieldByIndex(strct, f.index) 102 | if !ok { 103 | return true 104 | } 105 | forced := e.flags&omitEmptyFlag != 0 106 | return (f.omitEmpty || forced) && e.isEmptyValue(v) 107 | } 108 | 109 | func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error { 110 | v, ok := fieldByIndex(strct, f.index) 111 | if !ok { 112 | return e.EncodeNil() 113 | } 114 | return f.encoder(e, v) 115 | } 116 | 117 | func (f *field) DecodeValue(d *Decoder, strct reflect.Value) error { 118 | v := fieldByIndexAlloc(strct, f.index) 119 | return f.decoder(d, v) 120 | } 121 | 122 | //------------------------------------------------------------------------------ 123 | 124 | type fields struct { 125 | Type reflect.Type 126 | Map map[string]*field 127 | List []*field 128 | AsArray bool 129 | 130 | hasOmitEmpty bool 131 | } 132 | 133 | func newFields(typ reflect.Type) *fields { 134 | return &fields{ 135 | Type: typ, 136 | Map: make(map[string]*field, typ.NumField()), 137 | List: make([]*field, 0, typ.NumField()), 138 | } 139 | } 140 | 141 | func (fs *fields) Add(field *field) { 142 | fs.warnIfFieldExists(field.name) 143 | fs.Map[field.name] = field 144 | fs.List = append(fs.List, field) 145 | if field.omitEmpty { 146 | fs.hasOmitEmpty = true 147 | } 148 | } 149 | 150 | func (fs *fields) warnIfFieldExists(name string) { 151 | if _, ok := fs.Map[name]; ok { 152 | log.Printf("msgpack: %s already has field=%s", fs.Type, name) 153 | } 154 | } 155 | 156 | func (fs *fields) OmitEmpty(e *Encoder, strct reflect.Value) []*field { 157 | forced := e.flags&omitEmptyFlag != 0 158 | if !fs.hasOmitEmpty && !forced { 159 | return fs.List 160 | } 161 | 162 | fields := make([]*field, 0, len(fs.List)) 163 | 164 | for _, f := range fs.List { 165 | if !f.Omit(e, strct) { 166 | fields = append(fields, f) 167 | } 168 | } 169 | 170 | return fields 171 | } 172 | 173 | func getFields(typ reflect.Type, fallbackTag string) *fields { 174 | fs := newFields(typ) 175 | 176 | var omitEmpty bool 177 | for i := 0; i < typ.NumField(); i++ { 178 | f := typ.Field(i) 179 | 180 | tagStr := f.Tag.Get(defaultStructTag) 181 | if tagStr == "" && fallbackTag != "" { 182 | tagStr = f.Tag.Get(fallbackTag) 183 | } 184 | 185 | tag := tagparser.Parse(tagStr) 186 | if tag.Name == "-" { 187 | continue 188 | } 189 | 190 | if f.Name == "_msgpack" { 191 | fs.AsArray = tag.HasOption("as_array") || tag.HasOption("asArray") 192 | if tag.HasOption("omitempty") { 193 | omitEmpty = true 194 | } 195 | } 196 | 197 | if f.PkgPath != "" && !f.Anonymous { 198 | continue 199 | } 200 | 201 | field := &field{ 202 | name: tag.Name, 203 | index: f.Index, 204 | omitEmpty: omitEmpty || tag.HasOption("omitempty"), 205 | } 206 | 207 | if tag.HasOption("intern") { 208 | switch f.Type.Kind() { 209 | case reflect.Interface: 210 | field.encoder = encodeInternedInterfaceValue 211 | field.decoder = decodeInternedInterfaceValue 212 | case reflect.String: 213 | field.encoder = encodeInternedStringValue 214 | field.decoder = decodeInternedStringValue 215 | default: 216 | err := fmt.Errorf("msgpack: intern strings are not supported on %s", f.Type) 217 | panic(err) 218 | } 219 | } else { 220 | field.encoder = getEncoder(f.Type) 221 | field.decoder = getDecoder(f.Type) 222 | } 223 | 224 | if field.name == "" { 225 | field.name = f.Name 226 | } 227 | 228 | if f.Anonymous && !tag.HasOption("noinline") { 229 | inline := tag.HasOption("inline") 230 | if inline { 231 | inlineFields(fs, f.Type, field, fallbackTag) 232 | } else { 233 | inline = shouldInline(fs, f.Type, field, fallbackTag) 234 | } 235 | 236 | if inline { 237 | if _, ok := fs.Map[field.name]; ok { 238 | log.Printf("msgpack: %s already has field=%s", fs.Type, field.name) 239 | } 240 | fs.Map[field.name] = field 241 | continue 242 | } 243 | } 244 | 245 | fs.Add(field) 246 | 247 | if alias, ok := tag.Options["alias"]; ok { 248 | fs.warnIfFieldExists(alias) 249 | fs.Map[alias] = field 250 | } 251 | } 252 | return fs 253 | } 254 | 255 | var ( 256 | encodeStructValuePtr uintptr 257 | decodeStructValuePtr uintptr 258 | ) 259 | 260 | //nolint:gochecknoinits 261 | func init() { 262 | encodeStructValuePtr = reflect.ValueOf(encodeStructValue).Pointer() 263 | decodeStructValuePtr = reflect.ValueOf(decodeStructValue).Pointer() 264 | } 265 | 266 | func inlineFields(fs *fields, typ reflect.Type, f *field, tag string) { 267 | inlinedFields := getFields(typ, tag).List 268 | for _, field := range inlinedFields { 269 | if _, ok := fs.Map[field.name]; ok { 270 | // Don't inline shadowed fields. 271 | continue 272 | } 273 | field.index = append(f.index, field.index...) 274 | fs.Add(field) 275 | } 276 | } 277 | 278 | func shouldInline(fs *fields, typ reflect.Type, f *field, tag string) bool { 279 | var encoder encoderFunc 280 | var decoder decoderFunc 281 | 282 | if typ.Kind() == reflect.Struct { 283 | encoder = f.encoder 284 | decoder = f.decoder 285 | } else { 286 | for typ.Kind() == reflect.Ptr { 287 | typ = typ.Elem() 288 | encoder = getEncoder(typ) 289 | decoder = getDecoder(typ) 290 | } 291 | if typ.Kind() != reflect.Struct { 292 | return false 293 | } 294 | } 295 | 296 | if reflect.ValueOf(encoder).Pointer() != encodeStructValuePtr { 297 | return false 298 | } 299 | if reflect.ValueOf(decoder).Pointer() != decodeStructValuePtr { 300 | return false 301 | } 302 | 303 | inlinedFields := getFields(typ, tag).List 304 | for _, field := range inlinedFields { 305 | if _, ok := fs.Map[field.name]; ok { 306 | // Don't auto inline if there are shadowed fields. 307 | return false 308 | } 309 | } 310 | 311 | for _, field := range inlinedFields { 312 | field.index = append(f.index, field.index...) 313 | fs.Add(field) 314 | } 315 | return true 316 | } 317 | 318 | type isZeroer interface { 319 | IsZero() bool 320 | } 321 | 322 | func (e *Encoder) isEmptyValue(v reflect.Value) bool { 323 | kind := v.Kind() 324 | 325 | for kind == reflect.Interface { 326 | if v.IsNil() { 327 | return true 328 | } 329 | v = v.Elem() 330 | kind = v.Kind() 331 | } 332 | 333 | if z, ok := v.Interface().(isZeroer); ok { 334 | return nilable(kind) && v.IsNil() || z.IsZero() 335 | } 336 | 337 | switch kind { 338 | case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 339 | return v.Len() == 0 340 | case reflect.Struct: 341 | structFields := structs.Fields(v.Type(), e.structTag) 342 | fields := structFields.OmitEmpty(e, v) 343 | return len(fields) == 0 344 | case reflect.Bool: 345 | return !v.Bool() 346 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 347 | return v.Int() == 0 348 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 349 | return v.Uint() == 0 350 | case reflect.Float32, reflect.Float64: 351 | return v.Float() == 0 352 | case reflect.Ptr: 353 | return v.IsNil() 354 | default: 355 | return false 356 | } 357 | } 358 | 359 | func fieldByIndex(v reflect.Value, index []int) (_ reflect.Value, ok bool) { 360 | if len(index) == 1 { 361 | return v.Field(index[0]), true 362 | } 363 | 364 | for i, idx := range index { 365 | if i > 0 { 366 | if v.Kind() == reflect.Ptr { 367 | if v.IsNil() { 368 | return v, false 369 | } 370 | v = v.Elem() 371 | } 372 | } 373 | v = v.Field(idx) 374 | } 375 | 376 | return v, true 377 | } 378 | 379 | func fieldByIndexAlloc(v reflect.Value, index []int) reflect.Value { 380 | if len(index) == 1 { 381 | return v.Field(index[0]) 382 | } 383 | 384 | for i, idx := range index { 385 | if i > 0 { 386 | var ok bool 387 | v, ok = indirectNil(v) 388 | if !ok { 389 | return v 390 | } 391 | } 392 | v = v.Field(idx) 393 | } 394 | 395 | return v 396 | } 397 | 398 | func indirectNil(v reflect.Value) (reflect.Value, bool) { 399 | if v.Kind() == reflect.Ptr { 400 | if v.IsNil() { 401 | if !v.CanSet() { 402 | return v, false 403 | } 404 | elemType := v.Type().Elem() 405 | if elemType.Kind() != reflect.Struct { 406 | return v, false 407 | } 408 | v.Set(cachedValue(elemType)) 409 | } 410 | v = v.Elem() 411 | } 412 | return v, true 413 | } 414 | -------------------------------------------------------------------------------- /types_test.go: -------------------------------------------------------------------------------- 1 | package msgpack_test 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | "math" 8 | "math/big" 9 | "net/url" 10 | "reflect" 11 | "strings" 12 | "testing" 13 | "time" 14 | 15 | "github.com/stretchr/testify/require" 16 | "github.com/vmihailenco/msgpack/v5" 17 | "github.com/vmihailenco/msgpack/v5/msgpcode" 18 | ) 19 | 20 | //------------------------------------------------------------------------------ 21 | 22 | type Object struct { 23 | n int64 24 | } 25 | 26 | func (o *Object) MarshalMsgpack() ([]byte, error) { 27 | return msgpack.Marshal(o.n) 28 | } 29 | 30 | func (o *Object) UnmarshalMsgpack(b []byte) error { 31 | return msgpack.Unmarshal(b, &o.n) 32 | } 33 | 34 | //------------------------------------------------------------------------------ 35 | 36 | type CustomTime time.Time 37 | 38 | func (t CustomTime) EncodeMsgpack(enc *msgpack.Encoder) error { 39 | return enc.Encode(time.Time(t)) 40 | } 41 | 42 | func (t *CustomTime) DecodeMsgpack(dec *msgpack.Decoder) error { 43 | var tm time.Time 44 | err := dec.Decode(&tm) 45 | if err != nil { 46 | return err 47 | } 48 | *t = CustomTime(tm) 49 | return nil 50 | } 51 | 52 | //------------------------------------------------------------------------------ 53 | 54 | type IntSet map[int]struct{} 55 | 56 | var ( 57 | _ msgpack.CustomEncoder = (*IntSet)(nil) 58 | _ msgpack.CustomDecoder = (*IntSet)(nil) 59 | ) 60 | 61 | func (set IntSet) EncodeMsgpack(enc *msgpack.Encoder) error { 62 | slice := make([]int, 0, len(set)) 63 | for n := range set { 64 | slice = append(slice, n) 65 | } 66 | return enc.Encode(slice) 67 | } 68 | 69 | func (setptr *IntSet) DecodeMsgpack(dec *msgpack.Decoder) error { 70 | n, err := dec.DecodeArrayLen() 71 | if err != nil { 72 | return err 73 | } 74 | 75 | set := make(IntSet, n) 76 | for i := 0; i < n; i++ { 77 | n, err := dec.DecodeInt() 78 | if err != nil { 79 | return err 80 | } 81 | set[n] = struct{}{} 82 | } 83 | *setptr = set 84 | 85 | return nil 86 | } 87 | 88 | //------------------------------------------------------------------------------ 89 | 90 | type CustomEncoder struct { 91 | str string 92 | ref *CustomEncoder 93 | num int 94 | } 95 | 96 | var ( 97 | _ msgpack.CustomEncoder = (*CustomEncoder)(nil) 98 | _ msgpack.CustomDecoder = (*CustomEncoder)(nil) 99 | ) 100 | 101 | func (s *CustomEncoder) EncodeMsgpack(enc *msgpack.Encoder) error { 102 | if s == nil { 103 | return enc.EncodeNil() 104 | } 105 | return enc.EncodeMulti(s.str, s.ref, s.num) 106 | } 107 | 108 | func (s *CustomEncoder) DecodeMsgpack(dec *msgpack.Decoder) error { 109 | return dec.DecodeMulti(&s.str, &s.ref, &s.num) 110 | } 111 | 112 | type CustomEncoderField struct { 113 | Field CustomEncoder 114 | } 115 | 116 | type CustomEncoderEmbeddedPtr struct { 117 | *CustomEncoder 118 | } 119 | 120 | func (s *CustomEncoderEmbeddedPtr) DecodeMsgpack(dec *msgpack.Decoder) error { 121 | if s.CustomEncoder == nil { 122 | s.CustomEncoder = new(CustomEncoder) 123 | } 124 | return s.CustomEncoder.DecodeMsgpack(dec) 125 | } 126 | 127 | //------------------------------------------------------------------------------ 128 | 129 | type JSONFallbackTest struct { 130 | Foo string `json:"foo,omitempty"` 131 | Bar string `json:",omitempty" msgpack:"bar"` 132 | } 133 | 134 | func TestUseJsonTag(t *testing.T) { 135 | var buf bytes.Buffer 136 | 137 | enc := msgpack.NewEncoder(&buf) 138 | enc.SetCustomStructTag("json") 139 | 140 | in := &JSONFallbackTest{Foo: "hello", Bar: "world"} 141 | err := enc.Encode(in) 142 | if err != nil { 143 | t.Fatal(err) 144 | } 145 | 146 | dec := msgpack.NewDecoder(&buf) 147 | dec.SetCustomStructTag("json") 148 | 149 | out := new(JSONFallbackTest) 150 | err = dec.Decode(out) 151 | if err != nil { 152 | t.Fatal(err) 153 | } 154 | 155 | if out.Foo != in.Foo { 156 | t.Fatalf("got %q, wanted %q", out.Foo, in.Foo) 157 | } 158 | if out.Bar != in.Bar { 159 | t.Fatalf("got %q, wanted %q", out.Foo, in.Foo) 160 | } 161 | } 162 | 163 | //------------------------------------------------------------------------------ 164 | 165 | type CustomFallbackTest struct { 166 | Foo string `custom:"foo,omitempty"` 167 | Bar string `custom:",omitempty" msgpack:"bar"` 168 | } 169 | 170 | func TestUseCustomTag(t *testing.T) { 171 | var buf bytes.Buffer 172 | 173 | enc := msgpack.NewEncoder(&buf) 174 | enc.SetCustomStructTag("custom") 175 | in := &CustomFallbackTest{Foo: "hello", Bar: "world"} 176 | err := enc.Encode(in) 177 | if err != nil { 178 | t.Fatal(err) 179 | } 180 | 181 | dec := msgpack.NewDecoder(&buf) 182 | dec.SetCustomStructTag("custom") 183 | out := new(CustomFallbackTest) 184 | err = dec.Decode(out) 185 | if err != nil { 186 | t.Fatal(err) 187 | } 188 | 189 | if out.Foo != in.Foo || out.Foo != "hello" { 190 | t.Fatalf("got %q, wanted %q", out.Foo, in.Foo) 191 | } 192 | if out.Bar != in.Bar || out.Bar != "world" { 193 | t.Fatalf("got %q, wanted %q", out.Foo, in.Foo) 194 | } 195 | } 196 | 197 | //------------------------------------------------------------------------------ 198 | 199 | type OmitTimeTest struct { 200 | Foo time.Time `msgpack:",omitempty"` 201 | Bar *time.Time `msgpack:",omitempty"` 202 | } 203 | 204 | type OmitEmptyTest struct { 205 | Foo string `msgpack:",omitempty"` 206 | Bar string `msgpack:",omitempty"` 207 | } 208 | 209 | type InlineTest struct { 210 | OmitEmptyTest 211 | } 212 | 213 | type InlinePtrTest struct { 214 | *OmitEmptyTest 215 | } 216 | 217 | type FooTest struct { 218 | Foo string 219 | } 220 | 221 | type FooDupTest FooTest 222 | 223 | type InlineDupTest struct { 224 | FooTest 225 | FooDupTest 226 | } 227 | 228 | type AsArrayTest struct { 229 | _msgpack struct{} `msgpack:",as_array"` 230 | 231 | OmitEmptyTest 232 | } 233 | 234 | type ExtTestField struct { 235 | ExtTest ExtTest 236 | } 237 | 238 | //------------------------------------------------------------------------------ 239 | 240 | type encoderTest struct { 241 | in interface{} 242 | wanted string 243 | } 244 | 245 | var encoderTests = []encoderTest{ 246 | {nil, "c0"}, 247 | 248 | {[]byte(nil), "c0"}, 249 | {[]byte{1, 2, 3}, "c403010203"}, 250 | {[3]byte{1, 2, 3}, "c403010203"}, 251 | 252 | {time.Unix(0, 0), "d6ff00000000"}, 253 | {time.Unix(1, 1), "d7ff0000000400000001"}, 254 | {time.Time{}, "c70cff00000000fffffff1886e0900"}, 255 | 256 | {IntSet{}, "90"}, 257 | {IntSet{8: struct{}{}}, "9108"}, 258 | 259 | {map[string]string(nil), "c0"}, 260 | { 261 | map[string]string{"a": "", "b": "", "c": "", "d": "", "e": ""}, 262 | "85a161a0a162a0a163a0a164a0a165a0", 263 | }, 264 | 265 | {(*Object)(nil), "c0"}, 266 | {&Object{}, "d30000000000000000"}, 267 | {&Object{42}, "d3000000000000002a"}, 268 | {[]*Object{nil, nil}, "92c0c0"}, 269 | 270 | {&CustomEncoder{}, "a0c000"}, 271 | { 272 | &CustomEncoder{"a", &CustomEncoder{"b", nil, 7}, 6}, 273 | "a161a162c00706", 274 | }, 275 | 276 | {OmitEmptyTest{}, "80"}, 277 | {&OmitEmptyTest{Foo: "hello"}, "81a3466f6fa568656c6c6f"}, 278 | 279 | {&InlineTest{OmitEmptyTest: OmitEmptyTest{Bar: "world"}}, "81a3426172a5776f726c64"}, 280 | {&InlinePtrTest{OmitEmptyTest: &OmitEmptyTest{Bar: "world"}}, "81a3426172a5776f726c64"}, 281 | 282 | {&AsArrayTest{}, "92a0a0"}, 283 | 284 | {&JSONFallbackTest{Foo: "hello"}, "82a3666f6fa568656c6c6fa3626172a0"}, 285 | {&JSONFallbackTest{Bar: "world"}, "81a3626172a5776f726c64"}, 286 | {&JSONFallbackTest{Foo: "hello", Bar: "world"}, "82a3666f6fa568656c6c6fa3626172a5776f726c64"}, 287 | 288 | {&NoIntern{A: "foo", B: "foo", C: "foo"}, "83a141a3666f6fa142a3666f6fa143a3666f6f"}, 289 | {&Intern{A: "foo", B: "foo", C: "foo"}, "83a141a3666f6fa142d48000a143d48000"}, 290 | } 291 | 292 | func TestEncoder(t *testing.T) { 293 | var buf bytes.Buffer 294 | enc := msgpack.NewEncoder(&buf) 295 | enc.SetCustomStructTag("json") 296 | enc.SetSortMapKeys(true) 297 | enc.UseCompactInts(true) 298 | 299 | for i, test := range encoderTests { 300 | buf.Reset() 301 | 302 | err := enc.Encode(test.in) 303 | require.Nil(t, err) 304 | 305 | s := hex.EncodeToString(buf.Bytes()) 306 | require.Equal(t, test.wanted, s, "#%d", i) 307 | } 308 | } 309 | 310 | type floatEncoderTest struct { 311 | in interface{} 312 | wanted string 313 | compact bool 314 | } 315 | 316 | var floatEncoderTests = []floatEncoderTest{ 317 | {float32(3.0), "ca40400000", false}, 318 | {float32(3.0), "03", true}, 319 | 320 | {float64(3.0), "cb4008000000000000", false}, 321 | {float64(3.0), "03", true}, 322 | 323 | {float64(-3.0), "cbc008000000000000", false}, 324 | {float64(-3.0), "fd", true}, 325 | 326 | {math.NaN(), "cb7ff8000000000001", false}, 327 | {math.NaN(), "cb7ff8000000000001", true}, 328 | {math.Inf(1), "cb7ff0000000000000", false}, 329 | {math.Inf(1), "cb7ff0000000000000", true}, 330 | } 331 | 332 | func TestFloatEncoding(t *testing.T) { 333 | var buf bytes.Buffer 334 | enc := msgpack.NewEncoder(&buf) 335 | enc.UseCompactInts(true) 336 | 337 | for _, test := range floatEncoderTests { 338 | buf.Reset() 339 | 340 | enc.UseCompactFloats(test.compact) 341 | 342 | err := enc.Encode(test.in) 343 | if err != nil { 344 | t.Fatal(err) 345 | } 346 | 347 | s := hex.EncodeToString(buf.Bytes()) 348 | if s != test.wanted { 349 | t.Fatalf("%s != %s (in=%#v)", s, test.wanted, test.in) 350 | } 351 | } 352 | } 353 | 354 | //------------------------------------------------------------------------------ 355 | 356 | type decoderTest struct { 357 | b []byte 358 | out interface{} 359 | err string 360 | } 361 | 362 | var decoderTests = []decoderTest{ 363 | {b: []byte{byte(msgpcode.Bin32), 0x0f, 0xff, 0xff, 0xff}, out: new([]byte), err: "EOF"}, 364 | {b: []byte{byte(msgpcode.Str32), 0x0f, 0xff, 0xff, 0xff}, out: new([]byte), err: "EOF"}, 365 | {b: []byte{byte(msgpcode.Array32), 0x0f, 0xff, 0xff, 0xff}, out: new([]int), err: "EOF"}, 366 | {b: []byte{byte(msgpcode.Map32), 0x0f, 0xff, 0xff, 0xff}, out: new(map[int]int), err: "EOF"}, 367 | } 368 | 369 | func TestDecoder(t *testing.T) { 370 | for i, test := range decoderTests { 371 | err := msgpack.Unmarshal(test.b, test.out) 372 | if err == nil { 373 | t.Fatalf("#%d err is nil, wanted %q", i, test.err) 374 | } 375 | if err.Error() != test.err { 376 | t.Fatalf("#%d err is %q, wanted %q", i, err.Error(), test.err) 377 | } 378 | } 379 | } 380 | 381 | //------------------------------------------------------------------------------ 382 | 383 | type unexported struct { 384 | Foo string 385 | } 386 | 387 | type Exported struct { 388 | Bar string 389 | } 390 | 391 | type EmbeddingTest struct { 392 | unexported 393 | Exported 394 | } 395 | 396 | type EmbeddingPtrTest struct { 397 | *Exported 398 | } 399 | 400 | type EmbeddedTime struct { 401 | time.Time 402 | } 403 | 404 | type ( 405 | interfaceAlias interface{} 406 | byteAlias byte 407 | uint8Alias uint8 408 | stringAlias string 409 | sliceByte []byte 410 | sliceString []string 411 | mapStringString map[string]string 412 | mapStringInterface map[string]interface{} 413 | ) 414 | 415 | type StructTest struct { 416 | F1 sliceString 417 | F2 []string 418 | } 419 | 420 | type typeTest struct { 421 | *testing.T 422 | 423 | in interface{} 424 | out interface{} 425 | encErr string 426 | decErr string 427 | wantnil bool 428 | wantzero bool 429 | wanted interface{} 430 | } 431 | 432 | func (t typeTest) String() string { 433 | return fmt.Sprintf("in=%#v, out=%#v", t.in, t.out) 434 | } 435 | 436 | func (t *typeTest) requireErr(err error, s string) { 437 | if err == nil { 438 | t.Fatalf("got %v error, wanted %q", err, s) 439 | } 440 | if err.Error() != s { 441 | t.Fatalf("got %q error, wanted %q", err, s) 442 | } 443 | } 444 | 445 | var ( 446 | intSlice = make([]int, 0, 3) 447 | repoURL, _ = url.Parse("https://github.com/vmihailenco/msgpack") 448 | typeTests = []typeTest{ 449 | {in: make(chan bool), encErr: "msgpack: Encode(unsupported chan bool)"}, 450 | 451 | {in: nil, out: nil, decErr: "msgpack: Decode(nil)"}, 452 | {in: nil, out: 0, decErr: "msgpack: Decode(non-pointer int)"}, 453 | {in: nil, out: (*int)(nil), decErr: "msgpack: Decode(non-settable *int)"}, 454 | {in: nil, out: new(chan bool), decErr: "msgpack: Decode(unsupported chan bool)"}, 455 | 456 | {in: true, out: new(bool)}, 457 | {in: false, out: new(bool)}, 458 | 459 | {in: nil, out: new(int), wanted: int(0)}, 460 | {in: nil, out: new(*int), wantnil: true}, 461 | 462 | {in: float32(3.14), out: new(float32)}, 463 | {in: int8(-1), out: new(float32), wanted: float32(-1)}, 464 | {in: int32(1), out: new(float32), wanted: float32(1)}, 465 | {in: int32(999999999), out: new(float32), wanted: float32(999999999)}, 466 | {in: int64(math.MaxInt64), out: new(float32), wanted: float32(math.MaxInt64)}, 467 | 468 | {in: float64(3.14), out: new(float64)}, 469 | {in: int8(-1), out: new(float64), wanted: float64(-1)}, 470 | {in: int64(1), out: new(float64), wanted: float64(1)}, 471 | {in: int64(999999999), out: new(float64), wanted: float64(999999999)}, 472 | {in: int64(math.MaxInt64), out: new(float64), wanted: float64(math.MaxInt64)}, 473 | 474 | {in: nil, out: new(*string), wantnil: true}, 475 | {in: nil, out: new(string), wanted: ""}, 476 | {in: "", out: new(string)}, 477 | {in: "foo", out: new(string)}, 478 | 479 | {in: nil, out: new([]byte), wantnil: true}, 480 | {in: []byte(nil), out: new([]byte), wantnil: true}, 481 | {in: []byte(nil), out: &[]byte{}, wantnil: true}, 482 | {in: []byte{1, 2, 3}, out: new([]byte)}, 483 | {in: []byte{1, 2, 3}, out: new([]byte)}, 484 | {in: sliceByte{1, 2, 3}, out: new(sliceByte)}, 485 | {in: []byteAlias{1, 2, 3}, out: new([]byteAlias)}, 486 | {in: []uint8Alias{1, 2, 3}, out: new([]uint8Alias)}, 487 | 488 | {in: nil, out: new([3]byte), wanted: [3]byte{}}, 489 | {in: [3]byte{1, 2, 3}, out: new([3]byte)}, 490 | {in: [3]byte{1, 2, 3}, out: new([2]byte), decErr: "[2]uint8 len is 2, but msgpack has 3 elements"}, 491 | 492 | {in: nil, out: new([]interface{}), wantnil: true}, 493 | {in: nil, out: new([]interface{}), wantnil: true}, 494 | {in: []interface{}{int8(1), "hello"}, out: new([]interface{})}, 495 | 496 | {in: nil, out: new([]int), wantnil: true}, 497 | {in: nil, out: &[]int{1, 2}, wantnil: true}, 498 | {in: []int(nil), out: new([]int), wantnil: true}, 499 | {in: make([]int, 0), out: new([]int)}, 500 | {in: []int{}, out: new([]int)}, 501 | {in: []int{1, 2, 3}, out: new([]int)}, 502 | {in: []int{1, 2, 3}, out: &intSlice}, 503 | {in: [3]int{1, 2, 3}, out: new([3]int)}, 504 | {in: [3]int{1, 2, 3}, out: new([2]int), decErr: "[2]int len is 2, but msgpack has 3 elements"}, 505 | 506 | {in: []string(nil), out: new([]string), wantnil: true}, 507 | {in: []string{}, out: new([]string)}, 508 | {in: []string{"a", "b"}, out: new([]string)}, 509 | {in: [2]string{"a", "b"}, out: new([2]string)}, 510 | {in: sliceString{"foo", "bar"}, out: new(sliceString)}, 511 | {in: []stringAlias{"hello"}, out: new([]stringAlias)}, 512 | 513 | {in: nil, out: new(map[string]string), wantnil: true}, 514 | {in: nil, out: new(map[int]int), wantnil: true}, 515 | {in: nil, out: &map[string]string{"foo": "bar"}, wantnil: true}, 516 | {in: nil, out: &map[int]int{1: 2}, wantnil: true}, 517 | {in: map[string]string(nil), out: new(map[string]string)}, 518 | {in: map[string]interface{}{"foo": nil}, out: new(map[string]interface{})}, 519 | {in: mapStringString{"foo": "bar"}, out: new(mapStringString)}, 520 | {in: map[stringAlias]stringAlias{"foo": "bar"}, out: new(map[stringAlias]stringAlias)}, 521 | {in: mapStringInterface{"foo": "bar"}, out: new(mapStringInterface)}, 522 | {in: map[stringAlias]interfaceAlias{"foo": "bar"}, out: new(map[stringAlias]interfaceAlias)}, 523 | {in: map[int]string{1: "string"}, out: new(map[int]string)}, 524 | 525 | {in: (*Object)(nil), out: new(*Object)}, 526 | {in: &Object{42}, out: new(Object)}, 527 | {in: []*Object{new(Object), new(Object)}, out: new([]*Object)}, 528 | 529 | {in: IntSet{}, out: new(IntSet)}, 530 | {in: IntSet{42: struct{}{}}, out: new(IntSet)}, 531 | {in: IntSet{42: struct{}{}}, out: new(*IntSet)}, 532 | 533 | {in: StructTest{sliceString{"foo", "bar"}, []string{"hello"}}, out: new(StructTest)}, 534 | {in: StructTest{sliceString{"foo", "bar"}, []string{"hello"}}, out: new(*StructTest)}, 535 | 536 | {in: EmbeddingTest{}, out: new(EmbeddingTest)}, 537 | { 538 | in: EmbeddingTest{}, 539 | out: new(EmbeddingPtrTest), 540 | wanted: EmbeddingPtrTest{Exported: new(Exported)}, 541 | }, 542 | { 543 | in: EmbeddingPtrTest{}, 544 | out: new(EmbeddingPtrTest), 545 | wanted: EmbeddingPtrTest{Exported: new(Exported)}, 546 | }, 547 | {in: EmbeddingTest{}, out: new(*EmbeddingTest)}, 548 | { 549 | in: EmbeddingTest{ 550 | unexported: unexported{Foo: "hello"}, 551 | Exported: Exported{Bar: "world"}, 552 | }, 553 | out: new(EmbeddingTest), 554 | }, 555 | 556 | {in: time.Unix(0, 0), out: new(time.Time)}, 557 | {in: new(time.Time), out: new(time.Time)}, 558 | {in: time.Unix(0, 1), out: new(time.Time)}, 559 | {in: time.Unix(1, 0), out: new(time.Time)}, 560 | {in: time.Unix(1, 1), out: new(time.Time)}, 561 | { 562 | in: time.Unix(0, 0).Format(time.RFC3339), 563 | out: new(time.Time), 564 | wanted: mustParseTime(time.RFC3339, time.Unix(0, 0).Format(time.RFC3339)), 565 | }, 566 | {in: EmbeddedTime{Time: time.Unix(1, 1)}, out: new(EmbeddedTime)}, 567 | {in: EmbeddedTime{Time: time.Unix(1, 1)}, out: new(*EmbeddedTime)}, 568 | {in: CustomTime(time.Unix(0, 0)), out: new(CustomTime)}, 569 | 570 | {in: nil, out: new(*CustomEncoder), wantnil: true}, 571 | {in: nil, out: &CustomEncoder{str: "a"}, wantzero: true}, 572 | { 573 | in: &CustomEncoder{"a", &CustomEncoder{"b", nil, 1}, 2}, 574 | out: new(CustomEncoder), 575 | }, 576 | { 577 | in: &CustomEncoderField{Field: CustomEncoder{"a", nil, 1}}, 578 | out: new(CustomEncoderField), 579 | }, 580 | { 581 | in: &CustomEncoderEmbeddedPtr{&CustomEncoder{"a", nil, 1}}, 582 | out: new(CustomEncoderEmbeddedPtr), 583 | }, 584 | 585 | {in: repoURL, out: new(url.URL)}, 586 | {in: repoURL, out: new(*url.URL)}, 587 | 588 | {in: OmitEmptyTest{}, out: new(OmitEmptyTest)}, 589 | {in: OmitTimeTest{}, out: new(OmitTimeTest)}, 590 | 591 | {in: nil, out: new(*AsArrayTest), wantnil: true}, 592 | {in: nil, out: new(AsArrayTest), wantzero: true}, 593 | {in: AsArrayTest{OmitEmptyTest: OmitEmptyTest{"foo", "bar"}}, out: new(AsArrayTest)}, 594 | { 595 | in: AsArrayTest{OmitEmptyTest: OmitEmptyTest{"foo", "bar"}}, 596 | out: new(unexported), 597 | decErr: "msgpack: number of fields in array-encoded struct has changed", 598 | }, 599 | 600 | {in: (*EventTime)(nil), out: new(*EventTime)}, 601 | {in: &EventTime{time.Unix(0, 0)}, out: new(*EventTime)}, 602 | 603 | {in: (*ExtTest)(nil), out: new(*ExtTest)}, 604 | {in: &ExtTest{"world"}, out: new(*ExtTest), wanted: ExtTest{"hello world"}}, 605 | { 606 | in: &ExtTestField{ExtTest{"world"}}, 607 | out: new(*ExtTestField), 608 | wanted: ExtTestField{ExtTest{"hello world"}}, 609 | }, 610 | 611 | { 612 | in: &InlineTest{OmitEmptyTest: OmitEmptyTest{Bar: "world"}}, 613 | out: new(InlineTest), 614 | }, 615 | { 616 | in: &InlinePtrTest{OmitEmptyTest: &OmitEmptyTest{Bar: "world"}}, 617 | out: new(InlinePtrTest), 618 | }, 619 | { 620 | in: InlineDupTest{FooTest{"foo"}, FooDupTest{"foo"}}, 621 | out: new(InlineDupTest), 622 | }, 623 | 624 | {in: big.NewInt(123), out: new(big.Int)}, 625 | } 626 | ) 627 | 628 | func indirect(viface interface{}) interface{} { 629 | v := reflect.ValueOf(viface) 630 | for v.Kind() == reflect.Ptr { 631 | v = v.Elem() 632 | } 633 | if v.IsValid() { 634 | return v.Interface() 635 | } 636 | return nil 637 | } 638 | 639 | func TestTypes(t *testing.T) { 640 | msgpack.RegisterExt(1, (*EventTime)(nil)) 641 | 642 | for _, test := range typeTests { 643 | test.T = t 644 | 645 | var buf bytes.Buffer 646 | 647 | enc := msgpack.NewEncoder(&buf) 648 | err := enc.Encode(test.in) 649 | if test.encErr != "" { 650 | test.requireErr(err, test.encErr) 651 | continue 652 | } 653 | if err != nil { 654 | t.Fatalf("Encode failed: %s (in=%#v)", err, test.in) 655 | } 656 | 657 | dec := msgpack.NewDecoder(&buf) 658 | err = dec.Decode(test.out) 659 | if test.decErr != "" { 660 | test.requireErr(err, test.decErr) 661 | continue 662 | } 663 | if err != nil { 664 | t.Fatalf("Decode failed: %s (%s)", err, test) 665 | } 666 | 667 | if buf.Len() > 0 { 668 | t.Fatalf("unread data in the buffer: %q (%s)", buf.Bytes(), test) 669 | } 670 | 671 | if test.wantnil { 672 | v := reflect.Indirect(reflect.ValueOf(test.out)) 673 | if !v.IsNil() { 674 | t.Fatalf("got %#v, wanted nil (%s)", test.out, test) 675 | } 676 | continue 677 | } 678 | 679 | out := indirect(test.out) 680 | var wanted interface{} 681 | if test.wantzero { 682 | typ := reflect.TypeOf(out) 683 | wanted = reflect.Zero(typ).Interface() 684 | } else { 685 | wanted = test.wanted 686 | } 687 | if wanted == nil { 688 | wanted = indirect(test.in) 689 | } 690 | require.Equal(t, wanted, out) 691 | } 692 | 693 | for _, test := range typeTests { 694 | if test.encErr != "" || test.decErr != "" { 695 | continue 696 | } 697 | 698 | b, err := msgpack.Marshal(test.in) 699 | if err != nil { 700 | t.Fatal(err) 701 | } 702 | 703 | var dst interface{} 704 | dec := msgpack.NewDecoder(bytes.NewReader(b)) 705 | dec.SetMapDecoder(func(dec *msgpack.Decoder) (interface{}, error) { 706 | return dec.DecodeUntypedMap() 707 | }) 708 | 709 | err = dec.Decode(&dst) 710 | if err != nil { 711 | t.Fatalf("Unmarshal into interface{} failed: %s (%s)", err, test) 712 | } 713 | 714 | dec = msgpack.NewDecoder(bytes.NewReader(b)) 715 | dec.SetMapDecoder(func(dec *msgpack.Decoder) (interface{}, error) { 716 | return dec.DecodeUntypedMap() 717 | }) 718 | 719 | _, err = dec.DecodeInterface() 720 | if err != nil { 721 | t.Fatalf("DecodeInterface failed: %s (%s)", err, test) 722 | } 723 | } 724 | } 725 | 726 | func TestStringsBin(t *testing.T) { 727 | tests := []struct { 728 | in string 729 | wanted string 730 | }{ 731 | {"", "a0"}, 732 | {"a", "a161"}, 733 | {"hello", "a568656c6c6f"}, 734 | { 735 | strings.Repeat("x", 31), 736 | "bf" + strings.Repeat("78", 31), 737 | }, 738 | { 739 | strings.Repeat("x", 32), 740 | "d920" + strings.Repeat("78", 32), 741 | }, 742 | { 743 | strings.Repeat("x", 255), 744 | "d9ff" + strings.Repeat("78", 255), 745 | }, 746 | { 747 | strings.Repeat("x", 256), 748 | "da0100" + strings.Repeat("78", 256), 749 | }, 750 | { 751 | strings.Repeat("x", 65535), 752 | "daffff" + strings.Repeat("78", 65535), 753 | }, 754 | { 755 | strings.Repeat("x", 65536), 756 | "db00010000" + strings.Repeat("78", 65536), 757 | }, 758 | } 759 | 760 | for _, test := range tests { 761 | b, err := msgpack.Marshal(test.in) 762 | require.Nil(t, err) 763 | s := hex.EncodeToString(b) 764 | require.Equal(t, s, test.wanted) 765 | 766 | var out string 767 | err = msgpack.Unmarshal(b, &out) 768 | require.Nil(t, err) 769 | require.Equal(t, out, test.in) 770 | 771 | var msg msgpack.RawMessage 772 | err = msgpack.Unmarshal(b, &msg) 773 | require.Nil(t, err) 774 | require.Equal(t, []byte(msg), b) 775 | 776 | dec := msgpack.NewDecoder(bytes.NewReader(b)) 777 | v, err := dec.DecodeInterface() 778 | require.Nil(t, err) 779 | require.Equal(t, v.(string), test.in) 780 | 781 | var dst interface{} = "" 782 | err = msgpack.Unmarshal(b, &dst) 783 | require.EqualError(t, err, "msgpack: Decode(non-pointer string)") 784 | } 785 | } 786 | 787 | func TestBin(t *testing.T) { 788 | tests := []struct { 789 | in []byte 790 | wanted string 791 | }{ 792 | {[]byte{}, "c400"}, 793 | {[]byte{0}, "c40100"}, 794 | { 795 | bytes.Repeat([]byte{'x'}, 31), 796 | "c41f" + strings.Repeat("78", 31), 797 | }, 798 | { 799 | bytes.Repeat([]byte{'x'}, 32), 800 | "c420" + strings.Repeat("78", 32), 801 | }, 802 | { 803 | bytes.Repeat([]byte{'x'}, 255), 804 | "c4ff" + strings.Repeat("78", 255), 805 | }, 806 | { 807 | bytes.Repeat([]byte{'x'}, 256), 808 | "c50100" + strings.Repeat("78", 256), 809 | }, 810 | { 811 | bytes.Repeat([]byte{'x'}, 65535), 812 | "c5ffff" + strings.Repeat("78", 65535), 813 | }, 814 | { 815 | bytes.Repeat([]byte{'x'}, 65536), 816 | "c600010000" + strings.Repeat("78", 65536), 817 | }, 818 | } 819 | 820 | for _, test := range tests { 821 | b, err := msgpack.Marshal(test.in) 822 | if err != nil { 823 | t.Fatal(err) 824 | } 825 | s := hex.EncodeToString(b) 826 | if s != test.wanted { 827 | t.Fatalf("%.32s != %.32s", s, test.wanted) 828 | } 829 | 830 | var out []byte 831 | err = msgpack.Unmarshal(b, &out) 832 | if err != nil { 833 | t.Fatal(err) 834 | } 835 | if !bytes.Equal(out, test.in) { 836 | t.Fatalf("%x != %x", out, test.in) 837 | } 838 | 839 | dec := msgpack.NewDecoder(bytes.NewReader(b)) 840 | v, err := dec.DecodeInterface() 841 | if err != nil { 842 | t.Fatal(err) 843 | } 844 | if !bytes.Equal(v.([]byte), test.in) { 845 | t.Fatalf("%x != %x", v, test.in) 846 | } 847 | 848 | var dst interface{} = make([]byte, 0) 849 | err = msgpack.Unmarshal(b, &dst) 850 | if err.Error() != "msgpack: Decode(non-pointer []uint8)" { 851 | t.Fatal(err) 852 | } 853 | } 854 | } 855 | 856 | func TestUint64(t *testing.T) { 857 | tests := []struct { 858 | in uint64 859 | wanted string 860 | }{ 861 | {0, "00"}, 862 | {1, "01"}, 863 | {math.MaxInt8 - 1, "7e"}, 864 | {math.MaxInt8, "7f"}, 865 | {math.MaxInt8 + 1, "cc80"}, 866 | {math.MaxUint8 - 1, "ccfe"}, 867 | {math.MaxUint8, "ccff"}, 868 | {math.MaxUint8 + 1, "cd0100"}, 869 | {math.MaxUint16 - 1, "cdfffe"}, 870 | {math.MaxUint16, "cdffff"}, 871 | {math.MaxUint16 + 1, "ce00010000"}, 872 | {math.MaxUint32 - 1, "cefffffffe"}, 873 | {math.MaxUint32, "ceffffffff"}, 874 | {math.MaxUint32 + 1, "cf0000000100000000"}, 875 | {math.MaxInt64 - 1, "cf7ffffffffffffffe"}, 876 | {math.MaxInt64, "cf7fffffffffffffff"}, 877 | } 878 | 879 | var buf bytes.Buffer 880 | enc := msgpack.NewEncoder(&buf) 881 | enc.UseCompactInts(true) 882 | 883 | for _, test := range tests { 884 | err := enc.Encode(test.in) 885 | if err != nil { 886 | t.Fatal(err) 887 | } 888 | s := hex.EncodeToString(buf.Bytes()) 889 | if s != test.wanted { 890 | t.Fatalf("%.32s != %.32s", s, test.wanted) 891 | } 892 | 893 | var out uint64 894 | err = msgpack.Unmarshal(buf.Bytes(), &out) 895 | if err != nil { 896 | t.Fatal(err) 897 | } 898 | if out != test.in { 899 | t.Fatalf("%d != %d", out, test.in) 900 | } 901 | 902 | var out2 int64 903 | err = msgpack.Unmarshal(buf.Bytes(), &out2) 904 | if err != nil { 905 | t.Fatal(err) 906 | } 907 | if out2 != int64(test.in) { 908 | t.Fatalf("%d != %d", out2, int64(test.in)) 909 | } 910 | 911 | var out3 interface{} = uint64(0) 912 | err = msgpack.Unmarshal(buf.Bytes(), &out3) 913 | if err.Error() != "msgpack: Decode(non-pointer uint64)" { 914 | t.Fatal(err) 915 | } 916 | 917 | dec := msgpack.NewDecoder(&buf) 918 | _, err = dec.DecodeInterface() 919 | if err != nil { 920 | t.Fatal(err) 921 | } 922 | 923 | if buf.Len() != 0 { 924 | panic("buffer is not empty") 925 | } 926 | } 927 | } 928 | 929 | func TestInt64(t *testing.T) { 930 | tests := []struct { 931 | in int64 932 | wanted string 933 | }{ 934 | {math.MinInt64, "d38000000000000000"}, 935 | {math.MinInt32 - 1, "d3ffffffff7fffffff"}, 936 | {math.MinInt32, "d280000000"}, 937 | {math.MinInt32 + 1, "d280000001"}, 938 | {math.MinInt16 - 1, "d2ffff7fff"}, 939 | {math.MinInt16, "d18000"}, 940 | {math.MinInt16 + 1, "d18001"}, 941 | {math.MinInt8 - 1, "d1ff7f"}, 942 | {math.MinInt8, "d080"}, 943 | {math.MinInt8 + 1, "d081"}, 944 | {-33, "d0df"}, 945 | {-32, "e0"}, 946 | {-31, "e1"}, 947 | {-1, "ff"}, 948 | {0, "00"}, 949 | {1, "01"}, 950 | {math.MaxInt8 - 1, "7e"}, 951 | {math.MaxInt8, "7f"}, 952 | {math.MaxInt8 + 1, "cc80"}, 953 | {math.MaxUint8 - 1, "ccfe"}, 954 | {math.MaxUint8, "ccff"}, 955 | {math.MaxUint8 + 1, "cd0100"}, 956 | {math.MaxUint16 - 1, "cdfffe"}, 957 | {math.MaxUint16, "cdffff"}, 958 | {math.MaxUint16 + 1, "ce00010000"}, 959 | {math.MaxUint32 - 1, "cefffffffe"}, 960 | {math.MaxUint32, "ceffffffff"}, 961 | {math.MaxUint32 + 1, "cf0000000100000000"}, 962 | {math.MaxInt64 - 1, "cf7ffffffffffffffe"}, 963 | {math.MaxInt64, "cf7fffffffffffffff"}, 964 | } 965 | 966 | var buf bytes.Buffer 967 | enc := msgpack.NewEncoder(&buf) 968 | enc.UseCompactInts(true) 969 | 970 | for _, test := range tests { 971 | err := enc.Encode(test.in) 972 | if err != nil { 973 | t.Fatal(err) 974 | } 975 | s := hex.EncodeToString(buf.Bytes()) 976 | if s != test.wanted { 977 | t.Fatalf("%.32s != %.32s", s, test.wanted) 978 | } 979 | 980 | var out int64 981 | err = msgpack.Unmarshal(buf.Bytes(), &out) 982 | if err != nil { 983 | t.Fatal(err) 984 | } 985 | if out != test.in { 986 | t.Fatalf("%d != %d", out, test.in) 987 | } 988 | 989 | var out2 uint64 990 | err = msgpack.Unmarshal(buf.Bytes(), &out2) 991 | if err != nil { 992 | t.Fatal(err) 993 | } 994 | if out2 != uint64(test.in) { 995 | t.Fatalf("%d != %d", out2, uint64(test.in)) 996 | } 997 | 998 | var out3 interface{} = int64(0) 999 | err = msgpack.Unmarshal(buf.Bytes(), &out3) 1000 | if err.Error() != "msgpack: Decode(non-pointer int64)" { 1001 | t.Fatal(err) 1002 | } 1003 | 1004 | dec := msgpack.NewDecoder(&buf) 1005 | _, err = dec.DecodeInterface() 1006 | if err != nil { 1007 | t.Fatal(err) 1008 | } 1009 | 1010 | if buf.Len() != 0 { 1011 | panic("buffer is not empty") 1012 | } 1013 | } 1014 | } 1015 | 1016 | func TestFloat32(t *testing.T) { 1017 | tests := []struct { 1018 | in float32 1019 | wanted string 1020 | }{ 1021 | {0.1, "ca3dcccccd"}, 1022 | {0.2, "ca3e4ccccd"}, 1023 | {-0.1, "cabdcccccd"}, 1024 | {-0.2, "cabe4ccccd"}, 1025 | {float32(math.Inf(1)), "ca7f800000"}, 1026 | {float32(math.Inf(-1)), "caff800000"}, 1027 | {math.MaxFloat32, "ca7f7fffff"}, 1028 | {math.SmallestNonzeroFloat32, "ca00000001"}, 1029 | } 1030 | for _, test := range tests { 1031 | b, err := msgpack.Marshal(test.in) 1032 | if err != nil { 1033 | t.Fatal(err) 1034 | } 1035 | s := hex.EncodeToString(b) 1036 | if s != test.wanted { 1037 | t.Fatalf("%.32s != %.32s", s, test.wanted) 1038 | } 1039 | 1040 | var out float32 1041 | err = msgpack.Unmarshal(b, &out) 1042 | if err != nil { 1043 | t.Fatal(err) 1044 | } 1045 | if out != test.in { 1046 | t.Fatalf("%f != %f", out, test.in) 1047 | } 1048 | 1049 | var out2 float64 1050 | err = msgpack.Unmarshal(b, &out2) 1051 | if err != nil { 1052 | t.Fatal(err) 1053 | } 1054 | if out2 != float64(test.in) { 1055 | t.Fatalf("%f != %f", out2, float64(test.in)) 1056 | } 1057 | 1058 | dec := msgpack.NewDecoder(bytes.NewReader(b)) 1059 | v, err := dec.DecodeInterface() 1060 | if err != nil { 1061 | t.Fatal(err) 1062 | } 1063 | if v.(float32) != test.in { 1064 | t.Fatalf("%f != %f", v, test.in) 1065 | } 1066 | 1067 | var dst interface{} = float32(0) 1068 | err = msgpack.Unmarshal(b, &dst) 1069 | if err.Error() != "msgpack: Decode(non-pointer float32)" { 1070 | t.Fatal(err) 1071 | } 1072 | } 1073 | 1074 | in := float32(math.NaN()) 1075 | b, err := msgpack.Marshal(in) 1076 | if err != nil { 1077 | t.Fatal(err) 1078 | } 1079 | 1080 | var out float32 1081 | err = msgpack.Unmarshal(b, &out) 1082 | if err != nil { 1083 | t.Fatal(err) 1084 | } 1085 | if !math.IsNaN(float64(out)) { 1086 | t.Fatal("not NaN") 1087 | } 1088 | } 1089 | 1090 | func TestFloat64(t *testing.T) { 1091 | table := []struct { 1092 | in float64 1093 | wanted string 1094 | }{ 1095 | {0.1, "cb3fb999999999999a"}, 1096 | {0.2, "cb3fc999999999999a"}, 1097 | {-0.1, "cbbfb999999999999a"}, 1098 | {-0.2, "cbbfc999999999999a"}, 1099 | {math.Inf(1), "cb7ff0000000000000"}, 1100 | {math.Inf(-1), "cbfff0000000000000"}, 1101 | {math.MaxFloat64, "cb7fefffffffffffff"}, 1102 | {math.SmallestNonzeroFloat64, "cb0000000000000001"}, 1103 | } 1104 | for _, test := range table { 1105 | b, err := msgpack.Marshal(test.in) 1106 | if err != nil { 1107 | t.Fatal(err) 1108 | } 1109 | s := hex.EncodeToString(b) 1110 | if s != test.wanted { 1111 | t.Fatalf("%.32s != %.32s", s, test.wanted) 1112 | } 1113 | 1114 | var out float64 1115 | err = msgpack.Unmarshal(b, &out) 1116 | if err != nil { 1117 | t.Fatal(err) 1118 | } 1119 | if out != test.in { 1120 | t.Fatalf("%f != %f", out, test.in) 1121 | } 1122 | 1123 | dec := msgpack.NewDecoder(bytes.NewReader(b)) 1124 | v, err := dec.DecodeInterface() 1125 | if err != nil { 1126 | t.Fatal(err) 1127 | } 1128 | if v.(float64) != test.in { 1129 | t.Fatalf("%f != %f", v, test.in) 1130 | } 1131 | 1132 | var dst interface{} = float64(0) 1133 | err = msgpack.Unmarshal(b, &dst) 1134 | if err.Error() != "msgpack: Decode(non-pointer float64)" { 1135 | t.Fatal(err) 1136 | } 1137 | } 1138 | } 1139 | 1140 | func mustParseTime(format, s string) time.Time { 1141 | tm, err := time.Parse(format, s) 1142 | if err != nil { 1143 | panic(err) 1144 | } 1145 | return tm 1146 | } 1147 | -------------------------------------------------------------------------------- /unsafe.go: -------------------------------------------------------------------------------- 1 | // +build !appengine 2 | 3 | package msgpack 4 | 5 | import ( 6 | "unsafe" 7 | ) 8 | 9 | // bytesToString converts byte slice to string. 10 | func bytesToString(b []byte) string { 11 | return *(*string)(unsafe.Pointer(&b)) 12 | } 13 | 14 | // stringToBytes converts string to byte slice. 15 | func stringToBytes(s string) []byte { 16 | return *(*[]byte)(unsafe.Pointer( 17 | &struct { 18 | string 19 | Cap int 20 | }{s, len(s)}, 21 | )) 22 | } 23 | -------------------------------------------------------------------------------- /version.go: -------------------------------------------------------------------------------- 1 | package msgpack 2 | 3 | // Version is the current release version. 4 | func Version() string { 5 | return "5.4.1" 6 | } 7 | --------------------------------------------------------------------------------