Help implementing deserialize on a complex enum

Hello! I've tried searching around for help on this, but I'm not finding any resources.

I have an enum that looks something like this:

enum Foo {
   VariantOne {
       field_one: u64,
       field_two: u64,
   },
   VariantTwo {
      field_one: String,
    },
    VariantThree,
}

Each enum variant has different data. I'd like to be able to deserialize this in a custom way. For example, if I have a csv:

variant_name, field_one, field_two 
variant_one,   1,              1
variant_three
variant_two,   100

I'd like to be able to handle this with serde and Deserialize.

I've tried reading the documentation on the Visitor pattern, but it isn't clear to me. Should I be visiting a sequence and handling each part individually?

Yes, that would be a valid solution. And also a good one for the problem you have.

1 Like

I ended up sorting it out. For anybody who comes across this:


impl<'de> Deserialize<'de> for Foo {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct FooVisitor;

        impl<'de> Visitor<'de> for FooVisitor {
            type Value = Foo;
            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("enum Foo")
            }

            fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
            where
                V: SeqAccess<'de>,
            {
                let foo_type = FooType::from_str(
                    seq.next_element()?
                        .ok_or_else(|| de::Error::invalid_length(0, &self))?,
                );
                 match FooType {
                    FooType::VariantOne => {
                      let field_one: u64 = seq
                                .next_element()?
                                .ok_or_else(|| de::Error::invalid_length(1, &self))?;
                      let field_two: u64 = seq
                                .next_element()?
                                .ok_or_else(|| de::Error::invalid_length(2, &self))?;
                      return Ok(Foo::VariantOne { field_one, field_two })
                    },
                    FooType::VariantTwo => ...etc., omitted for brevity,
                }
            }
        }
        deserializer.deserialize_seq(TransactionVisitor)
    }
}

enum FooType {
  VariantOne,
  VariantTwo,
  VariantThree
}

impl FooType {
  fn from_str(raw: &str) -> Self {
    match raw {
     "variant_one" => FooType::VariantOne,
     ... etc., omitted for brevity
    }
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.