From 6bbafa448922791d54ee253a7a725d4033071c3c Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 5 Sep 2019 15:38:54 +0200 Subject: Suppport deserialization of Spanned<> at the top level (#328) --- src/de.rs | 47 +++++++++++++++++++++++++++++++++++++++++---- test-suite/tests/spanned.rs | 42 +++++++++++++++++++++++++++++++--------- 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( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + 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, end: Option, - value: Option>, + value: Option, } -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(&mut self, seed: K) -> Result, 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, } - fn good<'de, T>(s: &'de str, expected: &str) + #[derive(Deserialize)] + struct BareFoo { + foo: T, + } + + fn good<'de, T>(s: &'de str, expected: &str, end: Option) where - T: serde::Deserialize<'de>, + T: serde::Deserialize<'de> + Debug + PartialEq, { let foo: Foo = 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> = 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::("foo = \"foo\"", "\"foo\""); - good::("foo = 42", "42"); + good::("foo = \"foo\"", "\"foo\"", None); + good::("foo = 42", "42", None); // leading plus - good::("foo = +42", "+42"); + good::("foo = +42", "+42", None); // table good::>( "foo = {\"foo\" = 42, \"bar\" = 42}", "{\"foo\" = 42, \"bar\" = 42}", + None, ); // array - good::>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]"); + good::>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]", None); // datetime - good::("foo = \"1997-09-09T09:09:09Z\"", "\"1997-09-09T09:09:09Z\""); + good::( + "foo = \"1997-09-09T09:09:09Z\"", + "\"1997-09-09T09:09:09Z\"", + None, + ); for expected in good_datetimes() { let s = format!("foo = {}", expected); - good::(&s, expected); + good::(&s, expected, None); } + // ending at something other than the absolute end + good::("foo = 42\nnoise = true", "42", Some(8)); } -- cgit v1.2.3