| 1 | use super::*; |
| 2 | |
| 3 | #[derive (Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] |
| 4 | pub struct Delegate { |
| 5 | pub def: TypeDef, |
| 6 | pub generics: Vec<Type>, |
| 7 | } |
| 8 | |
| 9 | impl Delegate { |
| 10 | pub fn type_name(&self) -> TypeName { |
| 11 | self.def.type_name() |
| 12 | } |
| 13 | |
| 14 | pub fn write(&self, writer: &Writer) -> TokenStream { |
| 15 | let name = self.write_name(writer); |
| 16 | //let vtbl_name = self.write_vtbl_name(writer); |
| 17 | let vtbl_name: TokenStream = format!(" {}_Vtbl" , self.def.name()).into(); |
| 18 | let boxed: TokenStream = format!(" {}Box" , self.def.name()).into(); |
| 19 | let generic_names = self.generics.iter().map(|ty| ty.write_name(writer)); |
| 20 | let generic_names = quote! { #(#generic_names,)* }; |
| 21 | |
| 22 | let constraints = writer.write_generic_constraints(&self.generics); |
| 23 | let named_phantoms = writer.write_generic_named_phantoms(&self.generics); |
| 24 | let method = self.method(); |
| 25 | |
| 26 | let mut dependencies = TypeMap::new(); |
| 27 | |
| 28 | if writer.config.package { |
| 29 | self.dependencies(&mut dependencies); |
| 30 | } |
| 31 | |
| 32 | let cfg = writer.write_cfg(self.def, self.def.namespace(), &dependencies, false); |
| 33 | |
| 34 | let invoke = method.write( |
| 35 | writer, |
| 36 | None, |
| 37 | InterfaceKind::Default, |
| 38 | &mut MethodNames::new(), |
| 39 | &mut MethodNames::new(), |
| 40 | ); |
| 41 | |
| 42 | let invoke_vtbl = method.write_abi(writer, true); |
| 43 | |
| 44 | let definition = if self.generics.is_empty() { |
| 45 | let guid = writer.write_guid_u128(&self.def.guid_attribute().unwrap()); |
| 46 | |
| 47 | quote! { |
| 48 | #cfg |
| 49 | windows_core::imp::define_interface!(#name, #vtbl_name, #guid); |
| 50 | #cfg |
| 51 | impl windows_core::RuntimeType for #name { |
| 52 | const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::for_interface::<Self>(); |
| 53 | } |
| 54 | } |
| 55 | } else { |
| 56 | let phantoms = writer.write_generic_phantoms(&self.generics); |
| 57 | |
| 58 | let guid = self.def.guid_attribute().unwrap(); |
| 59 | let pinterface = Literal::byte_string(&format!("pinterface( {{{guid}}}" )); |
| 60 | |
| 61 | let generics = self.generics.iter().map(|generic| { |
| 62 | let name = generic.write_name(writer); |
| 63 | quote! { |
| 64 | .push_slice(b";" ).push_other(#name::SIGNATURE) |
| 65 | } |
| 66 | }); |
| 67 | |
| 68 | quote! { |
| 69 | #cfg |
| 70 | #[repr(transparent)] |
| 71 | #[derive(Clone, Debug, Eq, PartialEq)] |
| 72 | pub struct #name(windows_core::IUnknown, #phantoms) where #constraints; |
| 73 | #cfg |
| 74 | unsafe impl<#constraints> windows_core::Interface for #name { |
| 75 | type Vtable = #vtbl_name<#generic_names>; |
| 76 | const IID: windows_core::GUID = windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); |
| 77 | } |
| 78 | #cfg |
| 79 | impl<#constraints> windows_core::RuntimeType for #name { |
| 80 | const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new().push_slice(#pinterface)#(#generics)*.push_slice(b")" ); |
| 81 | } |
| 82 | } |
| 83 | }; |
| 84 | |
| 85 | let fn_constraint = { |
| 86 | let signature = method.write_impl_signature(writer, false, false); |
| 87 | |
| 88 | quote! { F: FnMut #signature + Send + 'static } |
| 89 | }; |
| 90 | |
| 91 | let invoke_upcall = method.write_upcall(quote! { (this.invoke) }, false); |
| 92 | |
| 93 | quote! { |
| 94 | #definition |
| 95 | #cfg |
| 96 | impl<#constraints> #name { |
| 97 | pub fn new<#fn_constraint>(invoke: F) -> Self { |
| 98 | let com = #boxed { |
| 99 | vtable: &#boxed::<#generic_names F>::VTABLE, |
| 100 | count: windows_core::imp::RefCount::new(1), |
| 101 | invoke, |
| 102 | }; |
| 103 | unsafe { |
| 104 | core::mem::transmute(windows_core::imp::Box::new(com)) |
| 105 | } |
| 106 | } |
| 107 | #invoke |
| 108 | } |
| 109 | #cfg |
| 110 | #[repr(C)] |
| 111 | pub struct #vtbl_name<#generic_names> where #constraints { |
| 112 | base__: windows_core::IUnknown_Vtbl, |
| 113 | Invoke: unsafe extern "system" fn(#invoke_vtbl) -> windows_core::HRESULT, |
| 114 | #named_phantoms |
| 115 | } |
| 116 | #cfg |
| 117 | #[repr(C)] |
| 118 | struct #boxed<#generic_names #fn_constraint> where #constraints { |
| 119 | vtable: *const #vtbl_name<#generic_names>, |
| 120 | invoke: F, |
| 121 | count: windows_core::imp::RefCount, |
| 122 | } |
| 123 | #cfg |
| 124 | impl<#constraints #fn_constraint> #boxed<#generic_names F> { |
| 125 | const VTABLE: #vtbl_name<#generic_names> = #vtbl_name::<#generic_names>{ |
| 126 | base__: windows_core::IUnknown_Vtbl{QueryInterface: Self::QueryInterface, AddRef: Self::AddRef, Release: Self::Release}, |
| 127 | Invoke: Self::Invoke, |
| 128 | #named_phantoms |
| 129 | }; |
| 130 | unsafe extern "system" fn QueryInterface(this: *mut core::ffi::c_void, iid: *const windows_core::GUID, interface: *mut *mut core::ffi::c_void) -> windows_core::HRESULT { |
| 131 | unsafe { |
| 132 | let this = this as *mut *mut core::ffi::c_void as *mut Self; |
| 133 | |
| 134 | if iid.is_null() || interface.is_null() { |
| 135 | return windows_core::HRESULT(-2147467261); // E_POINTER |
| 136 | } |
| 137 | |
| 138 | *interface = if *iid == <#name as windows_core::Interface>::IID || |
| 139 | *iid == <windows_core::IUnknown as windows_core::Interface>::IID || |
| 140 | *iid == <windows_core::imp::IAgileObject as windows_core::Interface>::IID { |
| 141 | &mut (*this).vtable as *mut _ as _ |
| 142 | } else { |
| 143 | core::ptr::null_mut() |
| 144 | }; |
| 145 | |
| 146 | if (*interface).is_null() { |
| 147 | windows_core::HRESULT(-2147467262) // E_NOINTERFACE |
| 148 | } else { |
| 149 | (*this).count.add_ref(); |
| 150 | windows_core::HRESULT(0) |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { |
| 155 | unsafe { |
| 156 | let this = this as *mut *mut core::ffi::c_void as *mut Self; |
| 157 | (*this).count.add_ref() |
| 158 | } |
| 159 | } |
| 160 | unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { |
| 161 | unsafe { |
| 162 | let this = this as *mut *mut core::ffi::c_void as *mut Self; |
| 163 | let remaining = (*this).count.release(); |
| 164 | |
| 165 | if remaining == 0 { |
| 166 | let _ = windows_core::imp::Box::from_raw(this); |
| 167 | } |
| 168 | |
| 169 | remaining |
| 170 | } |
| 171 | } |
| 172 | unsafe extern "system" fn Invoke(#invoke_vtbl) -> windows_core::HRESULT { |
| 173 | unsafe { |
| 174 | let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); |
| 175 | #invoke_upcall |
| 176 | } |
| 177 | } |
| 178 | } |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | pub fn method(&self) -> Method { |
| 183 | Method::new( |
| 184 | self.def |
| 185 | .methods() |
| 186 | .find(|method| method.name() == "Invoke" ) |
| 187 | .unwrap(), |
| 188 | &self.generics, |
| 189 | ) |
| 190 | } |
| 191 | |
| 192 | pub fn runtime_signature(&self) -> String { |
| 193 | if self.generics.is_empty() { |
| 194 | let guid = self.def.guid_attribute().unwrap(); |
| 195 | format!("delegate( {{{guid}}})" ) |
| 196 | } else { |
| 197 | interface_signature(self.def, &self.generics) |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | pub fn dependencies(&self, dependencies: &mut TypeMap) { |
| 202 | dependencies.combine(&self.method().dependencies); |
| 203 | |
| 204 | for ty in &self.generics { |
| 205 | ty.dependencies(dependencies); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | pub fn write_name(&self, writer: &Writer) -> TokenStream { |
| 210 | self.type_name().write(writer, &self.generics) |
| 211 | } |
| 212 | } |
| 213 | |