diff options
author | John-John Tedro <udoprog@tedro.se> | 2018-05-07 03:47:09 +0200 |
---|---|---|
committer | John-John Tedro <udoprog@tedro.se> | 2018-05-07 04:28:00 +0200 |
commit | 6ff5c445f37083c785111c904426c94b7a01f4b4 (patch) | |
tree | c77129d6c74c34e9c043566142dc6ab26644090a /src/spanned.rs | |
parent | fd87ce35d563ecdac1f909d4540328365a16661f (diff) | |
download | milf-rs-6ff5c445f37083c785111c904426c94b7a01f4b4.tar.gz milf-rs-6ff5c445f37083c785111c904426c94b7a01f4b4.zip |
Use custom struct/field naming to deserialize spans
Diffstat (limited to 'src/spanned.rs')
-rw-r--r-- | src/spanned.rs | 136 |
1 files changed, 120 insertions, 16 deletions
diff --git a/src/spanned.rs b/src/spanned.rs index 04ec9b8..1673d66 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -6,43 +6,147 @@ //! use toml::spanned::Spanned; //! //! #[derive(Deserialize)] -//! struct Udoprog { +//! struct Value { //! s: Spanned<String>, //! } //! //! fn main() { -//! let t = "s = \"udoprog\"\n"; +//! let t = "s = \"value\"\n"; //! -//! let u: Udoprog = toml::from_str(t).unwrap(); +//! let u: Value = toml::from_str(t).unwrap(); //! //! assert_eq!(u.s.start, 4); -//! assert_eq!(u.s.end, 13); +//! assert_eq!(u.s.end, 11); //! } //! ``` -use serde::{Serialize, Serializer}; +use serde::{de, ser}; +use std::fmt; -// FIXME: use a more unique name like "toml::Spanned". #[doc(hidden)] -pub const NAME: &str = "Spanned"; +pub const NAME: &'static str = "$__toml_private_Spanned"; #[doc(hidden)] -pub const FIELDS: &[&str] = &["value", "start", "end"]; +pub const START: &'static str = "$__toml_private_start"; +#[doc(hidden)] +pub const END: &'static str = "$__toml_private_end"; +#[doc(hidden)] +pub const VALUE: &'static str = "$__toml_private_value"; + +macro_rules! key_deserialize { + ($ident:ident, $field:expr, $name:expr) => { + struct $ident; + + impl<'de> de::Deserialize<'de> for $ident { + fn deserialize<D>(deserializer: D) -> Result<$ident, D::Error> + where D: de::Deserializer<'de> + { + struct FieldVisitor; + + impl<'de> de::Visitor<'de> for FieldVisitor { + type Value = (); + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a valid spanned field") + } + + fn visit_str<E>(self, s: &str) -> Result<(), E> + where E: de::Error + { + if s == $field { + Ok(()) + } else { + Err(de::Error::custom( + concat!("expected spanned field `", $name, "`"))) + } + } + } + + deserializer.deserialize_identifier(FieldVisitor)?; + Ok($ident) + } + } + } +} -/// -#[derive(Deserialize, Debug)] + +/// A spanned value, indicating the range at which it is defined in the source. +#[derive(Debug)] pub struct Spanned<T> { - /// - pub value: T, - /// + /// The start range. pub start: usize, - /// + /// The end range (exclusive). pub end: usize, + /// The spanned value. + pub value: T, +} + +impl<'de, T> de::Deserialize<'de> for Spanned<T> + where T: de::Deserialize<'de> +{ + fn deserialize<D>(deserializer: D) -> Result<Spanned<T>, D::Error> + where D: de::Deserializer<'de> + { + struct SpannedVisitor<T>(::std::marker::PhantomData<T>); + + impl<'de, T> de::Visitor<'de> for SpannedVisitor<T> + where T: de::Deserialize<'de> + { + type Value = Spanned<T>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a TOML spanned") + } + + fn visit_map<V>(self, mut visitor: V) -> Result<Spanned<T>, V::Error> + where V: de::MapAccess<'de> + { + let start = visitor.next_key::<StartKey>()?; + + if start.is_none() { + return Err(de::Error::custom("spanned start key not found")) + } + + let start: usize = visitor.next_value()?; + + let end = visitor.next_key::<EndKey>()?; + + if end.is_none() { + return Err(de::Error::custom("spanned end key not found")) + } + + let end: usize = visitor.next_value()?; + + let value = visitor.next_key::<ValueKey>()?; + + if value.is_none() { + return Err(de::Error::custom("spanned value key not found")) + } + + let value: T = visitor.next_value()?; + + Ok(Spanned { + start: start, + end: end, + value: value + }) + } + } + + key_deserialize!(StartKey, START, "start"); + key_deserialize!(EndKey, END, "end"); + key_deserialize!(ValueKey, VALUE, "value"); + + let visitor = SpannedVisitor(::std::marker::PhantomData); + + static FIELDS: [&'static str; 3] = [START, END, VALUE]; + deserializer.deserialize_struct(NAME, &FIELDS, visitor) + } } -impl<T: Serialize> Serialize for Spanned<T> { +impl<T: ser::Serialize> ser::Serialize for Spanned<T> { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where - S: Serializer, + S: ser::Serializer, { self.value.serialize(serializer) } |