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::parse(
            &lib_name(),
            attr_tokens.into(),
            &item_tokens.to_string() )?;
    let itf_ident = itf.name();

    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 mut impl_branches = vec![];
            for ( ts, method_ts_impl ) in method.impls.iter() {

                let ts_tokens = ts.as_typesystem_tokens();
                impl_branches.push( quote!(
                    if let Some( comptr ) = ComItf::maybe_ptr( self, #ts_tokens ) {
                        #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!( #name : #ty )
            } );

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

            // Rust to COM implementation.
            impls.push( quote!(
                #unsafety fn #method_rust_ident(
                    #self_arg, #( #impl_args ),*
                ) -> #return_ty {

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

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

                    // None of the type system pointers were available,
                    // which means this is a null reference.
                    < #return_ty as ::intercom::ErrorValue >::from_com_error(
                            ::intercom::ComError::E_POINTER.into() )
                }
            ) );
        }

        let unsafety = if itf.is_unsafe() { quote!( unsafe ) } else { quote!() };
        output.push( quote!(
            #unsafety impl #itf_ident for ::intercom::ComItf< #itf_ident > {
                #( #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!( com_itf ),
            quote!( &( #itf_ident + 'static ) )
        )
    } else {

        // Note this is _extremely_ dangerous.
        //
        // Essentially we are assuming here that every #itf_ident pointer represents
        // a ComBox structure that we have created. This will fail the moment
        // the user code implements #itf_ident 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!(
                let some_iunk : &::intercom::ComItf<::intercom::IUnknown> = com_itf.as_ref();
                let iunknown_iid = ::intercom::IUnknown::iid(
                        ::intercom::TypeSystem::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::ComBox< #itf_ident > =
                        primary_iunk as *mut ::intercom::ComBox< #itf_ident >;
                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::ComBox::release( combox );

                    // Deref.
                    use std::ops::Deref;
                    (*combox).deref()
                }
            ),
            quote!( & #itf_ident )
        )
    };

    output.push( quote!(
        impl ::intercom::ComInterface for #itf_ident {

            #[doc = "Returns the IID of the requested interface."]
            fn iid( ts : ::intercom::TypeSystem ) -> Option< &'static ::intercom::IID > {
                match ts {
                    #( #iid_arms ),*
                }
            }

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

    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::parse(
            &lib_name(),
            attr_tokens.into(),
            &item_tokens.to_string() )?;
    let itf_ident = itf.name();
    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 mut impl_branches = vec![];
            for ( ts, method_ts_impl ) in method.impls.iter() {
                let ts_tokens = ts.as_typesystem_tokens();
                impl_branches.push( quote!(
                    if let Some( comptr ) = ComItf::maybe_ptr( self, #ts_tokens ) {
                        #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!( #name : #ty )
            } );
            let unsafety = if method.info.is_unsafe { quote!( unsafe ) } else { quote!() };
            let self_arg = &method.info.rust_self_arg;
            let method_rust_ident = &method.info.display_name;
            let return_ty = &method.info.rust_return_ty;
            // Rust to COM implementation.
            impls.push( quote!(
                #unsafety fn #method_rust_ident(
                    #self_arg, #( #impl_args ),*
                ) -> #return_ty {
                    #[allow(unused_imports)]
                    use ::intercom::ComInto;
                    #[allow(unused_imports)]
                    use ::intercom::ErrorValue;
                    // Try the available type systems.
                    #( #impl_branches )*
                    // None of the type system pointers were available,
                    // which means this is a null reference.
                    < #return_ty as ::intercom::ErrorValue >::from_com_error(
                            ::intercom::ComError::E_POINTER.into() )
                }
            ) );
        }
        let unsafety = if itf.is_unsafe() { quote!( unsafe ) } else { quote!() };
        output.push( quote!(
            #unsafety impl #itf_ident for ::intercom::ComItf< #itf_ident > {
                #( #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!( com_itf ),
            quote!( &( #itf_ident + 'static ) )
        )
    } else {
        // Note this is _extremely_ dangerous.
        //
        // Essentially we are assuming here that every #itf_ident pointer represents
        // a ComBox structure that we have created. This will fail the moment
        // the user code implements #itf_ident 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!(
                let some_iunk : &::intercom::ComItf<::intercom::IUnknown> = com_itf.as_ref();
                let iunknown_iid = ::intercom::IUnknown::iid(
                        ::intercom::TypeSystem::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::ComBox< #itf_ident > =
                        primary_iunk as *mut ::intercom::ComBox< #itf_ident >;
                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::ComBox::release( combox );
                    // Deref.
                    use std::ops::Deref;
                    (*combox).deref()
                }
            ),
            quote!( & #itf_ident )
        )
    };
    output.push( quote!(
        impl ::intercom::ComInterface for #itf_ident {
            #[doc = "Returns the IID of the requested interface."]
            fn iid( ts : ::intercom::TypeSystem ) -> Option< &'static ::intercom::IID > {
                match ts {
                    #( #iid_arms ),*
                }
            }
            fn deref(
                com_itf : &::intercom::ComItf< #itf_ident >
            ) -> #deref_ret {
                #deref_impl
            }
        }
    ) );
    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 :: parse ( & lib_name ( ) , attr_tokens . into ( ) , & item_tokens . to_string ( ) ) ? ; let itf_ident = itf . name ( ) ; 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 mut impl_branches = vec ! [ ] ; for ( ts , method_ts_impl ) in method . impls . iter ( ) { let ts_tokens = ts . as_typesystem_tokens ( ) ; impl_branches . push ( quote ! ( if let Some ( comptr ) ComItf maybe_ptr ( self ts_tokens ) { 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 ! ( name ty ) } ) ; let unsafety = if method . info . is_unsafe { quote ! ( unsafe ) } else { quote ! ( ) } ; let self_arg = & method . info . rust_self_arg ; let method_rust_ident = & method . info . display_name ; let return_ty = & method . info . rust_return_ty ; // Rust to COM implementation. impls . push ( quote ! ( unsafety fn method_rust_ident ( self_arg ( impl_args ) ) return_ty { [ allow ( unused_imports ) ] use intercom ComInto [ allow ( unused_imports ) ] use intercom ErrorValue // Try the available type systems. ( impl_branches ) // None of the type system pointers were available, // which means this is a null reference. return_ty as intercom ErrorValue from_com_error ( intercom ComError E_POINTER into ( ) ) } ) ) ; } let unsafety = if itf . is_unsafe ( ) { quote ! ( unsafe ) } else { quote ! ( ) } ; output . push ( quote ! ( unsafety impl itf_ident for intercom ComItf itf_ident { ( 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 ! ( com_itf ) , quote ! ( ( itf_ident ' static ) ) ) } else { // Note this is _extremely_ dangerous. // // Essentially we are assuming here that every #itf_ident pointer represents // a ComBox structure that we have created. This will fail the moment // the user code implements #itf_ident 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 ! ( let some_iunk intercom ComItf intercom IUnknown com_itf as_ref ( ) let iunknown_iid intercom IUnknown iid ( intercom TypeSystem Automation ) expect ( " " ) let primary_iunk some_iunk query_interface ( iunknown_iid ) expect ( " " ) let combox mut intercom ComBox itf_ident primary_iunk as mut intercom ComBox itf_ident 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 ComBox release ( combox ) // Deref. use std ops Deref ( combox ) deref ( ) } ) , quote ! ( itf_ident ) ) } ; output . push ( quote ! ( impl intercom ComInterface for itf_ident { [ doc " " ] fn iid ( ts intercom TypeSystem ) Option ' static intercom IID { match ts { ( iid_arms ) } } fn deref ( com_itf intercom ComItf itf_ident ) deref_ret { deref_impl } } ) ) ; Ok ( tokens_to_tokenstream ( item_tokens , output ) ) }
Expands the `com_interface` attribute.
Expands the ` com_interface ` attribute .
attr_tokens
TokenStreamNightly
item_tokens
TokenStreamNightly