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
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
use crate::helpers::*;

impl ::quote::ToTokens for crate::From {
    fn to_tokens(&self, tokens: &mut ::proc_macro2::TokenStream) {
        let orig_name = &self.orig_name;
        let ffi_name = &self.ffi_name;
        let receiver = &self.receiver;
        let init_expr = &self.init_expr;

        tokens.extend(::quote::quote! {
            impl From<#orig_name> for #ffi_name {
                fn from(#receiver: #orig_name) -> #ffi_name {
                    #init_expr
                }
            }
        });
    }
}

impl<'a> From<&'a crate::Data> for crate::From {
    fn from(data: &'a crate::Data) -> Self {
        let orig_name = data.ident.clone();
        let ffi_name = data.ident.clone().prefix("FFI");
        let receiver: ::syn::Expr = ::syn::parse_quote! { tmp };

        let init_expr = if data.opaque {
            ::syn::parse_quote! { #ffi_name(#receiver) }
        } else {
            match &data.data {
                ::darling::ast::Data::Enum(variants) => enum_init_expr(
                    &::syn::parse_quote! { #orig_name },
                    &::syn::parse_quote! { #ffi_name },
                    &receiver,
                    variants,
                ),
                ::darling::ast::Data::Struct(fields) => struct_init_expr(
                    &::syn::parse_quote! { #ffi_name },
                    Some(&receiver),
                    fields,
                ),
            }
        };

        Self{orig_name, ffi_name, receiver, init_expr}
    }
}

fn enum_init_expr(
    orig_name: &::syn::Path,
    ffi_name: &::syn::Path,
    receiver: &::syn::Expr,
    variants: &Vec<crate::Variant>,
) -> ::syn::Expr {
    let arms: Vec<::syn::Arm> = variants.iter().map(|v| {
        let variant_name = &v.ident;
        let orig_variant_fullpath: ::syn::Path = ::syn::parse_quote! { #orig_name::#variant_name };
        let ffi_variant_fullpath: ::syn::Path = ::syn::parse_quote! { #ffi_name::#variant_name };

        let init = struct_init_expr(&ffi_variant_fullpath, None, &v.fields);
        let destructuring: Vec<::syn::Ident> = v.fields.iter().enumerate().map(|(idx, field)| {
            field.ident.clone().unwrap_or(idx_to_name(idx as u32))
        }).collect();

        match v.fields.style {
            ::darling::ast::Style::Tuple => ::syn::parse_quote! {
                #orig_variant_fullpath(#(#destructuring),*) => #init
            },
            ::darling::ast::Style::Struct => ::syn::parse_quote! {
                #orig_variant_fullpath{#(#destructuring),*} => #init
            },
            ::darling::ast::Style::Unit => ::syn::parse_quote! {
                #orig_variant_fullpath => #ffi_variant_fullpath
            },
        }
    }).collect();

    ::syn::parse_quote! {
        match #receiver {
            #(#arms),*
        }
    }
}

fn struct_init_expr(
    ffi_name: &::syn::Path,
    receiver: Option<&::syn::Expr>,
    fields: &::darling::ast::Fields<crate::Field>,
) -> ::syn::Expr {
    let exprs = fields.iter().enumerate().map(|(idx, field)| {
        field.from(idx, receiver)
    });

    if fields.style == ::darling::ast::Style::Tuple {
        ::syn::parse_quote! { #ffi_name(#(#exprs),*) }
    } else {
        let field_inits: Vec<::syn::FieldValue> = fields.iter().zip(exprs).map(|(field, expr)| {
            let field_name = &field.ident.as_ref().unwrap();
            ::syn::parse_quote! { #field_name: #expr }
        }).collect();
        ::syn::parse_quote! { #ffi_name{#(#field_inits),*} }
    }
}