From 37d0807a9496fdb67df2200132b5e73bf8466e9f Mon Sep 17 00:00:00 2001 From: paq <89paku@gmail.com> Date: Sun, 12 Apr 2026 08:52:53 +0900 Subject: [PATCH 1/2] fix: restore reader depth on duplicate key error in map structs --- zerompk/src/lib.rs | 3 +++ zerompk/src/read.rs | 31 +++++++++++++++++++++++++++++++ zerompk_derive/src/lib.rs | 12 ++++++++---- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/zerompk/src/lib.rs b/zerompk/src/lib.rs index 2ac53cd..3d483cc 100644 --- a/zerompk/src/lib.rs +++ b/zerompk/src/lib.rs @@ -1,5 +1,8 @@ #![no_std] +#[cfg(test)] +extern crate self as zerompk; + mod consts; mod error; mod r#impl; diff --git a/zerompk/src/read.rs b/zerompk/src/read.rs index c25c2a8..57e1126 100644 --- a/zerompk/src/read.rs +++ b/zerompk/src/read.rs @@ -1503,3 +1503,34 @@ impl<'de, R: std::io::Read> Read<'de> for IOReader { } } } + +#[cfg(test)] +mod tests { + use super::SliceReader; + use crate::{Error, FromMessagePack}; + + #[allow(dead_code)] + #[derive(Debug, zerompk_derive::FromMessagePack)] + #[msgpack(map)] + struct DuplicateKeyMap { + x: u8, + y: u8, + } + + #[test] + fn derived_map_struct_duplicate_key_restores_reader_depth() { + let data = [ + 0x82, // fixmap with 2 entries + 0xa1, b'x', // fixstr of length 1: "x" + 0x01, // positive fixint: 1 + 0xa1, b'x', // fixstr of length 1: "x" (duplicate key) + 0x02, // positive fixint: 2 + ]; + let mut reader = SliceReader::new(&data); + + let err = DuplicateKeyMap::read(&mut reader).unwrap_err(); + + assert!(matches!(err, Error::KeyDuplicated(ref key) if key == "x")); + assert_eq!(reader.depth, 0); + } +} diff --git a/zerompk_derive/src/lib.rs b/zerompk_derive/src/lib.rs index 0e5d2bd..6d84214 100644 --- a/zerompk_derive/src/lib.rs +++ b/zerompk_derive/src/lib.rs @@ -1128,7 +1128,7 @@ fn expand_map_struct(data: &DataStruct) -> Result { quote! { #idx => { if #slot.is_some() { - return Err(::zerompk::Error::KeyDuplicated(#key_name.into())); + break '__zerompk_read_map Err(::zerompk::Error::KeyDuplicated(#key_name.into())); } #slot = ::core::option::Option::Some(#read_expr); } @@ -1167,6 +1167,7 @@ fn expand_map_struct(data: &DataStruct) -> Result { }; let read = quote! { + '__zerompk_read_map: { reader.check_map_len(#count)?; #( let mut #slots: ::core::option::Option<#tys> = ::core::option::Option::None; )* @@ -1189,7 +1190,8 @@ fn expand_map_struct(data: &DataStruct) -> Result { let #names = #slots.ok_or_else(|| ::zerompk::Error::KeyNotFound(#key_lits.into()))?; )* - Ok(Self { #( #init_fields ),* }) + break '__zerompk_read_map Ok(Self { #( #init_fields ),* }); + } }; Ok(ImplBody { write, read }) @@ -1690,7 +1692,7 @@ fn build_enum_variant_payload( quote! { #idx => { if #slot.is_some() { - return Err(::zerompk::Error::KeyDuplicated(#key_name.into())); + break '__zerompk_read_map Err(::zerompk::Error::KeyDuplicated(#key_name.into())); } #slot = ::core::option::Option::Some(#read_expr); } @@ -1734,6 +1736,7 @@ fn build_enum_variant_payload( }; let read_ctor = quote! { + '__zerompk_read_map: { reader.check_map_len(#count)?; #( let mut #slot_vars: ::core::option::Option<#active_tys> = ::core::option::Option::None; )* @@ -1756,7 +1759,8 @@ fn build_enum_variant_payload( let #active_names = #slot_vars.ok_or_else(|| ::zerompk::Error::KeyNotFound(#key_lits.into()))?; )* - Ok(Self::#v_ident { #( #init_fields ),* }) + break '__zerompk_read_map Ok(Self::#v_ident { #( #init_fields ),* }); + } }; Ok(( From 508082d17d60055d1c5f58eec2ee47c0fa9217dd Mon Sep 17 00:00:00 2001 From: nuskey8 Date: Fri, 24 Apr 2026 23:27:52 +0900 Subject: [PATCH 2/2] fix: use in tests --- zerompk/src/read.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/zerompk/src/read.rs b/zerompk/src/read.rs index 7109def..6ad361d 100644 --- a/zerompk/src/read.rs +++ b/zerompk/src/read.rs @@ -1477,8 +1477,7 @@ impl<'de, R: std::io::Read> Read<'de> for IOReader { #[cfg(test)] mod tests { - use super::SliceReader; - use crate::{Error, FromMessagePack}; + use crate::{Error, FromMessagePack, Read, read::IOReader, read::SliceReader}; #[allow(dead_code)] #[derive(Debug, zerompk_derive::FromMessagePack)]