use crate::*;
use squote::{quote, Literal, TokenStream};
#[derive(Debug)]
pub struct ComInterface {
pub name: TypeName,
pub methods: Vec<Signature>,
}
impl ComInterface {
pub fn from_type_name(name: TypeName) -> Self {
let methods = name
.def
.methods()
.map(|method| Signature::new(&method, &[], &name.namespace))
.collect();
Self { name, methods }
}
pub fn gen(&self) -> TokenStream {
let name = self.name.gen();
let abi_name = self.name.gen_abi_definition();
let guid = TypeGuid::from_type_def(&self.name.def);
let guid = self.name.gen_guid(&guid);
let methods = self.methods.iter().enumerate().map(|(vtable_offset, signature)| {
let return_type = if let Some(t) = &signature.return_type {
let tokens = t.gen_field();
quote! { -> #tokens }
} else {
TokenStream::new()
};
let params = signature.params.iter().map(|t| {
let name = format_ident(&t.name);
let tokens = t.gen_field();
quote! { #name: #tokens }
});
let args = signature.params.iter().map(|t| {
let name = format_ident(&t.name);
quote! { #name }
});
let name = format_ident(signature.method.name());
let vtable_offset = Literal::u32_unsuffixed((vtable_offset + 3) as u32);
quote! {
pub fn #name(&self, #(#params),*) #return_type {
unsafe {
(::windows::Interface::vtable(self).#vtable_offset)(::windows::Abi::abi(self), #(#args),*)
}
}
}
});
let abi_methods = self.methods.iter().map(|signature| {
let return_type = if let Some(t) = &signature.return_type {
let tokens = t.gen_field();
quote! { -> #tokens }
} else {
TokenStream::new()
};
let params = signature.params.iter().map(|t| {
let name = format_ident(&t.name);
let tokens = t.gen_field();
quote! { #name: #tokens }
});
quote! {
pub unsafe extern "system" fn (this: ::windows::RawPtr, #(#params),*) #return_type
}
});
quote! {
#[repr(transparent)]
#[allow(non_camel_case_types)]
pub struct #name(::windows::IUnknown);
impl ::std::clone::Clone for #name {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl ::std::fmt::Debug for #name {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
write!(f, "{:?}", self.0)
}
}
impl ::std::cmp::PartialEq for #name {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl ::std::cmp::Eq for #name {}
unsafe impl ::windows::Interface for #name {
type Vtable = #abi_name;
const IID: ::windows::Guid = #guid;
}
#[repr(C)]
pub struct #abi_name(
pub unsafe extern "system" fn(this: ::windows::RawPtr, iid: &::windows::Guid, interface: *mut ::windows::RawPtr) -> ::windows::ErrorCode,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
#(#abi_methods,)*
);
#[allow(non_snake_case)]
impl #name {
#(#methods)*
}
}
}
pub fn dependencies(&self) -> Vec<winmd::TypeDef> {
self.methods
.iter()
.map(|signature| signature.dependencies())
.flatten()
.collect()
}
}