Suppport deserialization of Spanned<> at the top level (#328)
This commit is contained in:
parent
57aea7dfad
commit
5fef3914cf
47
src/de.rs
47
src/de.rs
|
@ -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>
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue