aboutsummaryrefslogtreecommitdiff
path: root/src/spanned.rs
diff options
context:
space:
mode:
authorJohn-John Tedro <udoprog@tedro.se>2018-05-07 03:47:09 +0200
committerJohn-John Tedro <udoprog@tedro.se>2018-05-07 04:28:00 +0200
commit6ff5c445f37083c785111c904426c94b7a01f4b4 (patch)
treec77129d6c74c34e9c043566142dc6ab26644090a /src/spanned.rs
parentfd87ce35d563ecdac1f909d4540328365a16661f (diff)
downloadmilf-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.rs136
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)
}