use deser::State;
use deser::de::{DeserializeDriver, DeserializeOwned, Slot, default_atom};
use deser::ext::{ExtValue, Extension};
use deser::ser::{Emit, SerializeDriver};
use deser::{Atom, Deserialize, Error, ErrorKind, Event, Serialize};
fn without_len(event: deser::Event<'static>) -> deser::Event<'static> {
match event {
deser::Event::MapStart(shape) => {
deser::Event::MapStart(deser::ContainerShape::with_order(shape.order()))
}
deser::Event::SeqStart(shape) => {
deser::Event::SeqStart(deser::ContainerShape::with_order(shape.order()))
}
event => event,
}
}
fn capture_events<T: Serialize + ?Sized>(s: &T) -> Vec<Event<'static>> {
let mut events = Vec::new();
let mut driver = SerializeDriver::new(&s);
while let Some((event, _, _)) = driver.next().unwrap() {
events.push(without_len(event.to_static()));
}
events
}
fn deserialize<T: DeserializeOwned>(events: Vec<Event<'_>>) -> Result<T, Error> {
let mut out = None;
{
let mut driver = DeserializeDriver::new(&mut out);
for event in events {
driver.emit(event)?;
}
}
Ok(out.unwrap())
}
#[derive(Debug, Clone, PartialEq)]
struct Timestamp(i64);
impl Extension for Timestamp {
fn name(&self) -> &str {
"timestamp"
}
fn fallback(&self) -> Atom<'_> {
Atom::I64(self.0)
}
}
impl Serialize for Timestamp {
fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
Ok(Emit::Atom(Atom::Ext(ExtValue::borrowed(value))))
}
}
impl<'de> Deserialize<'de> for Timestamp {
fn deserialize_atom(slot: &mut Slot<Self>, atom: Atom, state: &mut State) -> Result<(), Error> {
match atom {
Atom::Ext(ref ext) if ext.is::<Timestamp>() => {
**slot = ext.downcast_ref::<Timestamp>().cloned();
Ok(())
}
Atom::I64(value) => {
slot.set(Timestamp(value));
Ok(())
}
other => default_atom(slot, other, state),
}
}
}
#[test]
fn test_custom_extension_roundtrip() {
let events = capture_events(&vec![Timestamp(42)]);
assert_eq!(
events,
vec![
Event::seq_start(),
Event::Atom(Atom::Ext(ExtValue::owned(Timestamp(42)))),
Event::SeqEnd,
]
);
assert_eq!(
deserialize::<Vec<Timestamp>>(events).unwrap(),
vec![Timestamp(42)]
);
}
#[test]
fn test_unknown_extension_uses_fallback() {
let events = capture_events(&Timestamp(42));
assert_eq!(deserialize::<i64>(events.clone()).unwrap(), 42);
assert_eq!(
deserialize::<Option<u32>>(events.clone()).unwrap(),
Some(42)
);
let err = deserialize::<String>(events).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidType);
}
#[test]
fn test_wide_integers() {
assert_eq!(
capture_events(&u128::MAX),
vec![Event::Atom(Atom::Ext(ExtValue::owned(u128::MAX)))]
);
assert_eq!(
capture_events(&i128::MIN),
vec![Event::Atom(Atom::Ext(ExtValue::owned(i128::MIN)))]
);
assert_eq!(
deserialize::<u128>(vec![u128::MAX.into()]).unwrap(),
u128::MAX
);
assert_eq!(
deserialize::<i128>(vec![i128::MIN.into()]).unwrap(),
i128::MIN
);
assert_eq!(deserialize::<u128>(vec![42u64.into()]).unwrap(), 42);
assert_eq!(deserialize::<i128>(vec![(-42i64).into()]).unwrap(), -42);
assert_eq!(deserialize::<u8>(vec![255u128.into()]).unwrap(), 255);
assert_eq!(deserialize::<i64>(vec![(-1i128).into()]).unwrap(), -1);
assert_eq!(
deserialize::<u8>(vec![256u128.into()]).unwrap_err().kind(),
ErrorKind::OutOfRange
);
assert_eq!(
deserialize::<f64>(vec![(1u128 << 100).into()]).unwrap(),
(1u128 << 100) as f64
);
}
#[test]
fn test_integer_range_checks() {
assert_eq!(
deserialize::<i64>(vec![u64::MAX.into()])
.unwrap_err()
.kind(),
ErrorKind::OutOfRange
);
assert_eq!(
deserialize::<u64>(vec![(-1i64).into()]).unwrap_err().kind(),
ErrorKind::OutOfRange
);
assert_eq!(
deserialize::<u8>(vec![(-1i64).into()]).unwrap_err().kind(),
ErrorKind::OutOfRange
);
assert_eq!(deserialize::<i8>(vec![(-128i64).into()]).unwrap(), -128);
}
#[derive(Debug, Clone, PartialEq)]
struct AnnotatedNull(&'static str);
impl Extension for AnnotatedNull {
fn name(&self) -> &str {
"annotated null"
}
fn fallback(&self) -> Atom<'_> {
Atom::Null
}
}
#[test]
fn test_optional_null_extension() {
let value = AnnotatedNull("missing");
let null = || Event::Atom(Atom::Ext(ExtValue::borrowed(&value)));
assert_eq!(deserialize::<Option<u32>>(vec![null()]).unwrap(), None);
assert_eq!(
deserialize::<Vec<Option<String>>>(vec![
Event::seq_start(),
null(),
"x".into(),
Event::SeqEnd
])
.unwrap(),
vec![None, Some("x".to_string())]
);
assert!(deserialize::<u32>(vec![null()]).is_err());
}
mod borrowed {
use std::borrow::Cow;
use deser::Atom;
use deser::ext::BorrowedExtension;
#[derive(Debug, Clone, PartialEq)]
pub struct Literal<'a> {
pub text: Cow<'a, str>,
pub value: f64,
}
impl BorrowedExtension for Literal<'static> {
type Value<'a> = Literal<'a>;
fn name<'v>(_value: &'v Literal<'_>) -> &'v str {
"literal"
}
fn fallback<'v>(value: &'v Literal<'_>) -> Atom<'v> {
Atom::F64(value.value)
}
fn to_static(value: &Literal<'_>) -> Literal<'static> {
Literal {
text: Cow::Owned(value.text.to_string()),
value: value.value,
}
}
fn shorten<'s, 'l: 's>(value: &'s Literal<'l>) -> &'s Literal<'s> {
value
}
}
}
fn shorten<'long: 'short, 'short>(ext: ExtValue<'long>) -> ExtValue<'short> {
ext
}
#[test]
fn test_borrowed_extension() {
use borrowed::Literal;
use std::borrow::Cow;
let input = String::from("1.50");
let detached = {
let literal = Literal {
text: Cow::Borrowed(&input),
value: 1.5,
};
let ext = ExtValue::borrowed_value::<Literal>(&literal);
assert!(ext.is::<Literal>());
assert!(!ext.is::<u128>());
assert_eq!(ext.name(), "literal");
assert_eq!(ext.fallback(), Atom::F64(1.5));
assert_eq!(ext.downcast_value_ref::<Literal>().unwrap().text, "1.50");
assert!(ext.downcast_ref::<u128>().is_none());
assert_eq!(format!("{:?}", ext), format!("{:?}", literal));
let ext = shorten(ext);
let cloned = ext.clone();
assert_eq!(cloned, ext);
assert_eq!(ext.as_borrowed(), ext);
ext.to_static()
};
drop(input);
assert_eq!(
detached.downcast_value_ref::<Literal>().unwrap().text,
"1.50"
);
let input = String::from("2.5");
let owned = ExtValue::owned_value::<Literal>(Literal {
text: Cow::Borrowed(&input),
value: 2.5,
});
assert_eq!(owned.clone(), owned);
assert_ne!(owned, detached);
assert_ne!(owned, ExtValue::owned(42u128));
let other = String::from("2.5");
assert_eq!(
owned,
ExtValue::owned_value::<Literal>(Literal {
text: Cow::Borrowed(&other),
value: 2.5,
})
);
let atom = Atom::Ext(owned.clone());
let value: f64 = {
let mut out = None;
{
let mut driver = DeserializeDriver::new(&mut out);
driver.emit(atom).unwrap();
}
out.unwrap()
};
assert_eq!(value, 2.5);
}