aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorest31 <est31@users.noreply.github.com>2019-09-05 15:38:54 +0200
committerAlex Crichton <alex@alexcrichton.com>2019-09-05 08:38:54 -0500
commit6bbafa448922791d54ee253a7a725d4033071c3c (patch)
tree60eab8d2d8b965f3f8154c48913429de47e2bb45
parentb2a427ee7df39d27e86348fbb3f4e79cf2074d41 (diff)
downloadmilf-rs-6bbafa448922791d54ee253a7a725d4033071c3c.tar.gz
milf-rs-6bbafa448922791d54ee253a7a725d4033071c3c.zip
Suppport deserialization of Spanned<> at the top level (#328)
-rw-r--r--src/de.rs47
-rw-r--r--test-suite/tests/spanned.rs42
2 files changed, 76 insertions, 13 deletions
diff --git a/src/de.rs b/src/de.rs
index e290b19..540600f 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -8,6 +8,7 @@ use std::borrow::Cow;
use std::error;
use std::f64;
use std::fmt;
+use std::marker::PhantomData;
use std::mem::discriminant;
use std::str;
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! {
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
}
}
@@ -664,6 +690,7 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
let end = self.value.end;
return visitor.visit_map(SpannedDeserializer {
+ phantom_data: PhantomData,
start: Some(start),
value: Some(self.value),
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> {
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>,
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;
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
diff --git a/test-suite/tests/spanned.rs b/test-suite/tests/spanned.rs
index 5f6d5a2..5130a72 100644
--- a/test-suite/tests/spanned.rs
+++ b/test-suite/tests/spanned.rs
@@ -4,6 +4,7 @@ extern crate toml;
extern crate serde_derive;
use std::collections::HashMap;
+use std::fmt::Debug;
use toml::value::Datetime;
use toml::Spanned;
@@ -31,33 +32,56 @@ fn test_spanned_field() {
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
- T: serde::Deserialize<'de>,
+ T: serde::Deserialize<'de> + Debug + PartialEq,
{
let foo: Foo<T> = toml::from_str(s).unwrap();
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()]);
+
+ // 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::<u32>("foo = 42", "42");
+ good::<String>("foo = \"foo\"", "\"foo\"", None);
+ good::<u32>("foo = 42", "42", None);
// leading plus
- good::<u32>("foo = +42", "+42");
+ good::<u32>("foo = +42", "+42", None);
// table
good::<HashMap<String, u32>>(
"foo = {\"foo\" = 42, \"bar\" = 42}",
"{\"foo\" = 42, \"bar\" = 42}",
+ None,
);
// 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
- 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() {
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));
}