[chore] update bun + extras v1.1.16 -> v1.1.17 (#2534)

This commit is contained in:
tobi 2024-01-15 14:08:07 +01:00 committed by GitHub
commit 6433a50582
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1426 additions and 294 deletions

View file

@ -1,6 +1,30 @@
## [5.4.1](https://github.com/vmihailenco/msgpack/compare/v5.4.0...v5.4.1) (2023-10-26)
### Bug Fixes
* **reflect:** not assignable to type ([edeaedd](https://github.com/vmihailenco/msgpack/commit/edeaeddb2d51868df8c6ff2d8a218b527aeaf5fd))
# [5.4.0](https://github.com/vmihailenco/msgpack/compare/v5.3.6...v5.4.0) (2023-10-01)
## [5.3.6](https://github.com/vmihailenco/msgpack/compare/v5.3.5...v5.3.6) (2023-10-01)
### Features
* allow overwriting time.Time parsing from extID 13 (for NodeJS Date) ([9a6b73b](https://github.com/vmihailenco/msgpack/commit/9a6b73b3588fd962d568715f4375e24b089f7066))
* apply omitEmptyFlag to empty structs ([e5f8d03](https://github.com/vmihailenco/msgpack/commit/e5f8d03c0a1dd9cc571d648cd610305139078de5))
* support sorted keys for map[string]bool ([690c1fa](https://github.com/vmihailenco/msgpack/commit/690c1fab9814fab4842295ea986111f49850d9a4))
## [5.3.5](https://github.com/vmihailenco/msgpack/compare/v5.3.4...v5.3.5) (2021-10-22)
- Allow decoding `nil` code as boolean false.
## v5

View file

@ -5,19 +5,18 @@
[![Documentation](https://img.shields.io/badge/msgpack-documentation-informational)](https://msgpack.uptrace.dev/)
[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
> :heart:
> [**Uptrace.dev** - All-in-one tool to optimize performance and monitor errors & logs](https://uptrace.dev/?utm_source=gh-msgpack&utm_campaign=gh-msgpack-var2)
> msgpack is brought to you by :star: [**uptrace/uptrace**](https://github.com/uptrace/uptrace).
> Uptrace is an [open source APM](https://uptrace.dev/get/open-source-apm.html) and blazingly fast
> [distributed tracing tool](https://get.uptrace.dev/compare/distributed-tracing-tools.html) powered
> by OpenTelemetry and ClickHouse. Give it a star as well!
## Resources
- Join [Discord](https://discord.gg/rWtp5Aj) to ask questions.
- [Documentation](https://msgpack.uptrace.dev)
- [Chat](https://discord.gg/rWtp5Aj)
- [Reference](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5)
- [Examples](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5#pkg-examples)
Other projects you may like:
- [Bun](https://bun.uptrace.dev) - fast and simple SQL client for PostgreSQL, MySQL, and SQLite.
- [BunRouter](https://bunrouter.uptrace.dev/) - fast and flexible HTTP router for Go.
## Features
- Primitives, arrays, maps, structs, time.Time and interface{}.
@ -84,3 +83,18 @@ func ExampleMarshal() {
// Output: bar
}
```
## See also
- [Golang ORM](https://github.com/uptrace/bun) for PostgreSQL, MySQL, MSSQL, and SQLite
- [Golang PostgreSQL](https://bun.uptrace.dev/postgres/)
- [Golang HTTP router](https://github.com/uptrace/bunrouter)
- [Golang ClickHouse ORM](https://github.com/uptrace/go-clickhouse)
## Contributors
Thanks to all the people who already contributed!
<a href="https://github.com/vmihailenco/msgpack/graphs/contributors">
<img src="https://contributors-img.web.app/image?repo=vmihailenco/msgpack" />
</a>

View file

@ -14,14 +14,16 @@ import (
)
const (
looseInterfaceDecodingFlag uint32 = 1 << iota
disallowUnknownFieldsFlag
bytesAllocLimit = 1 << 20 // 1mb
sliceAllocLimit = 1e6 // 1m elements
maxMapSize = 1e6 // 1m elements
)
const (
bytesAllocLimit = 1e6 // 1mb
sliceAllocLimit = 1e4
maxMapSize = 1e6
looseInterfaceDecodingFlag uint32 = 1 << iota
disallowUnknownFieldsFlag
usePreallocateValues
disableAllocLimitFlag
)
type bufReader interface {
@ -53,7 +55,7 @@ func PutDecoder(dec *Decoder) {
// in the value pointed to by v.
func Unmarshal(data []byte, v interface{}) error {
dec := GetDecoder()
dec.UsePreallocateValues(true)
dec.Reset(bytes.NewReader(data))
err := dec.Decode(v)
@ -64,16 +66,14 @@ func Unmarshal(data []byte, v interface{}) error {
// A Decoder reads and decodes MessagePack values from an input stream.
type Decoder struct {
r io.Reader
s io.ByteScanner
buf []byte
rec []byte // accumulates read data if not nil
r io.Reader
s io.ByteScanner
mapDecoder func(*Decoder) (interface{}, error)
structTag string
buf []byte
rec []byte
dict []string
flags uint32
structTag string
mapDecoder func(*Decoder) (interface{}, error)
}
// NewDecoder returns a new decoder that reads from r.
@ -95,10 +95,9 @@ func (d *Decoder) Reset(r io.Reader) {
// ResetDict is like Reset, but also resets the dict.
func (d *Decoder) ResetDict(r io.Reader, dict []string) {
d.resetReader(r)
d.ResetReader(r)
d.flags = 0
d.structTag = ""
d.mapDecoder = nil
d.dict = dict
}
@ -110,10 +109,16 @@ func (d *Decoder) WithDict(dict []string, fn func(*Decoder) error) error {
return err
}
func (d *Decoder) resetReader(r io.Reader) {
func (d *Decoder) ResetReader(r io.Reader) {
d.mapDecoder = nil
d.dict = nil
if br, ok := r.(bufReader); ok {
d.r = br
d.s = br
} else if r == nil {
d.r = nil
d.s = nil
} else {
br := bufio.NewReader(r)
d.r = br
@ -161,6 +166,24 @@ func (d *Decoder) UseInternedStrings(on bool) {
}
}
// UsePreallocateValues enables preallocating values in chunks
func (d *Decoder) UsePreallocateValues(on bool) {
if on {
d.flags |= usePreallocateValues
} else {
d.flags &= ^usePreallocateValues
}
}
// DisableAllocLimit enables fully allocating slices/maps when the size is known
func (d *Decoder) DisableAllocLimit(on bool) {
if on {
d.flags |= disableAllocLimitFlag
} else {
d.flags &= ^disableAllocLimitFlag
}
}
// Buffered returns a reader of the data remaining in the Decoder's buffer.
// The reader is valid until the next call to Decode.
func (d *Decoder) Buffered() io.Reader {
@ -603,7 +626,11 @@ func (d *Decoder) readFull(b []byte) error {
func (d *Decoder) readN(n int) ([]byte, error) {
var err error
d.buf, err = readN(d.r, d.buf, n)
if d.flags&disableAllocLimitFlag != 0 {
d.buf, err = readN(d.r, d.buf, n)
} else {
d.buf, err = readNGrow(d.r, d.buf, n)
}
if err != nil {
return nil, err
}
@ -615,6 +642,24 @@ func (d *Decoder) readN(n int) ([]byte, error) {
}
func readN(r io.Reader, b []byte, n int) ([]byte, error) {
if b == nil {
if n == 0 {
return make([]byte, 0), nil
}
b = make([]byte, 0, n)
}
if n > cap(b) {
b = append(b, make([]byte, n-len(b))...)
} else if n <= cap(b) {
b = b[:n]
}
_, err := io.ReadFull(r, b)
return b, err
}
func readNGrow(r io.Reader, b []byte, n int) ([]byte, error) {
if b == nil {
if n == 0 {
return make([]byte, 0), nil

View file

@ -13,6 +13,8 @@ var errArrayStruct = errors.New("msgpack: number of fields in array-encoded stru
var (
mapStringStringPtrType = reflect.TypeOf((*map[string]string)(nil))
mapStringStringType = mapStringStringPtrType.Elem()
mapStringBoolPtrType = reflect.TypeOf((*map[string]bool)(nil))
mapStringBoolType = mapStringBoolPtrType.Elem()
)
var (
@ -33,7 +35,11 @@ func decodeMapValue(d *Decoder, v reflect.Value) error {
}
if v.IsNil() {
v.Set(reflect.MakeMap(typ))
ln := n
if d.flags&disableAllocLimitFlag == 0 {
ln = min(ln, maxMapSize)
}
v.Set(reflect.MakeMapWithSize(typ, ln))
}
if n == 0 {
return nil
@ -104,7 +110,11 @@ func (d *Decoder) decodeMapStringStringPtr(ptr *map[string]string) error {
m := *ptr
if m == nil {
*ptr = make(map[string]string, min(size, maxMapSize))
ln := size
if d.flags&disableAllocLimitFlag == 0 {
ln = min(size, maxMapSize)
}
*ptr = make(map[string]string, ln)
m = *ptr
}
@ -147,7 +157,7 @@ func (d *Decoder) DecodeMap() (map[string]interface{}, error) {
return nil, nil
}
m := make(map[string]interface{}, min(n, maxMapSize))
m := make(map[string]interface{}, n)
for i := 0; i < n; i++ {
mk, err := d.DecodeString()
@ -174,7 +184,7 @@ func (d *Decoder) DecodeUntypedMap() (map[interface{}]interface{}, error) {
return nil, nil
}
m := make(map[interface{}]interface{}, min(n, maxMapSize))
m := make(map[interface{}]interface{}, n)
for i := 0; i < n; i++ {
mk, err := d.decodeInterfaceCond()
@ -222,7 +232,13 @@ func (d *Decoder) DecodeTypedMap() (interface{}, error) {
}
mapType := reflect.MapOf(keyType, valueType)
mapValue := reflect.MakeMap(mapType)
ln := n
if d.flags&disableAllocLimitFlag == 0 {
ln = min(ln, maxMapSize)
}
mapValue := reflect.MakeMapWithSize(mapType, ln)
mapValue.SetMapIndex(reflect.ValueOf(key), reflect.ValueOf(value))
n--
@ -234,17 +250,18 @@ func (d *Decoder) DecodeTypedMap() (interface{}, error) {
}
func (d *Decoder) decodeTypedMapValue(v reflect.Value, n int) error {
typ := v.Type()
keyType := typ.Key()
valueType := typ.Elem()
var (
typ = v.Type()
keyType = typ.Key()
valueType = typ.Elem()
)
for i := 0; i < n; i++ {
mk := reflect.New(keyType).Elem()
mk := d.newValue(keyType).Elem()
if err := d.DecodeValue(mk); err != nil {
return err
}
mv := reflect.New(valueType).Elem()
mv := d.newValue(valueType).Elem()
if err := d.DecodeValue(mv); err != nil {
return err
}

View file

@ -11,9 +11,8 @@ import (
type queryResult struct {
query string
key string
values []interface{}
hasAsterisk bool
values []interface{}
}
func (q *queryResult) nextKey() {

View file

@ -49,7 +49,7 @@ func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
return nil
}
ss := makeStrings(*ptr, n)
ss := makeStrings(*ptr, n, d.flags&disableAllocLimitFlag != 0)
for i := 0; i < n; i++ {
s, err := d.DecodeString()
if err != nil {
@ -62,8 +62,8 @@ func (d *Decoder) decodeStringSlicePtr(ptr *[]string) error {
return nil
}
func makeStrings(s []string, n int) []string {
if n > sliceAllocLimit {
func makeStrings(s []string, n int, noLimit bool) []string {
if !noLimit && n > sliceAllocLimit {
n = sliceAllocLimit
}
@ -101,10 +101,17 @@ func decodeSliceValue(d *Decoder, v reflect.Value) error {
v.Set(v.Slice(0, v.Cap()))
}
noLimit := d.flags&disableAllocLimitFlag != 1
if noLimit && n > v.Len() {
v.Set(growSliceValue(v, n, noLimit))
}
for i := 0; i < n; i++ {
if i >= v.Len() {
v.Set(growSliceValue(v, n))
if !noLimit && i >= v.Len() {
v.Set(growSliceValue(v, n, noLimit))
}
elem := v.Index(i)
if err := d.DecodeValue(elem); err != nil {
return err
@ -114,9 +121,9 @@ func decodeSliceValue(d *Decoder, v reflect.Value) error {
return nil
}
func growSliceValue(v reflect.Value, n int) reflect.Value {
func growSliceValue(v reflect.Value, n int, noLimit bool) reflect.Value {
diff := n - v.Len()
if diff > sliceAllocLimit {
if !noLimit && diff > sliceAllocLimit {
diff = sliceAllocLimit
}
v = reflect.AppendSlice(v, reflect.MakeSlice(v.Type(), diff, diff))
@ -163,7 +170,7 @@ func (d *Decoder) decodeSlice(c byte) ([]interface{}, error) {
return nil, nil
}
s := make([]interface{}, 0, min(n, sliceAllocLimit))
s := make([]interface{}, 0, n)
for i := 0; i < n; i++ {
v, err := d.decodeInterfaceCond()
if err != nil {

View file

@ -0,0 +1,46 @@
package msgpack
import (
"reflect"
"sync"
)
var cachedValues struct {
m map[reflect.Type]chan reflect.Value
sync.RWMutex
}
func cachedValue(t reflect.Type) reflect.Value {
cachedValues.RLock()
ch := cachedValues.m[t]
cachedValues.RUnlock()
if ch != nil {
return <-ch
}
cachedValues.Lock()
defer cachedValues.Unlock()
if ch = cachedValues.m[t]; ch != nil {
return <-ch
}
ch = make(chan reflect.Value, 256)
go func() {
for {
ch <- reflect.New(t)
}
}()
if cachedValues.m == nil {
cachedValues.m = make(map[reflect.Type]chan reflect.Value, 8)
}
cachedValues.m[t] = ch
return <-ch
}
func (d *Decoder) newValue(t reflect.Type) reflect.Value {
if d.flags&usePreallocateValues == 0 {
return reflect.New(t)
}
return cachedValue(t)
}

View file

@ -10,6 +10,7 @@ import (
var (
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
stringType = reflect.TypeOf((*string)(nil)).Elem()
boolType = reflect.TypeOf((*bool)(nil)).Elem()
)
var valueDecoders []decoderFunc
@ -127,12 +128,12 @@ func ptrValueDecoder(typ reflect.Type) decoderFunc {
return func(d *Decoder, v reflect.Value) error {
if d.hasNilCode() {
if !v.IsNil() {
v.Set(reflect.Zero(v.Type()))
v.Set(d.newValue(typ).Elem())
}
return d.DecodeNil()
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
v.Set(d.newValue(typ.Elem()))
}
return decoder(d, v.Elem())
}
@ -154,7 +155,7 @@ func nilAwareDecoder(typ reflect.Type, fn decoderFunc) decoderFunc {
return d.decodeNilValue(v)
}
if v.IsNil() {
v.Set(reflect.New(v.Type().Elem()))
v.Set(d.newValue(typ.Elem()))
}
return fn(d, v)
}

View file

@ -75,15 +75,12 @@ func Marshal(v interface{}) ([]byte, error) {
}
type Encoder struct {
w writer
buf []byte
timeBuf []byte
dict map[string]int
flags uint32
w writer
dict map[string]int
structTag string
buf []byte
timeBuf []byte
flags uint32
}
// NewEncoder returns a new encoder that writes to w.
@ -107,7 +104,7 @@ func (e *Encoder) Reset(w io.Writer) {
// ResetDict is like Reset, but also resets the dict.
func (e *Encoder) ResetDict(w io.Writer, dict map[string]int) {
e.resetWriter(w)
e.ResetWriter(w)
e.flags = 0
e.structTag = ""
e.dict = dict
@ -121,9 +118,12 @@ func (e *Encoder) WithDict(dict map[string]int, fn func(*Encoder) error) error {
return err
}
func (e *Encoder) resetWriter(w io.Writer) {
func (e *Encoder) ResetWriter(w io.Writer) {
e.dict = nil
if bw, ok := w.(writer); ok {
e.w = bw
} else if w == nil {
e.w = nil
} else {
e.w = newByteWriter(w)
}
@ -132,6 +132,7 @@ func (e *Encoder) resetWriter(w io.Writer) {
// SetSortMapKeys causes the Encoder to encode map keys in increasing order.
// Supported map types are:
// - map[string]string
// - map[string]bool
// - map[string]interface{}
func (e *Encoder) SetSortMapKeys(on bool) *Encoder {
if on {

View file

@ -30,6 +30,32 @@ func encodeMapValue(e *Encoder, v reflect.Value) error {
return nil
}
func encodeMapStringBoolValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
}
if err := e.EncodeMapLen(v.Len()); err != nil {
return err
}
m := v.Convert(mapStringBoolType).Interface().(map[string]bool)
if e.flags&sortMapKeysFlag != 0 {
return e.encodeSortedMapStringBool(m)
}
for mk, mv := range m {
if err := e.EncodeString(mk); err != nil {
return err
}
if err := e.EncodeBool(mv); err != nil {
return err
}
}
return nil
}
func encodeMapStringStringValue(e *Encoder, v reflect.Value) error {
if v.IsNil() {
return e.EncodeNil()
@ -113,6 +139,26 @@ func (e *Encoder) EncodeMapSorted(m map[string]interface{}) error {
return nil
}
func (e *Encoder) encodeSortedMapStringBool(m map[string]bool) error {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
err := e.EncodeString(k)
if err != nil {
return err
}
if err = e.EncodeBool(m[k]); err != nil {
return err
}
}
return nil
}
func (e *Encoder) encodeSortedMapStringString(m map[string]string) error {
keys := make([]string, 0, len(m))
for k := range m {
@ -148,7 +194,7 @@ func encodeStructValue(e *Encoder, strct reflect.Value) error {
if e.flags&arrayEncodedStructsFlag != 0 || structFields.AsArray {
return encodeStructValueAsArray(e, strct, structFields.List)
}
fields := structFields.OmitEmpty(strct, e.flags&omitEmptyFlag != 0)
fields := structFields.OmitEmpty(e, strct)
if err := e.EncodeMapLen(len(fields)); err != nil {
return err

View file

@ -111,6 +111,8 @@ func _getEncoder(typ reflect.Type) encoderFunc {
switch typ.Elem() {
case stringType:
return encodeMapStringStringValue
case boolType:
return encodeMapStringBoolValue
case interfaceType:
return encodeMapStringInterfaceValue
}
@ -198,6 +200,13 @@ func nilable(kind reflect.Kind) bool {
return false
}
func nilableType(t reflect.Type) bool {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
return nilable(t.Kind())
}
//------------------------------------------------------------------------------
func marshalBinaryValueAddr(e *Encoder, v reflect.Value) error {

View file

@ -96,7 +96,7 @@ func makeExtEncoder(
func makeExtEncoderAddr(extEncoder encoderFunc) encoderFunc {
return func(e *Encoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
return fmt.Errorf("msgpack: EncodeExt(nonaddressable %T)", v.Interface())
}
return extEncoder(e, v.Addr())
}
@ -157,7 +157,7 @@ func makeExtDecoder(
func makeExtDecoderAddr(extDecoder decoderFunc) decoderFunc {
return func(d *Decoder, v reflect.Value) error {
if !v.CanAddr() {
return fmt.Errorf("msgpack: Decode(nonaddressable %T)", v.Interface())
return fmt.Errorf("msgpack: DecodeExt(nonaddressable %T)", v.Interface())
}
return extDecoder(d, v.Addr())
}
@ -254,9 +254,9 @@ func (d *Decoder) decodeInterfaceExt(c byte) (interface{}, error) {
return nil, fmt.Errorf("msgpack: unknown ext id=%d", extID)
}
v := reflect.New(info.Type).Elem()
v := d.newValue(info.Type).Elem()
if nilable(v.Kind()) && v.IsNil() {
v.Set(reflect.New(info.Type.Elem()))
v.Set(d.newValue(info.Type.Elem()))
}
if err := info.Decoder(d, v, extLen); err != nil {

View file

@ -57,18 +57,16 @@ func encodeInternedStringValue(e *Encoder, v reflect.Value) error {
func (e *Encoder) encodeInternedString(s string, intern bool) error {
// Interned string takes at least 3 bytes. Plain string 1 byte + string len.
if len(s) >= minInternedStringLen {
if idx, ok := e.dict[s]; ok {
return e.encodeInternedStringIndex(idx)
}
if idx, ok := e.dict[s]; ok {
return e.encodeInternedStringIndex(idx)
}
if intern && len(e.dict) < maxDictLen {
if e.dict == nil {
e.dict = make(map[string]int)
}
idx := len(e.dict)
e.dict[s] = idx
if intern && len(s) >= minInternedStringLen && len(e.dict) < maxDictLen {
if e.dict == nil {
e.dict = make(map[string]int)
}
idx := len(e.dict)
e.dict[s] = idx
}
return e.encodeNormalString(s)

View file

@ -43,8 +43,8 @@ func (m *RawMessage) DecodeMsgpack(dec *Decoder) error {
//------------------------------------------------------------------------------
type unexpectedCodeError struct {
code byte
hint string
code byte
}
func (err unexpectedCodeError) Error() string {

View file

@ -1,4 +1,4 @@
{
"name": "msgpack",
"version": "5.3.5"
"version": "5.4.1"
}

View file

@ -26,6 +26,11 @@ func timeDecoder(d *Decoder, v reflect.Value, extLen int) error {
return err
}
if tm.IsZero() {
// Zero time does not have timezone information.
tm = tm.UTC()
}
ptr := v.Addr().Interface().(*time.Time)
*ptr = tm
@ -103,7 +108,8 @@ func (d *Decoder) DecodeTime() (time.Time, error) {
return time.Time{}, err
}
if extID != timeExtID {
// NodeJS seems to use extID 13.
if extID != timeExtID && extID != 13 {
return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID)
}

View file

@ -66,8 +66,8 @@ type structCache struct {
}
type structCacheKey struct {
tag string
typ reflect.Type
tag string
}
func newStructCache() *structCache {
@ -90,19 +90,20 @@ func (m *structCache) Fields(typ reflect.Type, tag string) *fields {
//------------------------------------------------------------------------------
type field struct {
encoder encoderFunc
decoder decoderFunc
name string
index []int
omitEmpty bool
encoder encoderFunc
decoder decoderFunc
}
func (f *field) Omit(strct reflect.Value, forced bool) bool {
func (f *field) Omit(e *Encoder, strct reflect.Value) bool {
v, ok := fieldByIndex(strct, f.index)
if !ok {
return true
}
return (f.omitEmpty || forced) && isEmptyValue(v)
forced := e.flags&omitEmptyFlag != 0
return (f.omitEmpty || forced) && e.isEmptyValue(v)
}
func (f *field) EncodeValue(e *Encoder, strct reflect.Value) error {
@ -152,7 +153,8 @@ func (fs *fields) warnIfFieldExists(name string) {
}
}
func (fs *fields) OmitEmpty(strct reflect.Value, forced bool) []*field {
func (fs *fields) OmitEmpty(e *Encoder, strct reflect.Value) []*field {
forced := e.flags&omitEmptyFlag != 0
if !fs.hasOmitEmpty && !forced {
return fs.List
}
@ -160,7 +162,7 @@ func (fs *fields) OmitEmpty(strct reflect.Value, forced bool) []*field {
fields := make([]*field, 0, len(fs.List))
for _, f := range fs.List {
if !f.Omit(strct, forced) {
if !f.Omit(e, strct) {
fields = append(fields, f)
}
}
@ -317,7 +319,7 @@ type isZeroer interface {
IsZero() bool
}
func isEmptyValue(v reflect.Value) bool {
func (e *Encoder) isEmptyValue(v reflect.Value) bool {
kind := v.Kind()
for kind == reflect.Interface {
@ -335,6 +337,10 @@ func isEmptyValue(v reflect.Value) bool {
switch kind {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
return v.Len() == 0
case reflect.Struct:
structFields := structs.Fields(v.Type(), e.structTag)
fields := structFields.OmitEmpty(e, v)
return len(fields) == 0
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@ -399,7 +405,7 @@ func indirectNil(v reflect.Value) (reflect.Value, bool) {
if elemType.Kind() != reflect.Struct {
return v, false
}
v.Set(reflect.New(elemType))
v.Set(cachedValue(elemType))
}
v = v.Elem()
}

View file

@ -2,5 +2,5 @@ package msgpack
// Version is the current release version.
func Version() string {
return "5.3.5"
return "5.4.1"
}