1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::helpers::*;

impl ::quote::ToTokens for crate::Data {
    fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
        let ffi_name = self.ident.clone().prefix("FFI");

        if self.opaque {
            self.opaque_to_tokens(ffi_name, tokens)
        } else {
            match &self.data {
                ::darling::ast::Data::Struct(fds) => self.struct_to_tokens(ffi_name, fds, tokens),
                ::darling::ast::Data::Enum(vars) => self.enum_to_tokens(ffi_name, vars, tokens),
            }
        }
    }
}

impl crate::Data {
    pub(crate) fn validate(self) -> Self {
        if let ::darling::ast::Data::Enum(_) = &self.data {
            if self.constructor.is_some() {
                panic!("in enums, please specifies constructors per-variant");
            }
        }
        self
    }

    fn opaque_to_tokens(&self, ffi_name: ::syn::Ident, tokens: &mut ::proc_macro2::TokenStream) {
        let orig_name = &self.ident;
        tokens.extend(::quote::quote! {
            pub struct #ffi_name(#orig_name);
        });
    }

    fn enum_to_tokens(
        &self,
        ffi_name: ::syn::Ident,
        variants: &Vec<crate::Variant>,
        tokens: &mut ::proc_macro2::TokenStream,
    ) {
        let variants: Vec<_> = variants.iter().map(|v| v.fold()).collect();
        tokens.extend(::quote::quote! {
            #[repr(u16)]
            pub enum #ffi_name {
                #(#variants),*
            }
        });
    }

    fn struct_to_tokens(
        &self,
        ffi_name: ::syn::Ident,
        fields: &::darling::ast::Fields<crate::Field>,
        tokens: &mut ::proc_macro2::TokenStream,
    ) {
        let ffi_fields: Vec<::syn::Field> = fields.iter().map(|f| f.fold()).collect();
        tokens.extend(match fields.style {
            ::darling::ast::Style::Tuple => ::quote::quote! {
                #[repr(C)]
                pub struct #ffi_name(#(#ffi_fields),*);
            },
            ::darling::ast::Style::Struct => ::quote::quote! {
                #[repr(C)]
                pub struct #ffi_name { #(#ffi_fields),* }
            },
            ::darling::ast::Style::Unit => ::quote::quote! {
                #[repr(C)]
                pub struct #ffi_name;
            },
        });
    }
}