1//! Generates output for the `implement` proc macro.
2//!
3//! Each function in this module focuses on generating one thing, or one kind of thing.
4//! Each takes `ImplementInputs` as its input. `gen_all` calls all of the `gen_*` functions
5//! and merges them into the final list of output items.
6//!
7//! We use `parse_quote` so that we can verify that a given function generates a well-formed AST
8//! item, within the narrowest possible scope. This allows us to detect errors more quickly during
9//! development. If the input to `parse_quote` cannot be parsed, then the macro will panic and
10//! the panic will point to the specific `parse_quote` call, rather than the entire output of the
11//! `implement` proc macro being unparsable. This greatly aids in development.
12
13use super::*;
14use quote::{quote, quote_spanned};
15use syn::{parse_quote, parse_quote_spanned};
16
17/// Generates code for the `#[implements]` macro.
18pub(crate) fn gen_all(inputs: &ImplementInputs) -> Vec<syn::Item> {
19 let mut items: Vec<syn::Item> = Vec::with_capacity(64);
20
21 items.push(gen_original_impl(inputs));
22 items.push(gen_impl_struct(inputs));
23 items.push(gen_impl_deref(inputs));
24 items.push(gen_impl_impl(inputs));
25 items.push(gen_iunknown_impl(inputs));
26 items.push(gen_impl_com_object_inner(inputs));
27 items.extend(iter:gen_impl_from(inputs));
28 items.extend(iter:gen_impl_com_object_interfaces(inputs));
29
30 for (i: usize, interface_chain: &InterfaceChain) in inputs.interface_chains.iter().enumerate() {
31 items.push(gen_impl_as_impl(inputs, interface_chain, interface_chain_index:i));
32 }
33
34 items
35}
36
37/// Generates an `impl` block for the original `Foo` type.
38///
39/// This `impl` block will contain `into_outer` and `into_static` (if applicable).
40fn gen_original_impl(inputs: &ImplementInputs) -> syn::Item {
41 let original_ident: &Ident = &inputs.original_ident;
42 let generics: &TokenStream = &inputs.generics;
43 let constraints: &TokenStream = &inputs.constraints;
44
45 let mut output: syn::ItemImpl = parse_quote! {
46 impl #generics #original_ident::#generics where #constraints {}
47 };
48
49 output.items.push(gen_into_outer(inputs));
50
51 // Static COM objects have a lot of constraints. They can't be generic (open parameters),
52 // because that would be meaningless (an open generic type cannot have a known representation).
53 //
54 // Right now, we can't generate static COM objects that have base classes because we rely on
55 // boxing and then unboxing during construction of aggregated types.
56 if !inputs.is_generic {
57 output.items.push(gen_into_static(inputs));
58 }
59
60 syn::Item::Impl(output)
61}
62
63/// Generates the structure definition for the `Foo_Impl` type.
64fn gen_impl_struct(inputs: &ImplementInputs) -> syn::Item {
65 let impl_ident = &inputs.impl_ident;
66 let generics = &inputs.generics;
67 let constraints = &inputs.constraints;
68 let original_ident = &inputs.original_ident;
69 let vis = &inputs.original_type.vis;
70
71 let mut impl_fields = quote! {
72 identity: &'static ::windows_core::IInspectable_Vtbl,
73 };
74
75 for interface_chain in inputs.interface_chains.iter() {
76 let vtbl_ty = interface_chain.implement.to_vtbl_ident();
77 let chain_field_ident = &interface_chain.field_ident;
78 impl_fields.extend(quote! {
79 #chain_field_ident: &'static #vtbl_ty,
80 });
81 }
82
83 impl_fields.extend(quote! {
84 this: #original_ident::#generics,
85 count: ::windows_core::imp::WeakRefCount,
86 });
87
88 parse_quote! {
89 #[repr(C)]
90 #[allow(non_camel_case_types)]
91 #vis struct #impl_ident #generics where #constraints {
92 #impl_fields
93 }
94 }
95}
96
97/// Generates the implementation of `core::ops::Deref` for the generated `Foo_Impl` type.
98fn gen_impl_deref(inputs: &ImplementInputs) -> syn::Item {
99 let generics: &TokenStream = &inputs.generics;
100 let constraints: &TokenStream = &inputs.constraints;
101 let original_ident: &Ident = &inputs.original_type.ident;
102 let impl_ident: &Ident = &inputs.impl_ident;
103
104 parse_quote! {
105 impl #generics ::core::ops::Deref for #impl_ident::#generics where #constraints {
106 type Target = #original_ident::#generics;
107
108 #[inline(always)]
109 fn deref(&self) -> &Self::Target {
110 &self.this
111 }
112 }
113 }
114}
115
116/// Generates an `impl` block for the generated `Foo_Impl` block.
117///
118/// This generates:
119///
120/// ```rust,ignore
121/// const VTABLE_IDENTITY = IInspectable_Vtbl = ...;
122/// const VTABLE_INTERFACE1_IFOO: IFoo_Vtbl = ...;
123/// const VTABLE_INTERFACE2_IBAR: IBar_Vtbl = ...;
124/// ```
125///
126/// These constants are used when constructing vtables. The benefit of using constants instead
127/// of directly generating these expressions is that it allows us to overcome limitations in
128/// using generics in constant contexts. Right now, Rust has a lot of limitations around using
129/// constants in constant contexts. Fortunately, associated constants (constants defined within
130/// `impl` blocks) work in stable Rust, even for generic types.
131fn gen_impl_impl(inputs: &ImplementInputs) -> syn::Item {
132 let impl_ident = &inputs.impl_ident;
133 let generics = &inputs.generics;
134 let constraints = &inputs.constraints;
135
136 let mut output: syn::ItemImpl = parse_quote! {
137 impl #generics #impl_ident::#generics where #constraints {}
138 };
139
140 // This is here so that IInspectable::GetRuntimeClassName can work properly.
141 // For a test case for this, see crates/tests/misc/component_client.
142 let identity_type = if let Some(first) = inputs.interface_chains.first() {
143 first.implement.to_ident()
144 } else {
145 quote! { ::windows_core::IInspectable }
146 };
147
148 output.items.push(parse_quote! {
149 const VTABLE_IDENTITY: ::windows_core::IInspectable_Vtbl =
150 ::windows_core::IInspectable_Vtbl::new::<
151 #impl_ident::#generics,
152 #identity_type,
153 0,
154 >();
155 });
156
157 for (interface_index, interface_chain) in inputs.interface_chains.iter().enumerate() {
158 let vtbl_ty = interface_chain.implement.to_vtbl_ident();
159 let vtable_const_ident = &interface_chain.vtable_const_ident;
160
161 let chain_offset_in_pointers: isize = -1 - interface_index as isize;
162 output.items.push(parse_quote! {
163 const #vtable_const_ident: #vtbl_ty = #vtbl_ty::new::<
164 #impl_ident::#generics,
165 #chain_offset_in_pointers,
166 >();
167 });
168 }
169
170 syn::Item::Impl(output)
171}
172
173/// Generates the `IUnknownImpl` implementation for the `Foo_Impl` type.
174fn gen_iunknown_impl(inputs: &ImplementInputs) -> syn::Item {
175 let generics = &inputs.generics;
176 let constraints = &inputs.constraints;
177 let impl_ident = &inputs.impl_ident;
178 let original_ident = &inputs.original_type.ident;
179
180 let trust_level = proc_macro2::Literal::usize_unsuffixed(inputs.trust_level);
181
182 let mut output: syn::ItemImpl = parse_quote! {
183 impl #generics ::windows_core::IUnknownImpl for #impl_ident::#generics where #constraints {
184 type Impl = #original_ident::#generics;
185
186 #[inline(always)]
187 fn get_impl(&self) -> &Self::Impl {
188 &self.this
189 }
190
191 #[inline(always)]
192 fn get_impl_mut(&mut self) -> &mut Self::Impl {
193 &mut self.this
194 }
195
196 #[inline(always)]
197 fn into_inner(self) -> Self::Impl {
198 self.this
199 }
200
201 #[inline(always)]
202 fn AddRef(&self) -> u32 {
203 self.count.add_ref()
204 }
205
206 #[inline(always)]
207 unsafe fn Release(self_: *mut Self) -> u32 {
208 let remaining = (*self_).count.release();
209 if remaining == 0 {
210 _ = ::windows_core::imp::Box::from_raw(self_);
211 }
212 remaining
213 }
214
215 #[inline(always)]
216 fn is_reference_count_one(&self) -> bool {
217 self.count.is_one()
218 }
219
220 unsafe fn GetTrustLevel(&self, value: *mut i32) -> ::windows_core::HRESULT {
221 if value.is_null() {
222 return ::windows_core::imp::E_POINTER;
223 }
224 *value = #trust_level;
225 ::windows_core::HRESULT(0)
226 }
227
228 fn to_object(&self) -> ::windows_core::ComObject<Self::Impl> {
229 self.count.add_ref();
230 unsafe {
231 ::windows_core::ComObject::from_raw(
232 ::core::ptr::NonNull::new_unchecked(self as *const Self as *mut Self)
233 )
234 }
235 }
236 }
237 };
238
239 let query_interface_fn = gen_query_interface(inputs);
240 output.items.push(syn::ImplItem::Fn(query_interface_fn));
241
242 syn::Item::Impl(output)
243}
244
245/// Generates the implementation of `ComObjectInner`.
246fn gen_impl_com_object_inner(inputs: &ImplementInputs) -> syn::Item {
247 let original_ident = &inputs.original_type.ident;
248 let generics = &inputs.generics;
249 let constraints = &inputs.constraints;
250 let impl_ident = &inputs.impl_ident;
251
252 parse_quote! {
253 impl #generics ::windows_core::ComObjectInner for #original_ident::#generics where #constraints {
254 type Outer = #impl_ident::#generics;
255
256 // IMPORTANT! This function handles assembling the "boxed" type of a COM object.
257 // It immediately moves the box into a heap allocation (box) and returns only a ComObject
258 // reference that points to it. We intentionally _do not_ expose any owned instances of
259 // Foo_Impl to safe Rust code, because doing so would allow unsound behavior in safe Rust
260 // code, due to the adjustments of the reference count that Foo_Impl permits.
261 //
262 // This is why this function returns ComObject<Self> instead of returning #impl_ident.
263
264 fn into_object(self) -> ::windows_core::ComObject<Self> {
265 let boxed = ::windows_core::imp::Box::<#impl_ident::#generics>::new(self.into_outer());
266 unsafe {
267 let ptr = ::windows_core::imp::Box::into_raw(boxed);
268 ::windows_core::ComObject::from_raw(
269 ::core::ptr::NonNull::new_unchecked(ptr)
270 )
271 }
272 }
273 }
274 }
275}
276
277/// Generates the `query_interface` method.
278fn gen_query_interface(inputs: &ImplementInputs) -> syn::ImplItemFn {
279 let queries = inputs.interface_chains.iter().map(|interface_chain| {
280 let chain_ty = interface_chain.implement.to_vtbl_ident();
281 let chain_field = &interface_chain.field_ident;
282 quote_spanned! {
283 interface_chain.implement.span =>
284 if #chain_ty::matches(&iid) {
285 break 'found &self.#chain_field as *const _ as *const ::core::ffi::c_void;
286 }
287 }
288 });
289
290 // Dynamic casting requires that the object not contain non-static lifetimes.
291 let enable_dyn_casting = inputs.original_type.generics.lifetimes().count() == 0;
292 let dynamic_cast_query = if enable_dyn_casting {
293 quote! {
294 if iid == ::windows_core::DYNAMIC_CAST_IID {
295 // DYNAMIC_CAST_IID is special. We _do not_ increase the reference count for this pseudo-interface.
296 // Also, instead of returning an interface pointer, we simply write the `&dyn Any` directly to the
297 // 'interface' pointer. Since the size of `&dyn Any` is 2 pointers, not one, the caller must be
298 // prepared for this. This is not a normal QueryInterface call.
299 //
300 // See the `Interface::cast_to_any` method, which is the only caller that should use DYNAMIC_CAST_ID.
301 (interface as *mut *const dyn core::any::Any).write(self as &dyn ::core::any::Any as *const dyn ::core::any::Any);
302 return ::windows_core::HRESULT(0);
303 }
304 }
305 } else {
306 quote!()
307 };
308
309 let identity_query = quote! {
310 if iid == <::windows_core::IUnknown as ::windows_core::Interface>::IID
311 || iid == <::windows_core::IInspectable as ::windows_core::Interface>::IID
312 || iid == <::windows_core::imp::IAgileObject as ::windows_core::Interface>::IID {
313 break 'found &self.identity as *const _ as *const ::core::ffi::c_void;
314 }
315 };
316
317 let marshal_query = quote! {
318 #[cfg(windows)]
319 if iid == <::windows_core::imp::IMarshal as ::windows_core::Interface>::IID {
320 return ::windows_core::imp::marshaler(self.to_interface(), interface);
321 }
322 };
323
324 let tear_off_query = quote! {
325 let tear_off_ptr = self.count.query(&iid, &self.identity as *const _ as *mut _);
326 if !tear_off_ptr.is_null() {
327 *interface = tear_off_ptr;
328 return ::windows_core::HRESULT(0);
329 }
330 };
331
332 parse_quote! {
333 unsafe fn QueryInterface(
334 &self,
335 iid: *const ::windows_core::GUID,
336 interface: *mut *mut ::core::ffi::c_void,
337 ) -> ::windows_core::HRESULT {
338 unsafe {
339 if iid.is_null() || interface.is_null() {
340 return ::windows_core::imp::E_POINTER;
341 }
342
343 let iid = *iid;
344
345 let interface_ptr: *const ::core::ffi::c_void = 'found: {
346 #identity_query
347 #(#queries)*
348 #marshal_query
349 #dynamic_cast_query
350 #tear_off_query
351
352 *interface = ::core::ptr::null_mut();
353 return ::windows_core::imp::E_NOINTERFACE;
354 };
355
356 debug_assert!(!interface_ptr.is_null());
357 *interface = interface_ptr as *mut ::core::ffi::c_void;
358 self.count.add_ref();
359 return ::windows_core::HRESULT(0);
360 }
361 }
362 }
363}
364
365/// Generates the `T::into_outer` function. This function is part of how we construct a
366/// `ComObject<T>` from a `T`.
367fn gen_into_outer(inputs: &ImplementInputs) -> syn::ImplItem {
368 let generics = &inputs.generics;
369 let impl_ident = &inputs.impl_ident;
370
371 let mut initializers = quote! {
372 identity: &#impl_ident::#generics::VTABLE_IDENTITY,
373 };
374
375 for interface_chain in inputs.interface_chains.iter() {
376 let vtbl_field_ident = &interface_chain.field_ident;
377 let vtable_const_ident = &interface_chain.vtable_const_ident;
378
379 initializers.extend(quote_spanned! {
380 interface_chain.implement.span =>
381 #vtbl_field_ident: &#impl_ident::#generics::#vtable_const_ident,
382 });
383 }
384
385 // If the type is generic then into_outer() cannot be a const fn.
386 let maybe_const = if inputs.is_generic {
387 quote!()
388 } else {
389 quote!(const)
390 };
391
392 parse_quote! {
393 // This constructs an "outer" object. This should only be used by the implementation
394 // of the outer object, never by application code.
395 //
396 // The callers of this function (`into_static` and `into_object`) are both responsible
397 // for maintaining one of our invariants: Application code never has an owned instance
398 // of the outer (implementation) type. into_static() maintains this invariant by
399 // returning a wrapped StaticComObject value, which owns its contents but never gives
400 // application code a way to mutably access its contents. This prevents the refcount
401 // shearing problem.
402 //
403 // TODO: Make it impossible for app code to call this function, by placing it in a
404 // module and marking this as private to the module.
405 #[inline(always)]
406 #maybe_const fn into_outer(self) -> #impl_ident::#generics {
407 #impl_ident::#generics {
408 #initializers
409 count: ::windows_core::imp::WeakRefCount::new(),
410 this: self,
411 }
412 }
413 }
414}
415
416/// Generates the `T::into_static` function. This function is part of how we construct a
417/// `StaticComObject<T>` from a `T`.
418fn gen_into_static(inputs: &ImplementInputs) -> syn::ImplItem {
419 assert!(!inputs.is_generic);
420 parse_quote! {
421 /// This converts a partially-constructed COM object (in the sense that it contains
422 /// application state but does not yet have vtable and reference count constructed)
423 /// into a `StaticComObject`. This allows the COM object to be stored in static
424 /// (global) variables.
425 pub const fn into_static(self) -> ::windows_core::StaticComObject<Self> {
426 ::windows_core::StaticComObject::from_outer(self.into_outer())
427 }
428 }
429}
430
431/// Generates `From`-based conversions.
432///
433/// These conversions convert from the user's type `T` to `ComObject<T>` or to an interface
434/// implemented by `T`. These conversions are shorthand for calling `ComObject::new(value)`.
435///
436/// We can only generate conversions from `T` to the roots of each interface chain. We can't
437/// generate `From` conversions from `T` to an interface that is inherited by an interface chain,
438/// because this proc macro does not have access to any information about the inheritance chain
439/// of interfaces that are referenced.
440///
441/// For example:
442///
443/// ```rust,ignore
444/// #[implement(IFoo3)]
445/// struct MyType;
446/// ```
447///
448/// If `IFoo3` inherits from `IFoo2`, then this code will _not_ generate a conversion for `IFoo2`.
449/// However, user code can still do this:
450///
451/// ```rust,ignore
452/// let ifoo2 = IFoo3::from(MyType).into();
453/// ```
454///
455/// This works because the `IFoo3` type has an `Into` impl for `IFoo2`.
456fn gen_impl_from(inputs: &ImplementInputs) -> Vec<syn::Item> {
457 let mut items = Vec::new();
458
459 let original_ident = &inputs.original_type.ident;
460 let generics = &inputs.generics;
461 let constraints = &inputs.constraints;
462
463 items.push(parse_quote! {
464 impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IUnknown where #constraints {
465 #[inline(always)]
466 fn from(this: #original_ident::#generics) -> Self {
467 let com_object = ::windows_core::ComObject::new(this);
468 com_object.into_interface()
469 }
470 }
471 });
472
473 items.push(parse_quote! {
474 impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IInspectable where #constraints {
475 #[inline(always)]
476 fn from(this: #original_ident::#generics) -> Self {
477 let com_object = ::windows_core::ComObject::new(this);
478 com_object.into_interface()
479 }
480 }
481 });
482
483 for interface_chain in inputs.interface_chains.iter() {
484 let interface_ident = interface_chain.implement.to_ident();
485
486 items.push(parse_quote_spanned! {
487 interface_chain.implement.span =>
488 impl #generics ::core::convert::From<#original_ident::#generics> for #interface_ident where #constraints {
489 #[inline(always)]
490 fn from(this: #original_ident::#generics) -> Self {
491 let com_object = ::windows_core::ComObject::new(this);
492 com_object.into_interface()
493 }
494 }
495 });
496 }
497
498 items
499}
500
501/// Generates the `ComObjectInterface` implementation for each interface chain.
502///
503/// Each of these `impl` blocks says "this COM object implements this COM interface".
504/// It allows the `ComObject` type to do conversions from the `ComObject` to `IFoo` instances,
505/// _without_ doing a `QueryInterface` call.
506fn gen_impl_com_object_interfaces(inputs: &ImplementInputs) -> Vec<syn::Item> {
507 let mut items = Vec::new();
508
509 let generics = &inputs.generics;
510 let constraints = &inputs.constraints;
511 let impl_ident = &inputs.impl_ident;
512
513 items.push(parse_quote! {
514 impl #generics ::windows_core::ComObjectInterface<::windows_core::IUnknown> for #impl_ident::#generics where #constraints {
515 #[inline(always)]
516 fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IUnknown> {
517 unsafe {
518 let interface_ptr = &self.identity;
519 ::core::mem::transmute(interface_ptr)
520 }
521 }
522 }
523 });
524
525 items.push(parse_quote! {
526 impl #generics ::windows_core::ComObjectInterface<::windows_core::IInspectable> for #impl_ident::#generics where #constraints {
527 #[inline(always)]
528 fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IInspectable> {
529 unsafe {
530 let interface_ptr = &self.identity;
531 ::core::mem::transmute(interface_ptr)
532 }
533 }
534 }
535 });
536
537 for interface_chain in inputs.interface_chains.iter() {
538 let chain_field = &interface_chain.field_ident;
539 let interface_ident = interface_chain.implement.to_ident();
540
541 items.push(parse_quote_spanned! {
542 interface_chain.implement.span =>
543 #[allow(clippy::needless_lifetimes)]
544 impl #generics ::windows_core::ComObjectInterface<#interface_ident> for #impl_ident::#generics where #constraints {
545 #[inline(always)]
546 fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, #interface_ident> {
547 unsafe {
548 ::core::mem::transmute(&self.#chain_field)
549 }
550 }
551 }
552 });
553 }
554
555 items
556}
557
558/// Generates the implementation of the `AsImpl` trait for a given interface chain.
559fn gen_impl_as_impl(
560 inputs: &ImplementInputs,
561 interface_chain: &InterfaceChain,
562 interface_chain_index: usize,
563) -> syn::Item {
564 let generics = &inputs.generics;
565 let constraints = &inputs.constraints;
566 let interface_ident = interface_chain.implement.to_ident();
567 let original_ident = &inputs.original_type.ident;
568 let impl_ident = &inputs.impl_ident;
569
570 parse_quote_spanned! {
571 interface_chain.implement.span =>
572 impl #generics ::windows_core::AsImpl<#original_ident::#generics> for #interface_ident where #constraints {
573 // SAFETY: the offset is guaranteed to be in bounds, and the implementation struct
574 // is guaranteed to live at least as long as `self`.
575 #[inline(always)]
576 unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> {
577 unsafe {
578 let this = ::windows_core::Interface::as_raw(self);
579 // Subtract away the vtable offset plus 1, for the `identity` field, to get
580 // to the impl struct which contains that original implementation type.
581 let this = (this as *mut *mut ::core::ffi::c_void).sub(1 + #interface_chain_index) as *mut #impl_ident::#generics;
582 ::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics)
583 }
584 }
585 }
586 }
587}
588