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 {
|
match self.value.e {
|
||||||
E::String(val) => visitor.visit_enum(val.into_deserializer()),
|
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> {
|
impl<'a> Deserializer<'a> {
|
||||||
/// Creates a new deserializer which will be deserializing the string
|
/// Creates a new deserializer which will be deserializing the string
|
||||||
|
@ -1510,6 +1594,21 @@ enum E<'a> {
|
||||||
DottedTable(Vec<(Cow<'a, str>, Value<'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> {
|
impl<'a> Value<'a> {
|
||||||
fn same_type(&self, other: &Value<'a>) -> bool {
|
fn same_type(&self, other: &Value<'a>) -> bool {
|
||||||
match (&self.e, &other.e) {
|
match (&self.e, &other.e) {
|
||||||
|
|
Loading…
Reference in a new issue