- decode:
readCodebsr fast path — when decoding from a byte slice, reads directly from the underlying array instead of dispatching through theio.ByteReaderinterface; eliminates ~900M interface calls/sec at Arc's throughput (#57) (StructUnmarshal -7.5%, StructUnmarshalPartially -6.1%) - decode:
PeekCodebsr fast path — peeks directly atbsr.data[bsr.pos]instead ofReadByte+UnreadByte(two interface calls) (#59) - encode: pool
OmitEmptyfiltered field slices viasync.Pool— when fields are actually omitted, the allocated[]*fieldslice is now returned to a pool for reuse instead of being GC'd (#58) - encode/decode: pool and pre-allocate interned-string dict —
SetInternedStringsDictCap(n)pre-sizes the dict to avoid map rehashing and slice growth; pooled encoders/decoders now reuse dict storage acrossReset()(cleared in place) instead of discarding it, andPut*()drops oversized dicts to keep the pool lean (#66) - decode: hoist
newValue()allocations out ofdecodeTypedMapValueloop — reuses a single key slot and value slot across all map entries, zeroing between iterations. Takes typed-map decode from 2Nreflect.New()calls to 2 per map (#65) (BenchmarkLargeMapIntInt -50% allocs/op, -50% B/op, -10% ns/op for 1000-entrymap[int]int)
- Lower
go.moddirective from 1.26 to 1.25 — preserves drop-in compatibility for downstream users on Go 1.25; CI matrix unchanged (1.25.x, 1.26.x) (#70)
- decode: zero-allocation byte-slice reader for
Unmarshal()— replacesbytes.NewReader+bufio.NewReaderwith a directbyteSliceReader, eliminating 2 allocations per call (~21% faster decode, ~50% less memory) - decode:
*interface{}fast path inDecode()— skipsreflect.ValueOffor the most commonUnmarshal(b, &interface{})pattern (~14% faster) - encode: pooled byte buffer in
Marshal()— replaces per-callbytes.Bufferwith a reusable[]byteembedded in the pooledEncoderstruct - encode:
byteSliceWriterforMarshal()path — nativeWriteByteimplementation eliminates per-byte heap allocation - encode:
byteWriter.WriteBytescratch fix for streaming path — uses[1]bytescratch instead of allocating[]byte{c} - encode:
Encode()fast paths formap[string]interface{}and[]interface{}— bypassesreflect.ValueOf+ sync.Map encoder lookup - encode:
MarshalAppend(dst, v)API — appends encoded bytes to caller-provided buffer, eliminating the finalmake+copyinMarshal()(-26% faster, -94% less memory for callers who reuse buffers) - encode: two-pass
OmitEmpty— avoids slice allocation when no fields are omitted (common case for time-series data) - encode: cache
isZeroerinterface check — pre-computes at struct-discovery time to skipv.Interface()boxing duringOmitEmptychecks - encode/decode: skip
reflect.Convertfor exact map/slice types — addsv.Type() == targetTypefast path beforeConvert()formap[string]string,map[string]bool,map[string]interface{}, and[]string(-7–8% faster) - encode:
map[string]stringfast path inEncode()type switch — bypassesreflect.ValueOf+ encoder lookup (-15% faster) - decode: replace goroutine-per-type
cachedValueswithsync.Pool— eliminates goroutine leak and channel synchronization overhead - encode: pool sorted map key slices via
sync.Pool— eliminates 1 alloc per sorted map encode forSetSortMapKeys(true)callers - decode: pool recording buffer in
unmarshalValue— eliminates 1 alloc perUnmarshaler.UnmarshalMsgpackcall - decode: inline
hasNilCodefor byte-slice reader path — peeks directly at underlying data, avoiding two interface method calls per nil check (-2–4% faster decode)
- decode: cap
decodeSlice()allocation atsliceAllocLimit(1M) to prevent OOM from malicious payloads (#1) - decode: cap
DecodeMap()allocation atmaxMapSize(1M) — same OOM vector formap[string]interface{}path - decode: fix
disableAllocLimitFlagcheck indecodeSliceValue—!= 1was always true because the flag value is1 << 3 = 8, so the alloc limit ingrowSliceValue()was never applied - decode: fix error message in
DecodeFloat64— said "decoding float32" instead of "decoding float64" (#13) - decode: allow float-encoded values to decode into
int64/uint64with validation — rejects NaN, Inf, fractional, and out-of-range values (#2) - decode: allow
float64-encoded values to decode intofloat32with overflow check (#12) - encode: handle non-addressable values with pointer receivers —
ensureAddrcreates an addressable copy instead of returning an error (#3) - encode: prevent panic when marshalling
reflect.Value— unwraps and encodes the underlying value (#15) - encode: preserve custom error types instead of reducing to plain strings via
.Error()(#22) - decode: support non-string map keys when decoding into
interface{}(#21) - decode: handle unaddressable values in interface decode (#21)
- encode: respect non-zero unexported fields in
omitemptystruct emptiness check (#6) - decode: use
interface{}value type for non-string-keyed typed maps to support heterogeneous nested maps (#20) - pool: drop oversized decoder buffers (>32KB) to prevent memory leak from large decode operations (#19)
- decode: choose
TextUnmarshaleroverBinaryUnmarshalerwhen wire format isstr(#10)
- Modernize GitHub Actions (checkout@v4, setup-go@v5)
- Go version matrix: 1.25.x, 1.26.x
- Bump
go.modto Go 1.26 - CI: add
-count=1 -timeout=5mandGOGC=50to race tests to prevent OOM on runners (#33) - CI: change cross-platform step from
go testtogo vet(compile-only) - Remove tautological
if err != nilindecodeInternedInterfaceValue(nilness warning) - Remove unused
nilableTypefunction fromencode_value.go
5.4.1 (2023-10-26)
- reflect: not assignable to type (edeaedd)
5.4.0 (2023-10-01)
5.3.6 (2023-10-01)
- allow overwriting time.Time parsing from extID 13 (for NodeJS Date) (9a6b73b)
- apply omitEmptyFlag to empty structs (e5f8d03)
- support sorted keys for map[string]bool (690c1fa)
5.3.5 (2021-10-22)
- Allow decoding
nilcode as boolean false.
DecodeMapis split intoDecodeMap,DecodeTypedMap, andDecodeUntypedMap.- New msgpack extensions API.
Reset*functions also reset flags.SetMapDecodeFuncis renamed toSetMapDecoder.StructAsArrayis renamed toUseArrayEncodedStructs.SortMapKeysis renamed toSetSortMapKeys.
UseJSONTagis removed. UseSetCustomStructTag("json")instead.
- Encode, Decode, Marshal, and Unmarshal are changed to accept single argument. EncodeMulti and DecodeMulti are added as replacement.
- Added EncodeInt8/16/32/64 and EncodeUint8/16/32/64.
- Encoder changed to preserve type of numbers instead of chosing most compact encoding. The old behavior can be achieved with Encoder.UseCompactEncoding.
msgpack:",inline"tag is restored to force inlining structs.
- Decoding extension types returns pointer to the value instead of the value. Fixes #153
- gopkg.in is not supported any more. Update import path to github.com/vmihailenco/msgpack.
- Msgpack maps are decoded into map[string]interface{} by default.
- EncodeSliceLen is removed in favor of EncodeArrayLen. DecodeSliceLen is removed in favor of DecodeArrayLen.
- Embedded structs are automatically inlined where possible.
- Time is encoded using extension as described in msgpack/msgpack#209. Old format is supported as well.
- EncodeInt8/16/32/64 is replaced with EncodeInt. EncodeUint8/16/32/64 is replaced with EncodeUint. There should be no performance differences.
- DecodeInterface can now return int8/16/32 and uint8/16/32.
- PeekCode returns codes.Code instead of byte.