cglue-gen 0.2.0

FFI safe code generation for making plugins and C-compatible libraries
Documentation
use proc_macro2::TokenStream;

use std::collections::BTreeMap;

use super::func::WrappedType;
use super::generics::ParsedGenerics;

use quote::*;
use syn::*;

pub fn gen_forward(tr: ItemTrait, ext_path: Option<TokenStream>) -> TokenStream {
    let crate_path = crate::util::crate_path();

    let mut types = BTreeMap::new();

    types.insert(
        format_ident!("Self"),
        WrappedType {
            ty: parse2(quote!(Self)).unwrap(),
            ty_ret_tmp: None,
            ty_static: None,
            return_conv: None,
            lifetime_bound: None,
            lifetime_type_bound: None,
            other_bounds: None,
            other_bounds_simple: None,
            impl_return_conv: None,
            inject_ret_tmp: false,
            unbounded_hrtb: false,
        },
    );

    let mut wrapped_types = TokenStream::new();

    let (funcs, generics, _) = super::traits::parse_trait(
        &tr,
        &crate_path,
        false,
        |(ty_ident, _, _), _, _, _, _, _| {
            if let Some(ident) = ty_ident {
                wrapped_types.extend(quote!(type #ident = CGlueT::#ident;));
            }
        },
    );

    let ParsedGenerics {
        life_declare,
        life_use,
        gen_declare,
        gen_use,
        gen_where_bounds,
        ..
    } = &generics;

    let trait_name = &tr.ident;

    let mut impls = TokenStream::new();

    let mut need_mut = false;

    for func in funcs {
        let nm = func.forward_wrapped_trait_impl(&mut impls);
        need_mut = nm || need_mut;
    }

    let mut required_mutability = TokenStream::new();

    required_mutability.extend(quote!(::core::ops::Deref<Target = CGlueT>));

    if need_mut {
        required_mutability.extend(quote!( + ::core::ops::DerefMut))
    }

    let tr_impl = if ext_path.is_some() {
        quote!()
    } else {
        quote!(#tr)
    };

    let needs_send = tr.supertraits.iter().any(|s| {
        if let TypeParamBound::Trait(tr) = s {
            tr.path.get_ident().map(|i| i == "Send") == Some(true)
        } else {
            false
        }
    });

    let send_bound = if needs_send { quote!(+ Send) } else { quote!() };
    quote! {
        #tr_impl

        impl<#life_declare CGlueO: #required_mutability #send_bound, CGlueT, #gen_declare> #ext_path #trait_name<#life_use #gen_use> for #crate_path::forward::Fwd<CGlueO> where CGlueT: #ext_path #trait_name<#life_use #gen_use>, #gen_where_bounds {
            #wrapped_types
            #impls
        }
    }
}