From e9066cf6ab0bbb21ab287d643de4ac2c53dc1ac8 Mon Sep 17 00:00:00 2001 From: Orual Date: Sun, 23 Aug 2026 18:11:17 -0400 Subject: [PATCH] bytes helpers: accept owned map keys in $bytes visitors (serde_json::from_value compat) visit_map now deserializes keys as Cow<'de, str>, so owned-key deserializers (serde_json::from_value) work alongside borrowing ones (from_str/from_slice/CBOR). regression test added. --- .../src/opt_serde_bytes_helper.rs | 9 +++++---- .../jacquard-common/src/serde_bytes_helper.rs | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/crates/jacquard-common/src/opt_serde_bytes_helper.rs b/crates/jacquard-common/src/opt_serde_bytes_helper.rs index 1705c3ec0..4e7ef1cd0 100644 --- a/crates/jacquard-common/src/opt_serde_bytes_helper.rs +++ b/crates/jacquard-common/src/opt_serde_bytes_helper.rs @@ -1,5 +1,6 @@ //! Custom serde helpers for bytes::Bytes using serde_bytes +use alloc::borrow::Cow; use alloc::string::String; use alloc::vec::Vec; use base64::{ @@ -102,8 +103,8 @@ impl<'de> Visitor<'de> for OptBytesVisitor { { let mut bytes = None; - while let Some(key) = map.next_key()? { - match key { + while let Some(key) = map.next_key::>()? { + match key.as_ref() { "$bytes" => { if bytes.is_some() { return Err(de::Error::duplicate_field("$bytes")); @@ -122,8 +123,8 @@ impl<'de> Visitor<'de> for OptBytesVisitor { return Err(de::Error::custom("invalid base64 string")); } } - _ => { - return Err(de::Error::unknown_field(key, &["$bytes"])); + other => { + return Err(de::Error::unknown_field(other, &["$bytes"])); } } } diff --git a/crates/jacquard-common/src/serde_bytes_helper.rs b/crates/jacquard-common/src/serde_bytes_helper.rs index 239d5de23..a648f9205 100644 --- a/crates/jacquard-common/src/serde_bytes_helper.rs +++ b/crates/jacquard-common/src/serde_bytes_helper.rs @@ -1,5 +1,6 @@ //! Custom serde helpers for bytes::Bytes using serde_bytes +use alloc::borrow::Cow; use alloc::string::String; use alloc::vec::Vec; use core::fmt; @@ -91,8 +92,8 @@ impl<'de> Visitor<'de> for BytesVisitor { { let mut bytes = None; - while let Some(key) = map.next_key()? { - match key { + while let Some(key) = map.next_key::>()? { + match key.as_ref() { "$bytes" => { if bytes.is_some() { return Err(de::Error::duplicate_field("$bytes")); @@ -111,8 +112,8 @@ impl<'de> Visitor<'de> for BytesVisitor { return Err(de::Error::custom("invalid base64 string")); } } - _ => { - return Err(de::Error::unknown_field(key, &["$bytes"])); + other => { + return Err(de::Error::unknown_field(other, &["$bytes"])); } } } @@ -132,6 +133,15 @@ mod tests { bytes: Bytes, } + #[test] + fn json_from_value_accepts_owned_map_keys() { + let value = serde_json::json!({ + "bytes": {"$bytes": BASE64_STANDARD.encode([0, 1, 2, 255])} + }); + let parsed: BytePayload = serde_json::from_value(value).unwrap(); + assert_eq!(parsed.bytes, Bytes::from_static(&[0, 1, 2, 255])); + } + #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "$type")] enum TaggedPayload { -- 2.51.2