forked from cfrantz/serde-annotate
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support partial serialization & deserialization
This feature allows writing structs which contain `Document` nodes. - When deserializing, everything under the `Document` node is simply attached to the struct. - When serializing, the `Document` node is passed through unmodified. Signed-off-by: Chris Frantz <[email protected]>
- Loading branch information
Showing
6 changed files
with
186 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | ||
|
||
use crate::annotate::{IsDeserializer, IsSerializer}; | ||
use crate::Deserializer as AnnotatedDeserializer; | ||
use crate::{Document, Error}; | ||
|
||
impl Serialize for Document { | ||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
{ | ||
if serializer.is_serde_annotate() { | ||
// If `serializer` is the correct type, then we can clone the | ||
// Document node and return it. | ||
let r: Result<Document, Error> = Ok(self.clone()); | ||
let result = unsafe { | ||
// We have to transmute because the we can't determine at compile | ||
// time that `Result<Document, Error>` is the same type as | ||
// `Result<S::Ok, S::Error>`. If the serializer is | ||
// `AnnotatedSerializer`, then it must be the same. | ||
std::mem::transmute_copy(&r) | ||
}; | ||
std::mem::forget(r); | ||
result | ||
} else { | ||
Err(serde::ser::Error::custom("Serializing document nodes is only supported with serde_annotate::AnnotatedSerializer")) | ||
} | ||
} | ||
} | ||
|
||
impl<'de> Deserialize<'de> for Document { | ||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||
where | ||
D: Deserializer<'de>, | ||
{ | ||
if deserializer.is_serde_annotate() { | ||
unsafe { | ||
// If the deserializer is ours, then we can simply clone the | ||
// deserializer's document node. | ||
let dsz: &AnnotatedDeserializer = std::mem::transmute_copy(&deserializer); | ||
std::mem::forget(deserializer); | ||
Ok(dsz.doc.clone()) | ||
} | ||
} else { | ||
Err(serde::de::Error::custom( | ||
"Deserializing document nodes is only supported with serde_annotate::Deserializer", | ||
)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
#![feature(min_specialization)] | ||
use anyhow::Result; | ||
use serde_annotate::serialize; | ||
use serde_annotate::{Document, StrFormat}; | ||
|
||
#[derive(Debug, serde::Serialize, serde::Deserialize)] | ||
struct Partial { | ||
n: i32, | ||
doc: Document, | ||
} | ||
|
||
const SERIALIZE_RESULT: &str = r#"{ | ||
n: 5, | ||
doc: [ | ||
"Hello", | ||
"world" | ||
] | ||
}"#; | ||
|
||
#[test] | ||
fn test_partial_serialize() -> Result<()> { | ||
let p = Partial { | ||
n: 5, | ||
doc: Document::Sequence(vec![ | ||
Document::String("Hello".into(), StrFormat::Standard), | ||
Document::String("world".into(), StrFormat::Standard), | ||
]), | ||
}; | ||
let s = serialize(&p)?.to_json5().to_string(); | ||
assert_eq!(s, SERIALIZE_RESULT); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_partial_serialize_error() -> Result<()> { | ||
let p = Partial { | ||
n: 5, | ||
doc: Document::Sequence(vec![ | ||
Document::String("Hello".into(), StrFormat::Standard), | ||
Document::String("world".into(), StrFormat::Standard), | ||
]), | ||
}; | ||
let s = serde_json::to_string_pretty(&p); | ||
assert!(s.is_err()); | ||
assert_eq!( | ||
s.unwrap_err().to_string(), | ||
"Serializing document nodes is only supported with serde_annotate::AnnotatedSerializer" | ||
); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_partial_deserialize() -> Result<()> { | ||
let doc = r#"{ | ||
n: 10, | ||
doc: { | ||
# A comment | ||
key: "value", | ||
i: 5, | ||
j: 10, | ||
} | ||
}"#; | ||
let p = serde_annotate::from_str::<Partial>(doc)?; | ||
assert_eq!(p.n, 10); | ||
let Document::Mapping(m) = p.doc else { | ||
panic!("Expecting Document::Mapping"); | ||
}; | ||
let (k, v) = m[0].as_kv()?; | ||
assert_eq!(k.as_str()?, "key"); | ||
assert_eq!(v.as_str()?, "value"); | ||
let (k, v) = m[1].as_kv()?; | ||
assert_eq!(k.as_str()?, "i"); | ||
assert_eq!(u32::try_from(v)?, 5); | ||
let (k, v) = m[2].as_kv()?; | ||
assert_eq!(k.as_str()?, "j"); | ||
assert_eq!(u32::try_from(v)?, 10); | ||
Ok(()) | ||
} | ||
|
||
#[test] | ||
fn test_partial_deserialize_error() -> Result<()> { | ||
let p = serde_json::from_str::<Partial>(r#"{"n":5, "doc": []}"#); | ||
assert!(p.is_err()); | ||
assert_eq!(p.unwrap_err().to_string(), | ||
"Deserializing document nodes is only supported with serde_annotate::Deserializer at line 1 column 15"); | ||
Ok(()) | ||
} |