winrt_gen 0.7.2

Code generation for the winrt crate
Documentation
use crate::types::*;
use proc_macro2::TokenStream;
use quote::quote;

pub fn get_async_tokens(
    name: &TypeName,
    interfaces: &Vec<RequiredInterface>,
) -> (TokenStream, TokenStream) {
    let kind = async_kind(name);
    if kind != AsyncKind::None {
        return to_async_tokens(kind, name, name);
    }

    for interface in interfaces {
        let kind = async_kind(&interface.name);

        if kind != AsyncKind::None {
            return to_async_tokens(kind, &interface.name, name);
        }
    }

    (TokenStream::new(), TokenStream::new())
}

#[derive(PartialEq)]
enum AsyncKind {
    None,
    Action,
    ActionWithProgress,
    Operation,
    OperationWithProgress,
}

fn async_kind(name: &TypeName) -> AsyncKind {
    if name.namespace != "Windows.Foundation" {
        return AsyncKind::None;
    }

    match name.name.as_ref() {
        "IAsyncAction" => AsyncKind::Action,
        "IAsyncActionWithProgress`1" => AsyncKind::ActionWithProgress,
        "IAsyncOperation`1" => AsyncKind::Operation,
        "IAsyncOperationWithProgress`2" => AsyncKind::OperationWithProgress,
        _ => AsyncKind::None,
    }
}

fn to_async_tokens(
    kind: AsyncKind,
    name: &TypeName,
    self_name: &TypeName,
) -> (TokenStream, TokenStream) {
    let namespace = to_namespace_tokens("Windows.Foundation", &self_name.namespace);

    let return_type = match kind {
        AsyncKind::Operation | AsyncKind::OperationWithProgress => name.generics[0].to_tokens(),
        _ => quote! { () },
    };

    let handler = match kind {
        AsyncKind::Action => quote! { AsyncActionCompletedHandler },
        AsyncKind::ActionWithProgress => quote! { AsyncActionWithProgressCompletedHandler },
        AsyncKind::Operation => quote! { AsyncOperationCompletedHandler },
        AsyncKind::OperationWithProgress => quote! { AsyncOperationWithProgressCompletedHandler },
        _ => panic!("Unexpected AsyncKind"),
    };

    let constraints = &self_name.constraints;
    let name = &self_name.tokens;

    (
        quote! {
            pub fn get(&self) -> ::winrt::Result<#return_type> {
                if self.status()? == #namespace AsyncStatus::Started {
                    unsafe {
                        let event = ::winrt::CreateEventW(::std::ptr::null_mut(), 1, 0, ::std::ptr::null_mut());
                        self.set_completed(#namespace #handler::new(move |_sender, _args| {
                            ::winrt::SetEvent(event);
                            Ok(())
                        }))?;
                        ::winrt::WaitForSingleObject(event, 0xFFFFFFFF);
                        ::winrt::CloseHandle(event);
                    }
                }
                self.get_results()
            }
        },
        quote! {
            impl<#constraints> ::std::future::Future for #name {
                type Output = ::winrt::Result<#return_type>;

                fn poll(self: ::std::pin::Pin<&mut Self>, context: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output> {
                    if self.status()? == #namespace AsyncStatus::Started {
                        let waker = context.waker().clone();

                        self.set_completed(#namespace #handler::new(move |_sender, _args| {
                            waker.wake_by_ref();
                            Ok(())
                        }))?;

                        ::std::task::Poll::Pending
                    } else {
                        ::std::task::Poll::Ready(self.get_results())
                    }
                }
            }
        },
    )
}