pub fn expand_com_interface(
    attr_tokens: TokenStreamNightly,
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let itf =
        model::ComInterface::from_ast(&lib_name(), attr_tokens.into(), item_tokens.clone().into())?;
    let itf_path = &itf.path;
    let itf_name = itf.ident.to_string();
    let itf_ref = &itf.itf_ref;

    let mut itf_output = InterfaceOutput::default();
    for (ts, itf_variant) in &itf.variants {
        process_itf_variant(&itf, *ts, itf_variant, &mut output, &mut itf_output);
    }

    if itf.item_type == utils::InterfaceType::Trait {
        let mut impls = vec![];
        for (_, method) in itf_output.method_impls.iter() {
            let method_rust_ident = &method.info.name;
            let method_name = method_rust_ident.to_string();
            let mut impl_branches = vec![];
            for (ts, method_ts_impl) in method.impls.iter() {
                let ts_tokens = ts.as_typesystem_type(method.info.signature_span);
                let ts_name = format!("{:?}", ts);
                impl_branches.push(quote_spanned!(method.info.signature_span =>
                    if let Some( comptr ) = intercom::ComItf::ptr::<#ts_tokens>( self ) {
                        intercom::logging::trace(|l| l(module_path!(), format_args!(
                            "[{:p}, with {:p}] Calling {}::{}, type system: {}",
                            self, comptr.ptr, #itf_name, #method_name, #ts_name)));

                        #method_ts_impl
                    }
                ));
            }

            // Format the method arguments into tokens.
            let impl_args = method.info.args.iter().map(|ca| {
                let name = &ca.name;
                let ty = &ca.ty;
                quote_spanned!(ca.span => #name : #ty )
            });

            let unsafety = if method.info.is_unsafe {
                quote_spanned!(method.info.signature_span => unsafe)
            } else {
                quote!()
            };
            let self_arg = &method.info.rust_self_arg;
            let return_ty = &method.info.rust_return_ty;

            // Rust to COM implementation.
            impls.push(quote_spanned!(method.info.signature_span =>
                #unsafety fn #method_rust_ident(
                    #self_arg, #( #impl_args ),*
                ) -> #return_ty {

                    intercom::logging::trace(|l| l(module_path!(), format_args!(
                        "[{:p}] Calling {}::{}", self, #itf_name, #method_name)));

                    #[allow(unused_imports)]
                    use intercom::ErrorValue;

                    // Try the available type systems.
                    #( #impl_branches )*

                    // The ComItf invariant states it has at least one pointer
                    // available so we should never get here.
                    //
                    // Also since this is Rust-to-COM call we are allowed to
                    // panic here.
                    unreachable!();
                }
            ));
        }

        let unsafety = if itf.is_unsafe {
            quote_spanned!(itf.span => unsafe)
        } else {
            quote!()
        };
        output.push(quote_spanned!(itf.span =>
            #[allow(clippy::all)]
            #[allow(unused_braces)]
            #unsafety impl<I: intercom::attributes::ComInterface + #itf_path + ?Sized> #itf_path for intercom::ComItf<I> {
                #( #impls )*
            }
        ));
    }

    // Implement the ComInterface for the trait.
    let iid_arms = itf_output.iid_arms;
    let (deref_impl, deref_ret) = if itf.item_type == utils::InterfaceType::Trait {
        (
            quote_spanned!(itf.span => com_itf),
            quote_spanned!(itf.span => &( dyn #itf_path + 'static ) ),
        )
    } else {
        // Note this is _extremely_ dangerous.
        //
        // Essentially we are assuming here that every #itf_path pointer represents
        // a ComBox structure that we have created. This will fail the moment
        // the user code implements #itf_path interface on their own and passes
        // that back to us.
        //
        // There's no real way to get this to work and we might want to just remove
        // the possibility to do 'implicit' interfaces by just impling the struct.
        (
            quote_spanned!(itf.span =>
                let some_iunk : &intercom::ComItf<dyn intercom::interfaces::RawIUnknown> = com_itf.as_raw_iunknown();
                let iunknown_iid = intercom::IUnknown::iid(
                        intercom::type_system::TypeSystemName::Automation )
                            .expect( "IUnknown must have Automation IID" );
                let primary_iunk = some_iunk.query_interface( iunknown_iid )
                        .expect( "All types must implement IUnknown" );

                let combox : *mut intercom::ComBoxData< #itf_path > =
                        primary_iunk as *mut intercom::ComBoxData< #itf_path >;
                unsafe {

                    // We are already holding a reference to the 'self', which should
                    // keep this alive. We don't need to maintain a lifetime of the
                    // queried interface.
                    intercom::ComBoxData::release( combox );

                    // Deref.
                    use std::ops::Deref;
                    (*combox).deref()
                }
            ),
            quote_spanned!(itf.span => & #itf_path ),
        )
    };

    output.push(quote_spanned!(itf.span =>
        impl intercom::attributes::ComInterface for #itf_ref {

            type TSelf = #itf_ref;

            #[doc = "Returns the IID of the requested interface."]
            fn iid_ts<TS: intercom::type_system::TypeSystem>() -> &'static intercom::IID
                where Self: intercom::attributes::ComInterfaceVariant<TS>
            {
                <Self as intercom::attributes::ComInterfaceVariant<TS>>::iid()
            }

            fn iid(
                ts : intercom::type_system::TypeSystemName
            ) -> Option< &'static intercom::IID >
            {
                match ts {
                    #( #iid_arms ),*
                }
            }

            fn deref(
                com_itf : &intercom::ComItf<#itf_ref>
            ) -> #deref_ret {
                #deref_impl
            }
        }
    ));

    // Implement type info for the interface.
    output.push(quote_spanned!(itf.span =>

        impl intercom::type_system::ForeignType for #itf_ref {

            /// The name of the type.
            fn type_name() -> &'static str { stringify!( #itf_path )  }
        }

    ));

    // Create runtime type info.
    output.push(create_get_typeinfo_function(&itf));

    Ok(tokens_to_tokenstream(item_tokens, output))
}
/// Expands the `com_interface` attribute.
///
/// The attribute expansion results in the following items:
///
/// - Global IID for the interface.
/// - Virtual table struct definition for the interface.
/// - Implementation for the delegating methods when calling the COM interface
///   from Rust.
Expands the `com_interface` attribute.
The attribute expansion results in the following items.

Global IID for the interface.
Virtual table struct definition for the interface.
Implementation for the delegating methods when calling the COM interface
from Rust.
Expands the ` com_interface ` attribute . The attribute expansion results in the following items . Global IID for the interface . Virtual table struct definition for the interface . Implementation for the delegating methods when calling the COM interface from Rust .
pub fn expand_com_interface(
    attr_tokens: TokenStreamNightly,
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, model::ParseError>
{
    // Parse the attribute.
    let mut output = vec![];
    let itf =
        model::ComInterface::from_ast(&lib_name(), attr_tokens.into(), item_tokens.clone().into())?;
    let itf_path = &itf.path;
    let itf_name = itf.ident.to_string();
    let itf_ref = &itf.itf_ref;
    let mut itf_output = InterfaceOutput::default();
    for (ts, itf_variant) in &itf.variants {
        process_itf_variant(&itf, *ts, itf_variant, &mut output, &mut itf_output);
    }
    if itf.item_type == utils::InterfaceType::Trait {
        let mut impls = vec![];
        for (_, method) in itf_output.method_impls.iter() {
            let method_rust_ident = &method.info.name;
            let method_name = method_rust_ident.to_string();
            let mut impl_branches = vec![];
            for (ts, method_ts_impl) in method.impls.iter() {
                let ts_tokens = ts.as_typesystem_type(method.info.signature_span);
                let ts_name = format!("{:?}", ts);
                impl_branches.push(quote_spanned!(method.info.signature_span =>
                    if let Some( comptr ) = intercom::ComItf::ptr::<#ts_tokens>( self ) {
                        intercom::logging::trace(|l| l(module_path!(), format_args!(
                            "[{:p}, with {:p}] Calling {}::{}, type system: {}",
                            self, comptr.ptr, #itf_name, #method_name, #ts_name)));
                        #method_ts_impl
                    }
                ));
            }
            // Format the method arguments into tokens.
            let impl_args = method.info.args.iter().map(|ca| {
                let name = &ca.name;
                let ty = &ca.ty;
                quote_spanned!(ca.span => #name : #ty )
            });
            let unsafety = if method.info.is_unsafe {
                quote_spanned!(method.info.signature_span => unsafe)
            } else {
                quote!()
            };
            let self_arg = &method.info.rust_self_arg;
            let return_ty = &method.info.rust_return_ty;
            // Rust to COM implementation.
            impls.push(quote_spanned!(method.info.signature_span =>
                #unsafety fn #method_rust_ident(
                    #self_arg, #( #impl_args ),*
                ) -> #return_ty {
                    intercom::logging::trace(|l| l(module_path!(), format_args!(
                        "[{:p}] Calling {}::{}", self, #itf_name, #method_name)));
                    #[allow(unused_imports)]
                    use intercom::ErrorValue;
                    // Try the available type systems.
                    #( #impl_branches )*
                    // The ComItf invariant states it has at least one pointer
                    // available so we should never get here.
                    //
                    // Also since this is Rust-to-COM call we are allowed to
                    // panic here.
                    unreachable!();
                }
            ));
        }
        let unsafety = if itf.is_unsafe {
            quote_spanned!(itf.span => unsafe)
        } else {
            quote!()
        };
        output.push(quote_spanned!(itf.span =>
            #[allow(clippy::all)]
            #[allow(unused_braces)]
            #unsafety impl<I: intercom::attributes::ComInterface + #itf_path + ?Sized> #itf_path for intercom::ComItf<I> {
                #( #impls )*
            }
        ));
    }
    // Implement the ComInterface for the trait.
    let iid_arms = itf_output.iid_arms;
    let (deref_impl, deref_ret) = if itf.item_type == utils::InterfaceType::Trait {
        (
            quote_spanned!(itf.span => com_itf),
            quote_spanned!(itf.span => &( dyn #itf_path + 'static ) ),
        )
    } else {
        // Note this is _extremely_ dangerous.
        //
        // Essentially we are assuming here that every #itf_path pointer represents
        // a ComBox structure that we have created. This will fail the moment
        // the user code implements #itf_path interface on their own and passes
        // that back to us.
        //
        // There's no real way to get this to work and we might want to just remove
        // the possibility to do 'implicit' interfaces by just impling the struct.
        (
            quote_spanned!(itf.span =>
                let some_iunk : &intercom::ComItf<dyn intercom::interfaces::RawIUnknown> = com_itf.as_raw_iunknown();
                let iunknown_iid = intercom::IUnknown::iid(
                        intercom::type_system::TypeSystemName::Automation )
                            .expect( "IUnknown must have Automation IID" );
                let primary_iunk = some_iunk.query_interface( iunknown_iid )
                        .expect( "All types must implement IUnknown" );
                let combox : *mut intercom::ComBoxData< #itf_path > =
                        primary_iunk as *mut intercom::ComBoxData< #itf_path >;
                unsafe {
                    // We are already holding a reference to the 'self', which should
                    // keep this alive. We don't need to maintain a lifetime of the
                    // queried interface.
                    intercom::ComBoxData::release( combox );
                    // Deref.
                    use std::ops::Deref;
                    (*combox).deref()
                }
            ),
            quote_spanned!(itf.span => & #itf_path ),
        )
    };
    output.push(quote_spanned!(itf.span =>
        impl intercom::attributes::ComInterface for #itf_ref {
            type TSelf = #itf_ref;
            #[doc = "Returns the IID of the requested interface."]
            fn iid_ts<TS: intercom::type_system::TypeSystem>() -> &'static intercom::IID
                where Self: intercom::attributes::ComInterfaceVariant<TS>
            {
                <Self as intercom::attributes::ComInterfaceVariant<TS>>::iid()
            }
            fn iid(
                ts : intercom::type_system::TypeSystemName
            ) -> Option< &'static intercom::IID >
            {
                match ts {
                    #( #iid_arms ),*
                }
            }
            fn deref(
                com_itf : &intercom::ComItf<#itf_ref>
            ) -> #deref_ret {
                #deref_impl
            }
        }
    ));
    // Implement type info for the interface.
    output.push(quote_spanned!(itf.span =>
        impl intercom::type_system::ForeignType for #itf_ref {
            /// The name of the type.
            fn type_name() -> &'static str { stringify!( #itf_path )  }
        }
    ));
    // Create runtime type info.
    output.push(create_get_typeinfo_function(&itf));
    Ok(tokens_to_tokenstream(item_tokens, output))
}
pub fn expand_com_interface ( attr_tokens : TokenStreamNightly , item_tokens : TokenStreamNightly , ) -> Result < TokenStreamNightly , model :: ParseError > { // Parse the attribute. let mut output = vec ! [ ] ; let itf = model :: ComInterface :: from_ast ( & lib_name ( ) , attr_tokens . into ( ) , item_tokens . clone ( ) . into ( ) ) ? ; let itf_path = & itf . path ; let itf_name = itf . ident . to_string ( ) ; let itf_ref = & itf . itf_ref ; let mut itf_output = InterfaceOutput :: default ( ) ; for ( ts , itf_variant ) in & itf . variants { process_itf_variant ( & itf , * ts , itf_variant , & mut output , & mut itf_output ) ; } if itf . item_type == utils :: InterfaceType :: Trait { let mut impls = vec ! [ ] ; for ( _ , method ) in itf_output . method_impls . iter ( ) { let method_rust_ident = & method . info . name ; let method_name = method_rust_ident . to_string ( ) ; let mut impl_branches = vec ! [ ] ; for ( ts , method_ts_impl ) in method . impls . iter ( ) { let ts_tokens = ts . as_typesystem_type ( method . info . signature_span ) ; let ts_name = format ! ( " " ts ) ; impl_branches . push ( quote_spanned ! ( method info signature_span if let Some ( comptr ) intercom ComItf ptr ts_tokens ( self ) { intercom logging trace ( l l ( module_path ( ) format_args ( " " self comptr ptr itf_name method_name ts_name ) ) ) method_ts_impl } ) ) ; } // Format the method arguments into tokens. let impl_args = method . info . args . iter ( ) . map ( | ca | { let name = & ca . name ; let ty = & ca . ty ; quote_spanned ! ( ca span name ty ) } ) ; let unsafety = if method . info . is_unsafe { quote_spanned ! ( method info signature_span unsafe ) } else { quote ! ( ) } ; let self_arg = & method . info . rust_self_arg ; let return_ty = & method . info . rust_return_ty ; // Rust to COM implementation. impls . push ( quote_spanned ! ( method info signature_span unsafety fn method_rust_ident ( self_arg ( impl_args ) ) return_ty { intercom logging trace ( l l ( module_path ( ) format_args ( " " self itf_name method_name ) ) ) [ allow ( unused_imports ) ] use intercom ErrorValue // Try the available type systems. ( impl_branches ) // The ComItf invariant states it has at least one pointer // available so we should never get here. // Also since this is Rust-to-COM call we are allowed to // panic here. unreachable ( ) } ) ) ; } let unsafety = if itf . is_unsafe { quote_spanned ! ( itf span unsafe ) } else { quote ! ( ) } ; output . push ( quote_spanned ! ( itf span [ allow ( clippy all ) ] [ allow ( unused_braces ) ] unsafety impl I intercom attributes ComInterface itf_path Sized itf_path for intercom ComItf I { ( impls ) } ) ) ; } // Implement the ComInterface for the trait. let iid_arms = itf_output . iid_arms ; let ( deref_impl , deref_ret ) = if itf . item_type == utils :: InterfaceType :: Trait { ( quote_spanned ! ( itf span com_itf ) , quote_spanned ! ( itf span ( dyn itf_path ' static ) ) , ) } else { // Note this is _extremely_ dangerous. // // Essentially we are assuming here that every #itf_path pointer represents // a ComBox structure that we have created. This will fail the moment // the user code implements #itf_path interface on their own and passes // that back to us. // // There's no real way to get this to work and we might want to just remove // the possibility to do 'implicit' interfaces by just impling the struct. ( quote_spanned ! ( itf span let some_iunk intercom ComItf dyn intercom interfaces RawIUnknown com_itf as_raw_iunknown ( ) let iunknown_iid intercom IUnknown iid ( intercom type_system TypeSystemName Automation ) expect ( " " ) let primary_iunk some_iunk query_interface ( iunknown_iid ) expect ( " " ) let combox mut intercom ComBoxData itf_path primary_iunk as mut intercom ComBoxData itf_path unsafe { // We are already holding a reference to the 'self', which should // keep this alive. We don't need to maintain a lifetime of the // queried interface. intercom ComBoxData release ( combox ) // Deref. use std ops Deref ( combox ) deref ( ) } ) , quote_spanned ! ( itf span itf_path ) , ) } ; output . push ( quote_spanned ! ( itf span impl intercom attributes ComInterface for itf_ref { type TSelf itf_ref [ doc " " ] fn iid_ts TS intercom type_system TypeSystem ( ) ' static intercom IID where Self intercom attributes ComInterfaceVariant TS { Self as intercom attributes ComInterfaceVariant TS iid ( ) } fn iid ( ts intercom type_system TypeSystemName ) Option ' static intercom IID { match ts { ( iid_arms ) } } fn deref ( com_itf intercom ComItf itf_ref ) deref_ret { deref_impl } } ) ) ; // Implement type info for the interface. output . push ( quote_spanned ! ( itf span impl intercom type_system ForeignType for itf_ref { /// The name of the type. fn type_name ( ) ' static str { stringify ( itf_path ) } } ) ) ; // Create runtime type info. output . push ( create_get_typeinfo_function ( & itf ) ) ; Ok ( tokens_to_tokenstream ( item_tokens , output ) ) }
Expands the `com_interface` attribute.
Expands the ` com_interface ` attribute .
attr_tokens
TokenStreamNightly
item_tokens
TokenStreamNightly
attr_tokens
TokenStreamNightly
item_tokens
TokenStreamNightly