Skip to content

fix: rewrite decode_struct so struct decoding actually works#14

Merged
medvednikov merged 2 commits into
masterfrom
fix-decode-struct
May 26, 2026
Merged

fix: rewrite decode_struct so struct decoding actually works#14
medvednikov merged 2 commits into
masterfrom
fix-decode-struct

Conversation

@medvednikov
Copy link
Copy Markdown
Member

Summary

Fixes #12. Struct decoding never worked: the previous decode_struct

  • never read the map header byte,
  • never read the field-name keys the encoder writes (it tried to read values directly),
  • called d.decode(data[d.pos..], mut field_val) — re-slicing the buffer without resetting d.pos, so next() read from the wrong offset,
  • and assigned via val[field.name] = field_val, which doesn't compile against current V (`type 'T' does not support indexing`).

The user-visible symptom in #12 was `invalid integer descriptor byte 117`0x75 = 'u', the first byte of the key \"used_ids\" being misinterpreted as an integer descriptor.

Rewrite to mirror the encoder's wire layout:

  1. Read the map header (already loaded into d.bd by the prior next()) → map_len.
  2. For each entry: next() → decode the key as a msgpack string → next() → look up the matching field by name (honoring @[codec: 'alias'] attrs the encoder writes) → decode the value into it via comptime field assignment.

Extracted the type-dispatch out of decode[T] into a private decode_value helper so containers can decode children without clobbering d.buffer / d.pos.

Also uncomments the previously-disabled struct round-trip assertion in decode_test.v and adds round-trips that don't depend on the encoder's chosen integer width.

Test plan

  • v test . — all 3 test files pass (encode, decode, decode_to_json), including the previously-commented struct round-trip
  • Issue Decoding does not work at all. #12 repro now succeeds: msgpack.decode[Map](msgpack.encode(Map{used_ids: 1})) returns Map{used_ids: 1} instead of erroring with byte 117
  • Round-trip a struct with mixed-type fields: Struct{'John', 30} and Struct{'', 0}
  • Independent of fix: use minimal integer encoding and decode fixint bytes #13 (this PR branches from master)

The previous decode_struct never read the map header, never read field
keys, fed each child decode call a re-sliced buffer without resetting
d.pos, and assigned via val[field.name] = ... which does not compile on
structs in current V. Decoding any struct produced
"invalid integer descriptor byte 117" (the 'u' from a field name being
treated as a value descriptor — see #12) or a compile
error.

Rewrite to mirror the encoder's wire layout: read the map header,
iterate map_len entries, read each key as a msgpack string, look up
the matching struct field by name (or by @[codec: 'alias'] attr), and
decode the value into it. Extract the type dispatch from decode[T] into
a private decode_value helper so containers can decode children without
clobbering d.buffer / d.pos. Uncomment the struct round-trip assertion
and add fresh round-trips that don't depend on the encoder's chosen
integer width.

Fixes #12.
@medvednikov medvednikov merged commit 426695c into master May 26, 2026
2 checks passed
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.

Decoding does not work at all.

1 participant