abi_stable_derive_lib 0.6.2

Implementation detail of abi_stable.
Documentation
use super::*;

use syn::Ident;

use proc_macro2::Span;

use abi_stable_shared::mangled_root_module_loader_name;




#[doc(hidden)]
pub fn mangle_library_getter_attr(_attr: TokenStream1, item: TokenStream1) -> TokenStream1 {

    measure!({
        mangle_library_getter_inner(
            syn::parse::<ItemFn>(item).unwrap()
        ).into()
    })

}

#[cfg(test)]
fn mangle_library_getter_str(item: &str)->TokenStream2{
    mangle_library_getter_inner(
        syn::parse_str::<ItemFn>(item).unwrap()
    )
}


fn mangle_library_getter_inner(mut input:ItemFn)->TokenStream2{
    let vis=&input.vis;

    let unsafe_no_layout_constant_path=
        syn::parse_str::<syn::Path>("unsafe_no_layout_constant").unwrap();

    let mut found_unsafe_no_layout_constant=false;
    input.attrs.retain(|attr|{
        let is_it=attr.path==unsafe_no_layout_constant_path;
        found_unsafe_no_layout_constant=found_unsafe_no_layout_constant||is_it;
        !is_it
    });
    let assoc_constant=Ident::new(
        if found_unsafe_no_layout_constant { "CONSTANTS_NO_ABI_INFO" }else{ "CONSTANTS" },
        Span::call_site(),
    );

    let ret_ty=match &input.decl.output {
        syn::ReturnType::Default=>
            panic!("\n\nThe return type of this function can't be `()`\n\n"),
        syn::ReturnType::Type(_,ty)=>
            &**ty,
    };
    
    let original_fn_ident=&input.ident;

    let export_name=Ident::new(
        &mangled_root_module_loader_name(),
        Span::call_site(),
    );

    quote!(
        #input

        #[no_mangle]
        #vis static #export_name:abi_stable::library::LibHeader={
            use abi_stable::{
                library::{LibHeader as __LibHeader},
                StableAbi,
            };

            pub extern "C" fn _sabi_erased_module(
            )->&'static abi_stable::marker_type::ErasedObject {
                ::abi_stable::extern_fn_panic_handling!(
                    let ret:#ret_ty=#original_fn_ident();
                    let _=abi_stable::library::RootModule::load_module_with(||{
                        Ok::<_,()>(ret)
                    });
                    unsafe{
                        abi_stable::utils::transmute_reference(ret)
                    }
                )
            }

            type __ReturnTy=#ret_ty;
            type __ModuleTy=<__ReturnTy as std::ops::Deref>::Target;
            
            unsafe{
                __LibHeader::from_constructor::<__ModuleTy>(
                    abi_stable::utils::Constructor(_sabi_erased_module),
                    <__ModuleTy as abi_stable::library::RootModule>::#assoc_constant,
                )
            }
        };
    )
}



#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn test_output(){
        let list=vec![
            (
                r##"
                    pub fn hello()->RString{}
                "##,
                "RootModule>::CONSTANTS"
            ),
            (
                r##"
                    #[unsafe_no_layout_constant]
                    pub fn hello()->RString{}
                "##,
                "RootModule>::CONSTANTS_NO_ABI_INFO"
            ),
            (
                r##"
                    #[hello]
                    #[unsafe_no_layout_constant]
                    pub fn hello()->RString{}
                "##,
                "RootModule>::CONSTANTS_NO_ABI_INFO"
            ),
            (
                r##"
                    #[hello]
                    #[unsafe_no_layout_constant]
                    #[hello]
                    pub fn hello()->RString{}
                "##,
                "RootModule>::CONSTANTS_NO_ABI_INFO"
            ),
            (
                r##"
                    #[unsafe_no_layout_constant]
                    #[hello]
                    pub fn hello()->RString{}
                "##,
                "RootModule>::CONSTANTS_NO_ABI_INFO"
            ),
        ];

        for (item,expected_const) in list {
            let str_out=mangle_library_getter_str(item).to_string()
                .chars()
                .filter(|c|!c.is_whitespace())
                .collect::<String>();
            assert!(str_out.contains(expected_const));
        }
    }
}