6

I'm trying to implement Serialize for an enum that includes struct variants. The serde.rs documentation indicates the following:

enum E { // Use three-step process: // 1. serialize_struct_variant // 2. serialize_field // 3. end Color { r: u8, g: u8, b: u8 }, // Use three-step process: // 1. serialize_tuple_variant // 2. serialize_field // 3. end Point2D(f64, f64), // Use serialize_newtype_variant. Inches(u64), // Use serialize_unit_variant. Instance, } 

With that in mind, I proceeded to implemention:

use serde::ser::{Serialize, SerializeStructVariant, Serializer}; use serde_derive::Deserialize; #[derive(Deserialize)] enum Variants { VariantA, VariantB { k: u32, p: f64 }, } impl Serialize for Variants { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { match *self { Variants::VariantA => serializer.serialize_unit_variant("Variants", 0, "VariantA"), Variants::VariantB { ref k, ref p } => { let mut state = serializer.serialize_struct_variant("Variants", 1, "VariantB", 2)?; state.serialize_field("k", k)?; state.serialize_field("p", p)?; state.end() } } } } fn main() { let x = Variants::VariantB { k: 5, p: 5.0 }; let toml_str = toml::to_string(&x).unwrap(); println!("{}", toml_str); } 

The code compiles, but when I run it it fails:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: UnsupportedType', src/libcore/result.rs:999:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace. 

I figured the issue must be in my use of the API, so I consulted the API documentation for StructVariant and it looks practically the same as my code. I'm sure I'm missing something, but I don't see it based on the docs and output.

4
  • What prevents you from deriving Serialize like most usages? Commented Aug 19, 2019 at 16:26
  • It fails with the same error "value: UnsupportedType". Presumably, my implementation is doing exactly the same that serde_derive would do? In which case, some advice on what the right thing to do would be would be greatly appreciated. Commented Aug 19, 2019 at 16:36
  • Perhaps you can edit your question to show what you'd like the generated TOML to be? Commented Aug 19, 2019 at 16:42
  • Actually, I guess I was trying to find out what the output was going to be myself. Commented Aug 19, 2019 at 16:45

2 Answers 2

6

Enabling external tagging for the enum enables Serde to serialize/deserialize it to TOML:

#[derive(Deserialize)] #[serde(tag = "type")] enum Variants { VariantA, VariantB { k: u32, p: f64 }, } toml::to_string(&Variants::VariantB { k: 42, p: 13.37 }) 

serializes to

type = VariantB k = 42 p = 13.37 

This works well in Vecs and HashMaps, too.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your answer, to be honest I don't even remember what I was using this for (asked about a year ago) but it's good to know it can be done!
5

The TOML format does not support enums with values:

use serde::Serialize; // 1.0.99 use toml; // 0.5.3 #[derive(Serialize)] enum A { B(i32), } fn main() { match toml::to_string(&A::B(42)) { Ok(s) => println!("{}", s), Err(e) => eprintln!("Error: {}", e), } } 
Error: unsupported Rust type 

It's unclear what you'd like your data structure to map to as TOML. Using JSON works just fine:

use serde::Serialize; // 1.0.99 use serde_json; // 1.0.40 #[derive(Serialize)] enum Variants { VariantA, VariantB { k: u32, p: f64 }, } fn main() { match serde_json::to_string(&Variants::VariantB { k: 42, p: 42.42 }) { Ok(s) => println!("{}", s), Err(e) => eprintln!("Error: {}", e), } } 
{"VariantB":{"k":42,"p":42.42}} 

1 Comment

It seems clear what the serialization should be: [VariantB] k: 42 p: 42.42

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.