aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAzriel Hoh <azriel91@gmail.com>2018-10-10 08:59:46 +1300
committerAzriel Hoh <azriel91@gmail.com>2018-11-10 11:06:34 +1300
commiteff2ed3b51fecf4e6799690c09ce35daa6e51280 (patch)
treebde557a12a1ed32e0870a3f70a93581d0832f3ee
parent3aec5a918a6cb39fa32e8a56725a3c2fc0ed6bc2 (diff)
downloadmilf-rs-eff2ed3b51fecf4e6799690c09ce35daa6e51280.tar.gz
milf-rs-eff2ed3b51fecf4e6799690c09ce35daa6e51280.zip
Implement deserialization for unit and struct variants.
Issue #225
-rw-r--r--examples/enum_external.rs40
-rw-r--r--src/de.rs101
2 files changed, 140 insertions, 1 deletions
diff --git a/examples/enum_external.rs b/examples/enum_external.rs
new file mode 100644
index 0000000..1feff77
--- /dev/null
+++ b/examples/enum_external.rs
@@ -0,0 +1,40 @@
+//! An example showing off the usage of `Deserialize` to automatically decode
+//! TOML into a Rust `struct`, with enums.
+
+#![deny(warnings)]
+
+extern crate toml;
+#[macro_use]
+extern crate serde_derive;
+
+/// This is what we're going to decode into.
+#[derive(Debug, Deserialize)]
+struct Config {
+ plain: MyEnum,
+ // tuple: MyEnum,
+ #[serde(rename = "struct")]
+ structv: MyEnum,
+ my_enum: Vec<MyEnum>,
+}
+
+#[derive(Debug, Deserialize)]
+enum MyEnum {
+ Plain,
+ Tuple(i64, bool),
+ Struct { value: i64 },
+}
+
+fn main() {
+ let toml_str = r#"
+ plain = "Plain"
+ # tuple = { 0 = 123, 1 = true }
+ struct = { Struct = { value = 123 } }
+ my_enum = [
+ { Plain = {} },
+ # { Tuple = { 0 = 123, 1 = true } },
+ { Struct = { value = 123 } }
+ ]"#;
+
+ let decoded: Config = toml::from_str(toml_str).unwrap();
+ println!("{:#?}", decoded);
+}
diff --git a/src/de.rs b/src/de.rs
index 491ae47..5de4f6a 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -585,7 +585,27 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
{
match self.value.e {
E::String(val) => visitor.visit_enum(val.into_deserializer()),
- _ => Err(Error::from_kind(ErrorKind::ExpectedString))
+ E::InlineTable(values) | E::DottedTable(values) => {
+ if values.len() != 1 {
+ Err(Error::from_kind(ErrorKind::Wanted {
+ expected: "exactly 1 element",
+ found: if values.is_empty() {
+ "zero elements"
+ } else {
+ "more than 1 element"
+ },
+ }))
+ } else {
+ visitor.visit_enum(InlineTableDeserializer {
+ values: values.into_iter(),
+ next_value: None,
+ })
+ }
+ }
+ e @ _ => Err(Error::from_kind(ErrorKind::Wanted {
+ expected: "string or table",
+ found: e.type_name(),
+ })),
}
}
@@ -724,6 +744,70 @@ impl<'de> de::MapAccess<'de> for InlineTableDeserializer<'de> {
}
}
+impl<'de> de::EnumAccess<'de> for InlineTableDeserializer<'de> {
+ type Error = Error;
+ type Variant = Self;
+
+ fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ let (key, value) = match self.values.next() {
+ Some(pair) => pair,
+ None => {
+ return Err(Error::from_kind(ErrorKind::Wanted {
+ expected: "table with exactly 1 entry",
+ found: "empty map",
+ }))
+ }
+ };
+ self.next_value = Some(value);
+
+ seed.deserialize(StrDeserializer::new(key))
+ .map(|val| (val, self))
+ }
+}
+
+impl<'de> de::VariantAccess<'de> for InlineTableDeserializer<'de> {
+ type Error = Error;
+
+ fn unit_variant(self) -> Result<(), Self::Error> {
+ // TODO: Error handling if there are entries
+ Ok(())
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
+ where
+ T: de::DeserializeSeed<'de>,
+ {
+ seed.deserialize(ValueDeserializer::new(
+ self.next_value.expect("Expected value"),
+ ))
+ }
+
+ fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ unimplemented!()
+ }
+
+ fn struct_variant<V>(
+ self,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ de::Deserializer::deserialize_struct(
+ ValueDeserializer::new(self.next_value.expect("Expected value")),
+ "", // TODO: this should be the variant name
+ fields,
+ visitor,
+ )
+ }
+}
impl<'a> Deserializer<'a> {
/// Creates a new deserializer which will be deserializing the string
@@ -1510,6 +1594,21 @@ enum E<'a> {
DottedTable(Vec<(Cow<'a, str>, Value<'a>)>),
}
+impl<'a> E<'a> {
+ fn type_name(&self) -> &'static str {
+ match *self {
+ E::String(..) => "string",
+ E::Integer(..) => "integer",
+ E::Float(..) => "float",
+ E::Boolean(..) => "boolean",
+ E::Datetime(..) => "datetime",
+ E::Array(..) => "array",
+ E::InlineTable(..) => "inline table",
+ E::DottedTable(..) => "dotted table",
+ }
+ }
+}
+
impl<'a> Value<'a> {
fn same_type(&self, other: &Value<'a>) -> bool {
match (&self.e, &other.e) {