Skip to content

types: prefer TextUnmarshaler over BinaryUnmarshaler for str format#389

Open
alliasgher wants to merge 3 commits intovmihailenco:v5from
alliasgher:fix-dual-marshaler-preference
Open

types: prefer TextUnmarshaler over BinaryUnmarshaler for str format#389
alliasgher wants to merge 3 commits intovmihailenco:v5from
alliasgher:fix-dual-marshaler-preference

Conversation

@alliasgher
Copy link
Copy Markdown

Fixes #370. For types implementing both BinaryUnmarshaler and TextUnmarshaler, peek at the wire format and use TextUnmarshaler for msgpack str and BinaryUnmarshaler for everything else.

The float64 fallback error path said "decoding float32" instead of
"decoding float64". Fix the message to match the function.

Fixes vmihailenco#352

Signed-off-by: alliasgher <alliasgher123@gmail.com>
The isEmptyValue method used structs.Fields to inspect only exported
fields when deciding whether a struct value tagged omitempty should be
omitted. If a struct had zero-valued exported fields but non-zero
unexported fields, it was incorrectly treated as empty and omitted.

Replace the exported-field scan with reflect.Value.IsZero, which checks
all fields (exported and unexported) recursively. A struct is now
omitted only when it equals the zero value of its type, which is the
semantically correct behaviour for an "omit if empty" tag.

Fixes vmihailenco#378

Signed-off-by: alliasgher <alliasgher123@gmail.com>
When a type implements both encoding.BinaryUnmarshaler and
encoding.TextUnmarshaler, the decoder previously always picked
BinaryUnmarshaler regardless of the wire format. This is wrong for
types like uuid.UUID that are stored as msgpack str (e.g. after a
JSON round-trip): the BinaryUnmarshaler expects raw bytes while a
TextUnmarshaler expects the text representation.

Introduce unmarshalBinaryOrTextValue that peeks at the next code:
- msgpack str (any variant) → use TextUnmarshaler
- everything else (bin, nil, ...) → use BinaryUnmarshaler

Fixes vmihailenco#370

Signed-off-by: alliasgher <alliasgher123@gmail.com>
@xe-nvdk
Copy link
Copy Markdown

xe-nvdk commented Apr 14, 2026

Hi @alliasgher, nice fix. Heads up that this repo has been unmaintained for ~3 years and PRs have been piling up.

We maintain an active fork at github.com/Basekick-Labs/msgpack (v6) where we already handle this case — decode_value.go:269-281 peeks at the wire format and routes to TextUnmarshaler for str and BinaryUnmarshaler for everything else:

func unmarshalBinaryOrTextValue(d *Decoder, v reflect.Value) error {
    c, err := d.PeekCode()
    if err != nil {
        return err
    }
    if msgpcode.IsString(c) {
        return unmarshalTextValue(d, v)
    }
    return unmarshalBinaryValue(d, v)
}

If upstream doesn't pick this up, feel free to port it to the fork — contributions welcome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use encoding.TextUnmarshaler when MessagePack format is a str

2 participants