lerouxrgd / rsgen-avro

Command line and library for generating Rust types from Avro schemas
MIT License
37 stars 29 forks source link

Add variant_access_derive to the enums generated from union types #13

Closed batconjurer closed 3 years ago

batconjurer commented 3 years ago

Recently, this crate added support for Avro union types (hooray!), but was forced to create enums with computer generated names and computer generated field names and it is not clear how to avoid that. There are unfortunately a few downsides to that.

[serde(default)]

[derive(Debug, PartialEq, Clone, serde::Deserialize, serde::Serialize)]

pub struct Contact { pub extra: ::std::collections::HashMap<String, Option>, }

impl Default for Contact { fn default() -> Contact { Contact { extra: ::std::collections::HashMap::new(), } } }

And a side-by-side comparison of using / not using `variant_access_traits` 
```rust
mod contact;
use variant_access_traits::*;
use crate::contact::*;

fn main() {

    //without variant_access
    let mut contact = Contact::default();
    contact.extra.insert(String::from("John"),
                         Some(UnionStringLongDoubleBoolean::String(String::from("Colleagues"))));
    if let Some(value) = contact.extra.get_mut("John").unwrap() {
        if let UnionStringLongDoubleBoolean::String(inner) = value {
            println!("{}", inner);
            *inner = String::from("Ex-colleague");
            println!("{:?}", value);
        } else {
            println!("Well, that was unexpected");
        }
    }

    // with variant_access
    let mut contact = Contact::default();
    contact.extra.insert(String::from("John"),
                         Some(create_variant_from(String::from("Colleague"))));
    if let Some(value) = contact.extra.get_mut("John").unwrap() {
        if let Ok(true) = value.contains_variant::<String>() {
            let inner: &mut String = value.get_variant_mut().expect("Uh oh");
            println!("{}", inner);
            *inner = String::from("Ex-colleague");
            println!("{:?}", value)
        } else {
            println!("Well, that was unexpected!");
        }
    }
}
lerouxrgd commented 3 years ago

Thank you for this feature.

However I'd see the implementation more like this:

Also, do you need to add use variant_access_traits::*; in the generated file ? I think it is only necessary in your main (or where you use the actual generated code) isn't it ?

Besides, there is no need for a cargo feature.

Let me know if you want to give the it a try with the above plan, otherwise I should be able to do it this week.

batconjurer commented 3 years ago

I have made the above changes. Please double check the docopt string to make sure it is clear. I also needed to make a quick patch to the variant_access crate so that the use variant_access_traits::*; line was not necessary in the generated code. So this means that anyone using this feature should use variant_access version 0.3.1 or later.

lerouxrgd commented 3 years ago

Perfect, thank you ! This has been released in 0.9.1.