diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d75399..4b47360 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## Unreleased +- Add `discriminant` magic field when deriving `FromVariant` [#105](https://github.com/TedDriggs/darling/pull/105) + ## v0.10.2 (October 30, 2019) - Bump syn dependency to 1.0.1 [#83](https://github.com/TedDriggs/darling/pull/83) diff --git a/core/src/codegen/from_variant_impl.rs b/core/src/codegen/from_variant_impl.rs index a5e5f27..7a5a43e 100644 --- a/core/src/codegen/from_variant_impl.rs +++ b/core/src/codegen/from_variant_impl.rs @@ -8,9 +8,28 @@ use util::PathList; pub struct FromVariantImpl<'a> { pub base: TraitImpl<'a>, + /// If set, the ident of the field into which the variant ident should be placed. + /// + /// This is one of `darling`'s "magic fields", which allow a type deriving a `darling` + /// trait to get fields from the input `syn` element added to the deriving struct + /// automatically. pub ident: Option<&'a Ident>, + /// If set, the ident of the field into which the transformed output of the input + /// variant's fields should be placed. + /// + /// This is one of `darling`'s "magic fields". pub fields: Option<&'a Ident>, + /// If set, the ident of the field into which the forwarded attributes of the input + /// variant should be placed. + /// + /// This is one of `darling`'s "magic fields". pub attrs: Option<&'a Ident>, + /// If set, the ident of the field into which the discriminant of the input variant + /// should be placed. The receiving field must be an `Option` as not all enums have + /// discriminants. + /// + /// This is one of `darling`'s "magic fields". + pub discriminant: Option<&'a Ident>, pub attr_names: &'a PathList, pub forward_attrs: Option<&'a ForwardAttrs>, pub from_ident: bool, @@ -25,6 +44,10 @@ impl<'a> ToTokens for FromVariantImpl<'a> { .ident .as_ref() .map(|i| quote!(#i: #input.ident.clone(),)); + let passed_discriminant = self + .discriminant + .as_ref() + .map(|i| quote!(#i: #input.discriminant.as_ref().map(|(_, expr)| expr.clone()),)); let passed_attrs = self.attrs.as_ref().map(|i| quote!(#i: __fwd_attrs,)); let passed_fields = self .fields @@ -68,6 +91,7 @@ impl<'a> ToTokens for FromVariantImpl<'a> { ::darling::export::Ok(Self { #passed_ident + #passed_discriminant #passed_attrs #passed_fields #inits diff --git a/core/src/options/from_variant.rs b/core/src/options/from_variant.rs index c5ffe5d..361f479 100644 --- a/core/src/options/from_variant.rs +++ b/core/src/options/from_variant.rs @@ -9,6 +9,9 @@ use {FromMeta, Result}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct FromVariantOptions { pub base: OuterFrom, + /// The field on the deriving struct into which the discriminant expression + /// should be placed by the derived `FromVariant` impl. + pub discriminant: Option, pub fields: Option, pub supports: Option, } @@ -17,6 +20,7 @@ impl FromVariantOptions { pub fn new(di: &DeriveInput) -> Result { (FromVariantOptions { base: OuterFrom::start(di), + discriminant: Default::default(), fields: Default::default(), supports: Default::default(), }) @@ -30,6 +34,7 @@ impl<'a> From<&'a FromVariantOptions> for FromVariantImpl<'a> { FromVariantImpl { base: (&v.base.container).into(), ident: v.base.ident.as_ref(), + discriminant: v.discriminant.as_ref(), fields: v.fields.as_ref(), attrs: v.base.attrs.as_ref(), attr_names: &v.base.attr_names, @@ -60,6 +65,10 @@ impl ParseData for FromVariantOptions { .as_ref() .map(|v| v.as_str()) { + Some("discriminant") => { + self.discriminant = field.ident.clone(); + Ok(()) + } Some("fields") => { self.fields = field.ident.clone(); Ok(()) diff --git a/src/lib.rs b/src/lib.rs index a0668cd..93cdd58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,13 @@ //! |`bounds`|`Vec`|The bounds applied to the type param| //! |`default`|`Option`|The default type of the parameter, if one exists| //! |`attrs`|`Vec`|The forwarded attributes from the passed in type param. These are controlled using the `forward_attrs` attribute.| +//! +//! ### `FromVariant` +//! |---|---|---| +//! |`ident`|`syn::Ident`|The identifier of the passed-in variant| +//! |`discriminant`|`Option`|For a variant such as `Example = 2`, the `2`| +//! |`fields`|`Option>`|The fields associated with the variant| +//! |`attrs`|`Vec`|The forwarded attributes from the passed in variant. These are controlled using the `forward_attrs` attribute.| extern crate core; extern crate darling_core; diff --git a/tests/from_variant.rs b/tests/from_variant.rs index be216cb..a226576 100644 --- a/tests/from_variant.rs +++ b/tests/from_variant.rs @@ -2,6 +2,9 @@ extern crate darling; extern crate syn; +use darling::FromVariant; +use syn::{spanned::Spanned, Expr, ExprLit, LitInt}; + #[derive(FromVariant)] #[darling(from_ident, attributes(hello))] #[allow(dead_code)] @@ -9,6 +12,7 @@ pub struct Lorem { ident: syn::Ident, into: Option, skip: Option, + discriminant: Option, fields: darling::ast::Fields, } @@ -18,10 +22,40 @@ impl From for Lorem { ident, into: Default::default(), skip: Default::default(), + discriminant: None, fields: darling::ast::Style::Unit.into(), } } } #[test] -fn expansion() {} +fn discriminant() { + let input: syn::DeriveInput = syn::parse_str( + r#" + pub enum Test { + Works = 1, + AlsoWorks = 2, + } + "#, + ) + .unwrap(); + + let span = input.span(); + if let syn::Data::Enum(enm) = input.data { + let lorem = Lorem::from_variant( + enm.variants + .first() + .expect("Hardcoded input has one variant"), + ) + .expect("FromVariant can process the discriminant"); + assert_eq!( + lorem.discriminant, + Some(Expr::Lit(ExprLit { + attrs: vec![], + lit: LitInt::new("1", span).into(), + })) + ) + } else { + panic!("Data should be enum"); + } +}