You can use the version suggested above internally and implement Serialize and Deserialize for your enum by delegating to the derived implementation of the internal types.
You can do a custom implementation of serialize and deserialize. The deserialize implementation was a little more complicated than I thought, but it does exactly what you wanted!
mod myenum_serde {
use super::MyEnum;
use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer};
impl Serialize for MyEnum {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use ser::SerializeSeq;
match self {
MyEnum::Foo => s.serialize_str("foo"),
MyEnum::Bar => s.serialize_str("bar"),
MyEnum::List(v) => {
let mut seq = s.serialize_seq(Some(v.len()))?;
for item in v {
seq.serialize_element(item)?;
}
seq.end()
}
}
}
}
struct MyEnumVisitor;
impl<'de> de::Visitor<'de> for MyEnumVisitor {
type Value = MyEnum;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, r#"Either, "foo", "bar", or a list of strings"#)
}
fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
match s {
"foo" => Ok(MyEnum::Foo),
"bar" => Ok(MyEnum::Bar),
_ => Err(de::Error::invalid_value(de::Unexpected::Str(s), &self)),
}
}
fn visit_seq<A: de::SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut v = if let Some(size) = seq.size_hint() {
Vec::with_capacity(size)
} else {
Vec::new()
};
while let Some(element) = seq.next_element()? {
v.push(element);
}
Ok(MyEnum::List(v))
}
}
impl<'de> Deserialize<'de> for MyEnum {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<MyEnum, D::Error> {
d.deserialize_any(MyEnumVisitor)
}
}
}
#[derive(Debug)]
enum MyEnum {
Foo,
Bar,
List(Vec<String>),
}
fn main() {
println!("Serialize");
println!("---------");
println!("{}", serde_json::to_string(&MyEnum::Foo).unwrap());
println!("{}", serde_json::to_string(&MyEnum::Bar).unwrap());
println!(
"{}",
serde_json::to_string(&MyEnum::List(vec![
"a".to_string(),
"b".to_string(),
"c".to_string()
]))
.unwrap()
);
println!();
println!("Deserialize");
println!("----------");
println!("{:?}", serde_json::from_str::<MyEnum>(r#""foo""#).unwrap());
println!("{:?}", serde_json::from_str::<MyEnum>(r#""bar""#).unwrap());
println!(
"{:?}",
serde_json::from_str::<MyEnum>(r#"["a", "b", "c"]"#).unwrap()
);
println!("Graceful failure: \"green\"");
println!("{:?}", serde_json::from_str::<MyEnum>(r#""green""#));
}
Serialize
---------
"foo"
"bar"
["a","b","c"]
Deserialize
----------
Foo
Bar
List(["a", "b", "c"])
Graceful failure: "green"
Err(Error("invalid value: string \"green\", expected Either, \"foo\", \"bar\", or a list of strings", line: 1, column: 7))