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 | |