(input_item: TokenStream)
| 4 | use syn::{Attribute, Data, DeriveInput, Field, Fields, ItemEnum, MetaList}; |
| 5 | |
| 6 | pub fn derive_discriminant_impl(input_item: TokenStream) -> syn::Result<TokenStream> { |
| 7 | let input = syn::parse2::<DeriveInput>(input_item).unwrap(); |
| 8 | |
| 9 | let mut data = match input.data { |
| 10 | Data::Enum(data) => data, |
| 11 | _ => return Err(syn::Error::new(Span::call_site(), "Tried to derive a discriminant for non-enum")), |
| 12 | }; |
| 13 | |
| 14 | let mut is_sub_discriminant = vec![]; |
| 15 | let mut attr_errs = vec![]; |
| 16 | |
| 17 | for var in &mut data.variants { |
| 18 | if var.attrs.iter().any(|a| a.path().is_ident("sub_discriminant")) { |
| 19 | match var.fields.len() { |
| 20 | 1 => { |
| 21 | let Field { ty, .. } = var.fields.iter_mut().next().unwrap(); |
| 22 | *ty = syn::parse_quote! { |
| 23 | <#ty as ToDiscriminant>::Discriminant |
| 24 | }; |
| 25 | is_sub_discriminant.push(true); |
| 26 | } |
| 27 | n => unimplemented!("#[sub_discriminant] on variants with {n} fields is not supported (for now)"), |
| 28 | } |
| 29 | } else { |
| 30 | var.fields = Fields::Unit; |
| 31 | is_sub_discriminant.push(false); |
| 32 | } |
| 33 | let mut retain = vec![]; |
| 34 | for (i, a) in var.attrs.iter_mut().enumerate() { |
| 35 | if a.path().is_ident("discriminant_attr") { |
| 36 | match a.meta.require_list() { |
| 37 | Ok(MetaList { tokens, .. }) => { |
| 38 | let attr: Attribute = syn::parse_quote! { |
| 39 | #[#tokens] |
| 40 | }; |
| 41 | *a = attr; |
| 42 | retain.push(i); |
| 43 | } |
| 44 | Err(e) => { |
| 45 | attr_errs.push(syn::Error::new(a.span(), e)); |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | } |
| 50 | var.attrs = var.attrs.iter().enumerate().filter(|(i, _)| retain.contains(i)).map(|(_, x)| x.clone()).collect(); |
| 51 | } |
| 52 | |
| 53 | let attrs = input |
| 54 | .attrs |
| 55 | .iter() |
| 56 | .cloned() |
| 57 | .filter_map(|a| { |
| 58 | let a_span = a.span(); |
| 59 | a.path() |
| 60 | .is_ident("discriminant_attr") |
| 61 | .then(|| match a.meta.require_list() { |
| 62 | Ok(MetaList { tokens, .. }) => { |
| 63 | let attr: Attribute = syn::parse_quote! { |
no test coverage detected