darling icon indicating copy to clipboard operation
darling copied to clipboard

Syntax for expressing enums with mixed variants

Open LonerDan opened this issue 2 years ago • 9 comments

Let's say I have the following:

#[derive(Debug, FromField)]
#[darling(attributes(my_attribute))]
struct StructFieldReceiver {
    ident: Option<syn::Ident>,
    vis: syn::Visibility,
    ty: syn::Type,
    name: String,
    sql_type: SqlType,
}

#[derive(Debug, FromMeta)]
#[darling(rename_all = "lowercase")]
enum SqlType {
// omitted variants
    BigInt, Int, SmallInt, TinyInt, Bit,
    Float(Option<u8>),
    Decimal{
        p: Option<u8>,
        s: Option<u8>
    },
// omitted variants
}

I can use the variants without type with #[my_attribute(name = "name", sql_type = "int")], but I don't know the correct syntax for specifying the Float or Decimal variants. Could you please point me in the right direction?

LonerDan avatar Jul 27 '23 12:07 LonerDan

Try #[my_attribute(name = "name", sql_type(float = 3.5)]

TedDriggs avatar Jul 27 '23 15:07 TedDriggs

Thank you, that works. Is there a way to also allow using it without the value, so that it defaults to None? Neither sql_type(float), sql_type = float nor sql_type = "float" seem to accomplish that.

LonerDan avatar Jul 28 '23 12:07 LonerDan

I think for that you'll need to do a custom implementation of FromMeta, or use the #[darling(with = "...")] attribute on the field in question to override the parsing function.

TedDriggs avatar Aug 01 '23 21:08 TedDriggs

Could this be done in addition to the derived FromMeta implementation (i.e. only add implementation for those cases)?

LonerDan avatar Aug 03 '23 13:08 LonerDan

Sort of - you can create a private mirror of the enum that derives FromMeta and has a conversion into the public enum, and then have your custom impl of FromMeta on the public enum delegate to the derived impl for all cases except the ones that need special handling.

I’d be willing to look at a PR or issue for adding with = “…” support to variants, which would be another way to do this.

TedDriggs avatar Aug 03 '23 13:08 TedDriggs

Would it be possible or desired to add handling of this to the code generated for #[derive(FromMeta)]? Darling already handles correctly Option<..> fields (i.e. absence of attribute field means None), so it could behave similarly in enums.

LonerDan avatar Aug 03 '23 13:08 LonerDan

I don't think the way that darling handles absent fields would work for enum variants; that uses the FromMeta::from_none method on the field-type level, and we don't have a good way of expressing that for variant type.

I think the place that would need work would be here, where we'd want to check if all the fields of the variant were optional and then do something special. However, I'm not sure if that would compose well with newtype variants, and I think any solution we pursue here would need to do that.

TedDriggs avatar Aug 14 '23 14:08 TedDriggs

I looked at the way the variant parsing is done from string values, and we could alter the matching a bit for the variants which are newtype or struct by using the default value or trying the from_none fallback (in a very similar way it is done in the from_list implementation). Here is a proof of concept: LonerDan/darling@3e06e62e2c72e4b8b841f90f9e92b682cb4bee17

LonerDan avatar Aug 15 '23 08:08 LonerDan

I'd suggest trying this again, as a bunch of changes in enum variant handling just merged.

TedDriggs avatar Jan 29 '24 21:01 TedDriggs