1use super::*;
2
3#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
4pub struct Delegate {
5 pub def: TypeDef,
6 pub generics: Vec<Type>,
7}
8
9impl 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