Skip to content

Commit 33f08f5

Browse files
committed
change Variant serde (de|)serialization
1 parent 017b992 commit 33f08f5

File tree

3 files changed

+219
-1
lines changed

3 files changed

+219
-1
lines changed

Cargo.lock

Lines changed: 117 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ serde_crate = { workspace = true, optional = true }
2020

2121
[dev-dependencies]
2222
amplify = { workspace = true, features = ["proc_attr", "hex"] }
23+
ciborium = "0.2.2"
24+
serde_json = "1.0.140"
25+
serde_yaml = "0.9.34"
2326
strict_encoding_test = { path = "./test_helpers" }
2427

2528
[target.'cfg(target_arch = "wasm32")'.dependencies]

rust/src/util.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,80 @@ impl Display for Sizing {
8484
}
8585

8686
#[derive(Clone, Eq, Debug)]
87-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate = "serde_crate"))]
8887
pub struct Variant {
8988
pub name: VariantName,
9089
pub tag: u8,
9190
}
9291
impl_strict_struct!(Variant, STRICT_TYPES_LIB; name, tag);
9392

93+
#[cfg(feature = "serde")]
94+
mod _serde {
95+
use std::str::FromStr;
96+
97+
use serde_crate::ser::SerializeStruct;
98+
use serde_crate::{Deserialize, Deserializer, Serialize, Serializer};
99+
100+
use super::*;
101+
102+
impl Serialize for Variant {
103+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104+
where S: Serializer {
105+
if serializer.is_human_readable() {
106+
serializer.serialize_str(&format!("{}:{}", self.name, self.tag))
107+
} else {
108+
let mut s = serializer.serialize_struct("Variant", 2)?;
109+
s.serialize_field("name", &self.name)?;
110+
s.serialize_field("tag", &self.tag)?;
111+
s.end()
112+
}
113+
}
114+
}
115+
116+
impl<'de> Deserialize<'de> for Variant {
117+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
118+
where D: Deserializer<'de> {
119+
if deserializer.is_human_readable() {
120+
let s = String::deserialize(deserializer)?;
121+
let mut split = s.split(':');
122+
let (name, tag) = (split.next(), split.next());
123+
if split.next().is_some() {
124+
return Err(serde::de::Error::custom(format!(
125+
"Invalid variant format: '{}'. Expected 'name:tag'",
126+
s
127+
)));
128+
}
129+
match (name, tag) {
130+
(Some(name), Some(tag)) => {
131+
let name = VariantName::from_str(name).map_err(|e| {
132+
serde::de::Error::custom(format!("Invalid variant name: {}", e))
133+
})?;
134+
let tag = tag.parse::<u8>().map_err(|e| {
135+
serde::de::Error::custom(format!("Invalid variant tag: {}", e))
136+
})?;
137+
Ok(Variant { name, tag })
138+
}
139+
_ => Err(serde::de::Error::custom(format!(
140+
"Invalid variant format: '{}'. Expected 'name:tag'",
141+
s
142+
))),
143+
}
144+
} else {
145+
#[cfg_attr(
146+
feature = "serde",
147+
derive(Deserialize),
148+
serde(crate = "serde_crate", rename = "Variant")
149+
)]
150+
struct VariantFields {
151+
name: VariantName,
152+
tag: u8,
153+
}
154+
let VariantFields { name, tag } = VariantFields::deserialize(deserializer)?;
155+
Ok(Variant { name, tag })
156+
}
157+
}
158+
}
159+
}
160+
94161
impl Variant {
95162
pub fn named(tag: u8, name: VariantName) -> Variant { Variant { name, tag } }
96163

@@ -138,3 +205,34 @@ impl Display for Variant {
138205
Ok(())
139206
}
140207
}
208+
209+
#[cfg(test)]
210+
mod test {
211+
#![allow(unused)]
212+
213+
use std::io::Cursor;
214+
215+
use crate::*;
216+
217+
#[cfg(feature = "serde")]
218+
#[test]
219+
fn variant_serde_roundtrip() {
220+
let variant_orig = Variant::strict_dumb();
221+
222+
// CBOR
223+
let mut buf = Vec::new();
224+
ciborium::into_writer(&variant_orig, &mut buf).unwrap();
225+
let variant_post: Variant = ciborium::from_reader(Cursor::new(&buf)).unwrap();
226+
assert_eq!(variant_orig, variant_post);
227+
228+
// JSON
229+
let variant_str = serde_json::to_string(&variant_orig).unwrap();
230+
let variant_post: Variant = serde_json::from_str(&variant_str).unwrap();
231+
assert_eq!(variant_orig, variant_post);
232+
233+
// YAML
234+
let variant_str = serde_yaml::to_string(&variant_orig).unwrap();
235+
let variant_post: Variant = serde_yaml::from_str(&variant_str).unwrap();
236+
assert_eq!(variant_orig, variant_post);
237+
}
238+
}

0 commit comments

Comments
 (0)