parent
f07ba88de4
commit
f5d14af5a6
40
examples/enum_external.rs
Normal file
40
examples/enum_external.rs
Normal file
|
@ -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);
|
||||
}
|
101
src/de.rs
101
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) {
|
||||
|
|
Loading…
Reference in a new issue