Suppport deserialization of Spanned<> at the top level (#328)

This commit is contained in:
est31 2019-09-05 15:38:54 +02:00 committed by Alex Crichton
parent 57aea7dfad
commit 5fef3914cf
2 changed files with 76 additions and 13 deletions

View file

@ -8,6 +8,7 @@ use std::borrow::Cow;
use std::error; use std::error;
use std::f64; use std::f64;
use std::fmt; use std::fmt;
use std::marker::PhantomData;
use std::mem::discriminant; use std::mem::discriminant;
use std::str; use std::str;
use std::vec; use std::vec;
@ -285,9 +286,34 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
} }
} }
fn deserialize_struct<V>(
self,
name: &'static str,
fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Error>
where
V: de::Visitor<'de>,
{
if name == spanned::NAME && fields == [spanned::START, spanned::END, spanned::VALUE] {
let start = 0;
let end = self.input.len();
let res = visitor.visit_map(SpannedDeserializer {
phantom_data: PhantomData,
start: Some(start),
value: Some(self),
end: Some(end),
});
return res;
}
self.deserialize_any(visitor)
}
serde::forward_to_deserialize_any! { serde::forward_to_deserialize_any! {
bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
bytes byte_buf map struct unit newtype_struct bytes byte_buf map unit newtype_struct
ignored_any unit_struct tuple_struct tuple option identifier ignored_any unit_struct tuple_struct tuple option identifier
} }
} }
@ -664,6 +690,7 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
let end = self.value.end; let end = self.value.end;
return visitor.visit_map(SpannedDeserializer { return visitor.visit_map(SpannedDeserializer {
phantom_data: PhantomData,
start: Some(start), start: Some(start),
value: Some(self.value), value: Some(self.value),
end: Some(end), end: Some(end),
@ -741,6 +768,14 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
} }
} }
impl<'de, 'b> de::IntoDeserializer<'de, Error> for &'b mut Deserializer<'de> {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> { impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> {
type Deserializer = ValueDeserializer<'de>; type Deserializer = ValueDeserializer<'de>;
@ -749,13 +784,17 @@ impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> {
} }
} }
struct SpannedDeserializer<'a> { struct SpannedDeserializer<'de, T: de::IntoDeserializer<'de, Error>> {
phantom_data: PhantomData<&'de ()>,
start: Option<usize>, start: Option<usize>,
end: Option<usize>, end: Option<usize>,
value: Option<Value<'a>>, value: Option<T>,
} }
impl<'de> de::MapAccess<'de> for SpannedDeserializer<'de> { impl<'de, T> de::MapAccess<'de> for SpannedDeserializer<'de, T>
where
T: de::IntoDeserializer<'de, Error>,
{
type Error = Error; type Error = Error;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>

View file

@ -4,6 +4,7 @@ extern crate toml;
extern crate serde_derive; extern crate serde_derive;
use std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug;
use toml::value::Datetime; use toml::value::Datetime;
use toml::Spanned; use toml::Spanned;
@ -31,33 +32,56 @@ fn test_spanned_field() {
foo: Spanned<T>, foo: Spanned<T>,
} }
fn good<'de, T>(s: &'de str, expected: &str) #[derive(Deserialize)]
struct BareFoo<T> {
foo: T,
}
fn good<'de, T>(s: &'de str, expected: &str, end: Option<usize>)
where where
T: serde::Deserialize<'de>, T: serde::Deserialize<'de> + Debug + PartialEq,
{ {
let foo: Foo<T> = toml::from_str(s).unwrap(); let foo: Foo<T> = toml::from_str(s).unwrap();
assert_eq!(6, foo.foo.start()); assert_eq!(6, foo.foo.start());
assert_eq!(s.len(), foo.foo.end()); if let Some(end) = end {
assert_eq!(end, foo.foo.end());
} else {
assert_eq!(s.len(), foo.foo.end());
}
assert_eq!(expected, &s[foo.foo.start()..foo.foo.end()]); assert_eq!(expected, &s[foo.foo.start()..foo.foo.end()]);
// Test for Spanned<> at the top level
let foo_outer: Spanned<BareFoo<T>> = toml::from_str(s).unwrap();
assert_eq!(0, foo_outer.start());
assert_eq!(s.len(), foo_outer.end());
assert_eq!(foo.foo.into_inner(), foo_outer.into_inner().foo);
} }
good::<String>("foo = \"foo\"", "\"foo\""); good::<String>("foo = \"foo\"", "\"foo\"", None);
good::<u32>("foo = 42", "42"); good::<u32>("foo = 42", "42", None);
// leading plus // leading plus
good::<u32>("foo = +42", "+42"); good::<u32>("foo = +42", "+42", None);
// table // table
good::<HashMap<String, u32>>( good::<HashMap<String, u32>>(
"foo = {\"foo\" = 42, \"bar\" = 42}", "foo = {\"foo\" = 42, \"bar\" = 42}",
"{\"foo\" = 42, \"bar\" = 42}", "{\"foo\" = 42, \"bar\" = 42}",
None,
); );
// array // array
good::<Vec<u32>>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]"); good::<Vec<u32>>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]", None);
// datetime // datetime
good::<String>("foo = \"1997-09-09T09:09:09Z\"", "\"1997-09-09T09:09:09Z\""); good::<String>(
"foo = \"1997-09-09T09:09:09Z\"",
"\"1997-09-09T09:09:09Z\"",
None,
);
for expected in good_datetimes() { for expected in good_datetimes() {
let s = format!("foo = {}", expected); let s = format!("foo = {}", expected);
good::<Datetime>(&s, expected); good::<Datetime>(&s, expected, None);
} }
// ending at something other than the absolute end
good::<u32>("foo = 42\nnoise = true", "42", Some(8));
} }