1use super::*;
2
3#[derive(Clone, Debug)]
4pub enum CppMethodOrName {
5 Method(CppMethod),
6 Name(&'static str),
7}
8
9#[derive(Clone, Debug, Hash, PartialEq, Eq)]
10pub struct CppInterface {
11 pub def: TypeDef,
12}
13
14impl Ord for CppInterface {
15 fn cmp(&self, other: &Self) -> Ordering {
16 self.def.name().cmp(other.def.name())
17 }
18}
19
20impl PartialOrd for CppInterface {
21 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
22 Some(self.cmp(other))
23 }
24}
25
26impl CppInterface {
27 pub fn type_name(&self) -> TypeName {
28 self.def.type_name()
29 }
30
31 pub fn get_methods(&self, writer: &Writer) -> Vec<CppMethodOrName> {
32 let namespace = self.def.namespace();
33
34 self.def
35 .methods()
36 .map(|def| {
37 let method = CppMethod::new(def, namespace);
38 if method.dependencies.included(writer.config) {
39 CppMethodOrName::Method(method)
40 } else {
41 CppMethodOrName::Name(method.def.name())
42 }
43 })
44 .collect()
45 }
46
47 pub fn write(&self, writer: &Writer) -> TokenStream {
48 let methods = self.get_methods(writer);
49
50 let base_interfaces = self.base_interfaces();
51 let has_unknown_base = matches!(base_interfaces.first(), Some(Type::IUnknown));
52
53 let mut dependencies = TypeMap::new();
54
55 if writer.config.package {
56 self.dependencies(&mut dependencies);
57 }
58
59 let cfg = writer.write_cfg(self.def, self.def.namespace(), &dependencies, false);
60 let vtbl_name = self.write_vtbl_name(writer);
61
62 let vtbl = {
63 let core = writer.write_core();
64
65 let base = match base_interfaces.last() {
66 Some(Type::IUnknown) => {
67 quote! { pub base__: #core IUnknown_Vtbl, }
68 }
69 Some(Type::Object) => {
70 quote! { pub base__: #core IInspectable_Vtbl, }
71 }
72 Some(Type::CppInterface(ty)) => {
73 let name = ty.write_vtbl_name(writer);
74 quote! { pub base__: #name, }
75 }
76 _ => quote! {},
77 };
78
79 let mut names = MethodNames::new();
80
81 let methods = methods.iter().map(|method| match method {
82 CppMethodOrName::Method(method) => {
83 let mut difference = TypeMap::new();
84
85 if writer.config.package {
86 difference = method.dependencies.difference(&dependencies);
87 }
88
89 let name = names.add(method.def);
90 let abi = method.write_abi(writer, false);
91 let cfg = writer.write_cfg(self.def, self.def.namespace(), &difference, false);
92
93 if cfg.is_empty() {
94 quote! {
95 pub #name: unsafe extern "system" fn #abi,
96 }
97 } else {
98 let cfg_not =
99 writer.write_cfg(self.def, self.def.namespace(), &difference, true);
100
101 quote! {
102 #cfg
103 pub #name: unsafe extern "system" fn #abi,
104 #cfg_not
105 #name: usize,
106 }
107 }
108 }
109 CppMethodOrName::Name(name) => {
110 let name = to_ident(name);
111 quote! { #name: usize, }
112 }
113 });
114
115 quote! {
116 #cfg
117 #[repr(C)]
118 pub struct #vtbl_name {
119 #base
120 #(#methods)*
121 }
122 }
123 };
124
125 if writer.config.sys {
126 let mut result = quote! {};
127
128 if !writer.config.package {
129 if has_unknown_base {
130 if let Some(guid) = self.def.guid_attribute() {
131 let name: TokenStream = format!("IID_{}", self.def.name()).into();
132 result.combine(writer.write_cpp_const_guid(name, &guid));
133 }
134 }
135
136 result.combine(vtbl);
137 }
138
139 result
140 } else {
141 let name = to_ident(self.def.name());
142
143 let mut result = if has_unknown_base {
144 if let Some(guid) = self.def.guid_attribute() {
145 let guid = writer.write_guid_u128(&guid);
146
147 quote! {
148 #cfg
149 windows_core::imp::define_interface!(#name, #vtbl_name, #guid);
150 }
151 } else {
152 quote! {
153 #cfg
154 windows_core::imp::define_interface!(#name, #vtbl_name, 0);
155 }
156 }
157 } else {
158 quote! {
159 #cfg
160 windows_core::imp::define_interface!(#name, #vtbl_name);
161 }
162 };
163
164 if let Some(Type::CppInterface(base)) = base_interfaces.last() {
165 let base = base.write_name(writer);
166
167 result.combine(quote! {
168 #cfg
169 impl core::ops::Deref for #name {
170 type Target = #base;
171 fn deref(&self) -> &Self::Target {
172 unsafe { core::mem::transmute(self) }
173 }
174 }
175 });
176 }
177
178 if !base_interfaces.is_empty() {
179 let bases = base_interfaces.iter().map(|ty| ty.write_name(writer));
180 result.combine(quote! {
181 #cfg
182 windows_core::imp::interface_hierarchy!(#name, #(#bases),*);
183 })
184 }
185
186 let method_names = &mut MethodNames::new();
187 let virtual_names = &mut MethodNames::new();
188 let mut methods_tokens = quote! {};
189
190 for method in methods.iter().filter_map(|method| match &method {
191 CppMethodOrName::Method(method) => Some(method),
192 _ => None,
193 }) {
194 let mut difference = TypeMap::new();
195
196 if writer.config.package {
197 difference = method.dependencies.difference(&dependencies);
198 }
199
200 let cfg = writer.write_cfg(self.def, self.def.namespace(), &difference, false);
201
202 let method = method.write(writer, method_names, virtual_names);
203
204 methods_tokens.combine(quote! {
205 #cfg
206 #method
207 });
208 }
209
210 if !methods_tokens.is_empty() {
211 result.combine(quote! {
212 #cfg
213 impl #name {
214 #methods_tokens
215 }
216 });
217 }
218
219 result.combine(vtbl);
220
221 let impl_name: TokenStream = format!("{}_Impl", self.def.name()).into();
222
223 if writer.config.package {
224 fn collect(interface: &CppInterface, dependencies: &mut TypeMap, writer: &Writer) {
225 for method in interface.get_methods(writer).iter() {
226 if let CppMethodOrName::Method(method) = method {
227 dependencies.combine(&method.dependencies);
228 }
229 }
230 }
231
232 collect(self, &mut dependencies, writer);
233 base_interfaces.iter().for_each(|interface| {
234 if let Type::CppInterface(ty) = interface {
235 collect(ty, &mut dependencies, writer);
236 }
237 });
238 }
239
240 let cfg = writer.write_cfg(self.def, self.def.namespace(), &dependencies, false);
241
242 let mut names = MethodNames::new();
243
244 let field_methods: Vec<_> = methods
245 .iter()
246 .map(|method| match method {
247 CppMethodOrName::Method(method) => {
248 let name = names.add(method.def);
249 if has_unknown_base {
250 quote! { #name: #name::<Identity, OFFSET>, }
251 } else {
252 quote! { #name: #name::<Identity>, }
253 }
254 }
255 CppMethodOrName::Name(name) => {
256 let name = to_ident(name);
257 quote! { #name: 0, }
258 }
259 })
260 .collect();
261
262 let mut names = MethodNames::new();
263
264 let impl_methods: Vec<_> = methods.iter().map(|method| match method {
265 CppMethodOrName::Method(method) => {
266 let name = names.add(method.def);
267 let signature = method.write_abi(writer, true);
268 let upcall = method.write_upcall(&impl_name, &name);
269
270 if has_unknown_base {
271 quote! {
272 unsafe extern "system" fn #name<Identity: #impl_name, const OFFSET: isize> #signature {
273 unsafe {
274 let this: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
275 #upcall
276 }
277 }
278 }
279 } else {
280 quote! {
281 unsafe extern "system" fn #name<Identity: #impl_name> #signature {
282 unsafe {
283 let this = (this as *mut *mut core::ffi::c_void) as *const windows_core::ScopedHeap;
284 let this = &*((*this).this as *const Identity);
285 #upcall
286 }
287 }
288 }
289 }
290 }
291 _ => quote! {},
292 }).collect();
293
294 let mut names = MethodNames::new();
295
296 let trait_methods: Vec<_> = methods
297 .iter()
298 .map(|method| match method {
299 CppMethodOrName::Method(method) => {
300 let name = names.add(method.def);
301 let signature = method.write_impl_signature(writer, true);
302 quote! { fn #name #signature; }
303 }
304 _ => quote! {},
305 })
306 .collect();
307
308 let impl_base = base_interfaces.last().map(|ty| ty.write_impl_name(writer));
309
310 let field_base = base_interfaces.last().map(|ty|{
311 match ty {
312 Type::IUnknown => quote! { base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), },
313 Type::Object => quote! { base__: windows_core::IInspectable_Vtbl::new::<Identity, #name, OFFSET>(), },
314 Type::CppInterface(ty) => {
315 let ty = ty.write_vtbl_name(writer);
316 if has_unknown_base {
317 quote! { base__: #ty::new::<Identity, OFFSET>(), }
318 } else {
319 quote! { base__: #ty::new::<Identity>(), }
320 }
321 }
322 rest => panic!("{rest:?}"),
323 }
324 });
325
326 result.combine( if has_unknown_base {
327 let matches = base_interfaces.iter().filter_map(|ty|{
328 match ty {
329 Type::CppInterface(ty) => {
330 let name = ty.write_name(writer);
331 Some(quote! { || iid == &<#name as windows_core::Interface>::IID })
332 }
333 _ => None,
334 }
335 });
336
337 quote! {
338 #cfg
339 pub trait #impl_name: #impl_base {
340 #(#trait_methods)*
341 }
342 #cfg
343 impl #vtbl_name {
344 pub const fn new<Identity: #impl_name, const OFFSET: isize>() -> Self {
345 #(#impl_methods)*
346 Self {
347 #field_base
348 #(#field_methods)*
349 }
350 }
351 pub fn matches(iid: &windows_core::GUID) -> bool {
352 iid == &<#name as windows_core::Interface>::IID #(#matches)*
353 }
354 }
355 #cfg
356 impl windows_core::RuntimeName for #name {}
357 }
358 } else {
359 let implvtbl_ident = impl_name.join("Vtbl");
360
361 quote! {
362 #cfg
363 pub trait #impl_name : #impl_base {
364 #(#trait_methods)*
365 }
366 #cfg
367 impl #vtbl_name {
368 pub const fn new<Identity: #impl_name>() -> Self {
369 #(#impl_methods)*
370 Self{
371 #field_base
372 #(#field_methods)*
373 }
374 }
375 }
376 #cfg
377 struct #implvtbl_ident<T: #impl_name> (core::marker::PhantomData<T>);
378 #cfg
379 impl<T: #impl_name> #implvtbl_ident<T> {
380 const VTABLE: #vtbl_name = #vtbl_name::new::<T>();
381 }
382 #cfg
383 impl #name {
384 pub fn new<'a, T: #impl_name>(this: &'a T) -> windows_core::ScopedInterface<'a, Self> {
385 let this = windows_core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
386 let this = core::mem::ManuallyDrop::new(windows_core::imp::Box::new(this));
387 unsafe { windows_core::ScopedInterface::new(core::mem::transmute(&this.vtable)) }
388 }
389 }
390 }
391 });
392
393 if self.def.is_agile() {
394 result.combine(quote! {
395 #cfg
396 unsafe impl Send for #name {}
397 #cfg
398 unsafe impl Sync for #name {}
399 });
400 }
401
402 result
403 }
404 }
405
406 pub fn write_name(&self, writer: &Writer) -> TokenStream {
407 if writer.config.sys {
408 quote! { *mut core::ffi::c_void }
409 } else {
410 self.type_name().write(writer, &[])
411 }
412 }
413
414 fn write_vtbl_name(&self, writer: &Writer) -> TokenStream {
415 let name: TokenStream = format!("{}_Vtbl", self.def.name()).into();
416 let namespace = writer.write_namespace(self.def.type_name());
417 quote! { #namespace #name }
418 }
419
420 pub fn write_impl_name(&self, writer: &Writer) -> TokenStream {
421 let name: TokenStream = format!("{}_Impl", self.def.name()).into();
422 let namespace = writer.write_namespace(self.def.type_name());
423 quote! { #namespace #name }
424 }
425
426 pub fn dependencies(&self, dependencies: &mut TypeMap) {
427 let base_interfaces = self.base_interfaces();
428
429 for interface in &base_interfaces {
430 interface.dependencies(dependencies);
431 }
432
433 for method in self.def.methods() {
434 for ty in method.signature(self.def.namespace(), &[]).types() {
435 if ty.is_core() {
436 ty.dependencies(dependencies);
437 }
438 }
439 }
440 }
441
442 pub fn base_interfaces(&self) -> Vec<Type> {
443 let mut bases = vec![];
444 let mut def = self.def;
445
446 while let Some(base) = def.interface_impls().map(move |imp| imp.ty(&[])).next() {
447 match base {
448 Type::CppInterface(ref ty) => {
449 def = ty.def;
450 bases.insert(0, base);
451 }
452 Type::Object => {
453 bases.insert(0, Type::IUnknown);
454 bases.insert(1, Type::Object);
455 break;
456 }
457 Type::IUnknown => {
458 bases.insert(0, Type::IUnknown);
459 break;
460 }
461 rest => panic!("{rest:?}"),
462 }
463 }
464
465 bases
466 }
467}
468