]> git.proxmox.com Git - rustc.git/blob - vendor/windows-bindgen/src/rust/implements.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / windows-bindgen / src / rust / implements.rs
1 use super::*;
2
3 pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream {
4 if writer.reader.type_def_kind(def) != TypeKind::Interface || (!writer.implement && writer.reader.has_attribute(def, "ExclusiveToAttribute")) {
5 return quote! {};
6 }
7
8 let generics = &type_def_generics(writer.reader, def);
9 let type_ident = to_ident(writer.reader.type_def_name(def));
10 let impl_ident = type_ident.join("_Impl");
11 let vtbl_ident = type_ident.join("_Vtbl");
12 let implvtbl_ident = impl_ident.join("Vtbl");
13 let constraints = writer.generic_constraints(generics);
14 let generic_names = writer.generic_names(generics);
15 let named_phantoms = writer.generic_named_phantoms(generics);
16 let cfg = type_def_cfg_impl(writer.reader, def, generics);
17 let doc = writer.cfg_doc(&cfg);
18 let features = writer.cfg_features(&cfg);
19 let mut requires = quote! {};
20 let type_ident = quote! { #type_ident<#generic_names> };
21 let vtables = type_def_vtables(writer.reader, def);
22 let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown));
23
24 fn gen_required_trait(writer: &Writer, def: TypeDef, generics: &[Type]) -> TokenStream {
25 let name = writer.type_def_name_imp(def, generics, "_Impl");
26 quote! {
27 + #name
28 }
29 }
30
31 let mut matches = quote! { iid == &<#type_ident as ::windows_core::ComInterface>::IID };
32
33 if let Some(Type::TypeDef(def, _)) = vtables.last() {
34 requires.combine(&gen_required_trait(writer, *def, &[]))
35 }
36
37 for def in &vtables {
38 if let Type::TypeDef(def, generics) = def {
39 let name = writer.type_def_name(*def, generics);
40
41 matches.combine(&quote! {
42 || iid == &<#name as ::windows_core::ComInterface>::IID
43 })
44 }
45 }
46
47 if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) {
48 // TODO: this awkward wrapping of TypeDefs needs fixing
49 for interface in type_interfaces(writer.reader, &Type::TypeDef(def, generics.to_vec())) {
50 if let Type::TypeDef(def, generics) = interface.ty {
51 requires.combine(&gen_required_trait(writer, def, &generics));
52 }
53 }
54 }
55
56 let runtime_name = writer.runtime_name_trait(def, generics, &type_ident, &constraints, &features);
57
58 let mut method_names = MethodNames::new();
59 method_names.add_vtable_types(writer, def);
60
61 let method_traits = writer.reader.type_def_methods(def).map(|method| {
62 let name = method_names.add(writer, method);
63
64 let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generics);
65
66 let signature_tokens = writer.impl_signature(def, &signature);
67 quote! { fn #name #signature_tokens; }
68 });
69
70 let mut method_names = MethodNames::new();
71 method_names.add_vtable_types(writer, def);
72
73 let method_impls = writer.reader.type_def_methods(def).map(|method| {
74 let name = method_names.add(writer, method);
75 let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generics);
76 let vtbl_signature = writer.vtbl_signature(def, generics, &signature);
77
78 let invoke_upcall = if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { winrt_methods::gen_upcall(writer, &signature, quote! { this.#name }) } else { com_methods::gen_upcall(writer, &signature, quote! { this.#name }) };
79
80 if has_unknown_base {
81 quote! {
82 unsafe extern "system" fn #name<#constraints Identity: ::windows_core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature {
83 // offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation
84 let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
85 let this = (*this).get_impl();
86 #invoke_upcall
87 }
88 }
89 } else {
90 quote! {
91 unsafe extern "system" fn #name<Impl: #impl_ident> #vtbl_signature {
92 let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows_core::ScopedHeap;
93 let this = &*((*this).this as *const Impl);
94 #invoke_upcall
95 }
96 }
97 }
98 });
99
100 let mut methods = quote! {};
101
102 match vtables.last() {
103 Some(Type::IUnknown) => methods.combine(&quote! { base__: ::windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }),
104 Some(Type::IInspectable) => methods.combine(&quote! { base__: ::windows_core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }),
105 Some(Type::TypeDef(def, generics)) => {
106 let name = writer.type_def_name_imp(*def, generics, "_Vtbl");
107 if has_unknown_base {
108 methods.combine(&quote! { base__: #name::new::<Identity, Impl, OFFSET>(), });
109 } else {
110 methods.combine(&quote! { base__: #name::new::<Impl>(), });
111 }
112 }
113 _ => {}
114 }
115
116 let mut method_names = MethodNames::new();
117 method_names.add_vtable_types(writer, def);
118
119 for method in writer.reader.type_def_methods(def) {
120 let name = method_names.add(writer, method);
121 if has_unknown_base {
122 methods.combine(&quote! { #name: #name::<#generic_names Identity, Impl, OFFSET>, });
123 } else {
124 methods.combine(&quote! { #name: #name::<Impl>, });
125 }
126 }
127
128 if has_unknown_base {
129 quote! {
130 #doc
131 #features
132 pub trait #impl_ident<#generic_names> : Sized #requires where #constraints {
133 #(#method_traits)*
134 }
135 #runtime_name
136 #features
137 impl<#constraints> #vtbl_ident<#generic_names> {
138 pub const fn new<Identity: ::windows_core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> {
139 #(#method_impls)*
140 Self{
141 #methods
142 #(#named_phantoms)*
143 }
144 }
145 pub fn matches(iid: &::windows_core::GUID) -> bool {
146 #matches
147 }
148 }
149 }
150 } else {
151 quote! {
152 #doc
153 #features
154 pub trait #impl_ident : Sized #requires {
155 #(#method_traits)*
156 }
157 #features
158 impl #vtbl_ident {
159 pub const fn new<Impl: #impl_ident>() -> #vtbl_ident {
160 #(#method_impls)*
161 Self{
162 #methods
163 #(#named_phantoms)*
164 }
165 }
166 }
167 #[doc(hidden)]
168 #features
169 struct #implvtbl_ident<T: #impl_ident> (::std::marker::PhantomData<T>);
170 #features
171 impl<T: #impl_ident> #implvtbl_ident<T> {
172 const VTABLE: #vtbl_ident = #vtbl_ident::new::<T>();
173 }
174 #features
175 impl #type_ident {
176 pub fn new<'a, T: #impl_ident>(this: &'a T) -> ::windows_core::ScopedInterface<'a, Self> {
177 let this = ::windows_core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
178 let this = ::std::mem::ManuallyDrop::new(::std::boxed::Box::new(this));
179 unsafe { ::windows_core::ScopedInterface::new(::std::mem::transmute(&this.vtable)) }
180 }
181 }
182 }
183 }
184 }