This crate is a public version if the serde private API for content reference deserialization. It is mainly useful to do enum deserialization without cloning the data.
Since integer tags are not available, you can use that to deserialize versioned structs.
use serde_content_ref::{Content, ContentRefDeserializer};
use serde::Deserialize;
#[derive(Clone, Debug)]
pub struct Edition<const V: u32>;
impl<const V: u32> Edition<V> {
pub const ERROR: &'static str = "Invalid edition";
}
impl<const V: u32> PartialEq<Edition<V>> for u32 {
fn eq(&self, _: &Edition<V>) -> bool {
V == *self
}
}
impl<'de, const V: u32> Deserialize<'de> for Edition<V> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = u32::deserialize(deserializer)?;
if value == V {
Ok(Edition::<V>)
} else {
Err(serde::de::Error::custom(Self::ERROR))
}
}
}
#[derive(Debug, Deserialize)]
pub struct MyStructV1 {
pub edition: Edition<1>,
pub name: String,
pub value: i32,
}
#[derive(Debug, Deserialize)]
pub struct MyStructV2 {
pub edition: Edition<2>,
pub label: String,
pub amount: f64,
}
#[derive(Debug)]
pub enum ParsableStruct {
V1(MyStructV1),
V2(MyStructV2),
}
impl<'de> Deserialize<'de> for ParsableStruct {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let content = Content::deserialize(deserializer)?;
match MyStructV2::deserialize(ContentRefDeserializer::<D::Error>::new(&content)) {
Ok(v) => return Ok(ParsableStruct::V2(v)),
Err(e) if e.to_string() != Edition::<2>::ERROR => return Err(e),
Err(_) => {},
}
match MyStructV1::deserialize(ContentRefDeserializer::<D::Error>::new(&content)) {
Ok(v) => return Ok(ParsableStruct::V1(v)),
Err(e) if e.to_string() != Edition::<1>::ERROR => return Err(e),
Err(_) => {},
}
Err(serde::de::Error::custom(
"data did not match any variant of untagged enum ParsableStruct",
))
}
}
fn main() {
// V1 JSON contains edition = 1 and v1 fields
let json_v1 = r#"{"edition": 1, "name": "v1 struct", "value": 42}"#;
// V2 JSON contains edition = 2 and v2 fields
let json_v2 = r#"{"edition": 2, "label": "v2 struct", "amount": 101.5}"#;
let v1: ParsableStruct = serde_json::from_str(json_v1).expect("should parse v1");
let v2: ParsableStruct = serde_json::from_str(json_v2).expect("should parse v2");
println!("Parsed v1: {:?}", v1);
println!("Parsed v2: {:?}", v2);
}This project includes code derived from the Serde project. See NOTICE for more details.