1use proc_macro2::{Ident, Span, TokenStream};
15use quote::{quote, ToTokens};
16use syn;
17
18use darling::{ast, FromVariant, FromDeriveInput};
19
20#[derive(Debug, FromDeriveInput)]
22#[darling(attributes(wrap), supports(enum_any))]
23struct EnumReceiver {
24 ident: Ident,
25 data: ast::Data<VariantReceiver, ()>,
26 c_enum: String,
28}
29
30impl ToTokens for EnumReceiver {
31 fn to_tokens(&self, tokens: &mut TokenStream) {
32 let EnumReceiver {
33 ref ident,
34 ref data,
35 ref c_enum,
36 } = *self;
37
38 let join_c_name_and_variant = |name: &str, variant: &str| {
39 Ident::new(&format!("{}_{}", &name, variant), Span::call_site())
40 };
41
42 let c_name = Ident::new(c_enum, Span::call_site());
43 let rust_name = ident;
44
45 let variants = data
46 .as_ref()
47 .take_enum()
48 .expect("should never be a struct");
49
50 let as_arms = variants
51 .iter()
52 .map(|v| {
53 let c_joined = join_c_name_and_variant(&c_name.to_string(), &v.c_variant);
54 let v_ident = &v.ident;
55
56 quote! {
57 #rust_name::#v_ident => #c_joined,
58 }
59 })
60 .collect::<Vec<_>>();
61
62 let try_from_arms = variants
63 .into_iter()
64 .map(|v| {
65 let c_joined = join_c_name_and_variant(&c_name.to_string(), &v.c_variant);
66 let v_ident = &v.ident;
67
68 quote! {
69 #c_joined => Ok(#rust_name::#v_ident),
70 }
71 })
72 .collect::<Vec<_>>();
73
74 tokens.extend(quote! {
75 impl #rust_name {
76 pub fn as_c(&self) -> #c_name {
78 match *self {
79 #(#as_arms)*
80 }
81 }
82 }
83
84 impl ::std::convert::TryFrom<#c_name> for #rust_name {
85 type Error = NvmlError;
86
87 fn try_from(data: #c_name) -> Result<Self, Self::Error> {
88 match data {
89 #(#try_from_arms)*
90 _ => Err(NvmlError::UnexpectedVariant(data)),
91 }
92 }
93 }
94 });
95 }
96}
97
98#[derive(Debug, FromVariant)]
100#[darling(attributes(wrap))]
101struct VariantReceiver {
102 ident: Ident,
103 c_variant: String
105}
106
107#[proc_macro_derive(EnumWrapper, attributes(wrap))]
108pub fn wrapcenum_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
109 let ast = syn::parse(input).unwrap();
110 let receiver = EnumReceiver::from_derive_input(&ast).unwrap();
111
112 quote!(#receiver).into()
113}