1use super::*;
2
3#[derive(Clone, Debug, PartialEq, Eq, Hash)]
4pub struct CppFn {
5 pub namespace: &'static str,
6 pub method: MethodDef,
7}
8
9impl Ord for CppFn {
10 fn cmp(&self, other: &Self) -> Ordering {
11 (self.method.name(), self.method).cmp(&(other.method.name(), other.method))
12 }
13}
14
15impl PartialOrd for CppFn {
16 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
17 Some(self.cmp(other))
18 }
19}
20
21impl CppFn {
22 pub fn type_name(&self) -> TypeName {
23 TypeName(self.namespace, self.method.name())
24 }
25
26 pub fn write_name(&self, writer: &Writer) -> TokenStream {
27 self.type_name().write(writer, &[])
28 }
29
30 pub fn write_link(&self, writer: &Writer, underlying_types: bool) -> TokenStream {
31 let name = self.method.name();
32 let library = self.method.module_name().to_lowercase();
33 let impl_map = self.method.impl_map().unwrap();
34 let mut symbol = Some(impl_map.import_name());
35
36 if symbol == Some(name) {
37 symbol = None;
38 }
39
40 let name = to_ident(self.method.name());
41 let impl_flags = impl_map.flags();
42
43 let abi = if impl_flags.contains(PInvokeAttributes::CallConvPlatformapi) {
44 "system"
45 } else if impl_flags.contains(PInvokeAttributes::CallConvCdecl) {
46 "cdecl"
47 } else {
48 panic!()
49 };
50
51 let signature = self.method.signature(self.namespace, &[]);
52
53 let params = signature.params.iter().map(|(ty, param)| {
54 let name = to_ident(&param.name().to_lowercase());
55 let ty = if underlying_types {
56 ty.underlying_type().write_abi(writer)
57 } else {
58 ty.write_abi(writer)
59 };
60 quote! { #name: #ty }
61 });
62
63 let return_sig = writer.write_return_sig(self.method, &signature, underlying_types);
64
65 let vararg =
66 if writer.config.sys && signature.call_flags.contains(MethodCallAttributes::VARARG) {
67 quote! { , ... }
68 } else {
69 quote! {}
70 };
71
72 link_fmt(quote! {
73 windows_targets::link!(#library #abi #symbol fn #name(#(#params),* #vararg) #return_sig);
74 })
75 }
76
77 pub fn write(&self, writer: &Writer) -> TokenStream {
78 let name = to_ident(self.method.name());
79 let signature = self.method.signature(self.namespace, &[]);
80 let mut dependencies = TypeMap::new();
81
82 if writer.config.package {
83 self.dependencies(&mut dependencies);
84 }
85
86 let link = self.write_link(writer, false);
87 let cfg = writer.write_cfg(self.method, self.namespace, &dependencies, false);
88 let window_long = self.write_window_long();
89 if writer.config.sys {
90 return quote! {
91 #cfg
92 #link
93 #window_long
94 };
95 }
96
97 let method = CppMethod::new(self.method, self.namespace);
98 let args = method.write_args();
99 let params = method.write_params(writer);
100 let generics = method.write_generics();
101 let abi_return_type = method.write_return(writer);
102
103 let wrapper = match method.return_hint {
104 ReturnHint::Query(..) => {
105 let where_clause = method.write_where(writer, true);
106
107 quote! {
108 #cfg
109 #[inline]
110 pub unsafe fn #name<#generics T>(#params) -> windows_core::Result<T> #where_clause {
111 #link
112 let mut result__ = core::ptr::null_mut();
113 unsafe { #name(#args).and_then(||windows_core::Type::from_abi(result__)) }
114 }
115 }
116 }
117 ReturnHint::QueryOptional(..) => {
118 let where_clause = method.write_where(writer, true);
119
120 quote! {
121 #cfg
122 #[inline]
123 pub unsafe fn #name<#generics T>(#params result__: *mut Option<T>) -> windows_core::Result<()> #where_clause {
124 #link
125 unsafe { #name(#args).ok() }
126 }
127 }
128 }
129 ReturnHint::ResultValue => {
130 let where_clause = method.write_where(writer, false);
131 let return_type = signature.params[signature.params.len() - 1].0.deref();
132
133 let map = if !return_type.is_interface() {
134 quote! { map(||core::mem::transmute(result__)) }
135 } else {
136 quote! { and_then(||windows_core::Type::from_abi(result__)) }
137 };
138
139 let return_type = return_type.write_name(writer);
140
141 quote! {
142 #cfg
143 #[inline]
144 pub unsafe fn #name<#generics>(#params) -> windows_core::Result<#return_type> #where_clause {
145 #link
146 unsafe {
147 let mut result__ = core::mem::zeroed();
148 #name(#args).#map
149 }
150 }
151 }
152 }
153 ReturnHint::ResultVoid => {
154 let where_clause = method.write_where(writer, false);
155
156 quote! {
157 #cfg
158 #[inline]
159 pub unsafe fn #name<#generics>(#params) -> windows_core::Result<()> #where_clause {
160 #link
161 unsafe { #name(#args).ok() }
162 }
163 }
164 }
165 ReturnHint::ReturnValue => {
166 let where_clause = method.write_where(writer, false);
167
168 let return_type = method.signature.params[method.signature.params.len() - 1]
169 .0
170 .deref();
171
172 if return_type.is_interface() {
173 let return_type = return_type.write_name(writer);
174
175 quote! {
176 #cfg
177 #[inline]
178 pub unsafe fn #name<#generics>(#params) -> windows_core::Result<#return_type> #where_clause {
179 #link
180 unsafe {
181 let mut result__ = core::mem::zeroed();
182 #name(#args);
183 windows_core::Type::from_abi(result__)
184 }
185 }
186 }
187 } else {
188 let map = if return_type.is_copyable() {
189 quote! { result__ }
190 } else {
191 quote! { core::mem::transmute(result__) }
192 };
193
194 let where_clause = method.write_where(writer, false);
195 let return_type = return_type.write_name(writer);
196
197 quote! {
198 #cfg
199 #[inline]
200 pub unsafe fn #name<#generics>(#params) -> #return_type #where_clause {
201 #link
202 unsafe {
203 let mut result__ = core::mem::zeroed();
204 #name(#args);
205 #map
206 }
207 }
208 }
209 }
210 }
211 ReturnHint::ReturnStruct | ReturnHint::None => {
212 let where_clause = method.write_where(writer, false);
213
214 if method.handle_last_error() {
215 let return_type = signature.return_type.0.write_name(writer);
216
217 quote! {
218 #cfg
219 #[inline]
220 pub unsafe fn #name<#generics>(#params) -> windows_core::Result<#return_type> #where_clause {
221 #link
222 let result__ = unsafe { #name(#args) };
223 (!result__.is_invalid()).then_some(result__).ok_or_else(windows_core::Error::from_win32)
224 }
225 }
226 } else {
227 quote! {
228 #cfg
229 #[inline]
230 pub unsafe fn #name<#generics>(#params) #abi_return_type #where_clause {
231 #link
232 unsafe { #name(#args) }
233 }
234 }
235 }
236 }
237 };
238
239 quote! {
240 #wrapper
241 #window_long
242 }
243 }
244
245 fn write_window_long(&self) -> TokenStream {
246 match self.method.name() {
247 "GetWindowLongPtrA" => quote! {
248 #[cfg(target_pointer_width = "32")]
249 pub use GetWindowLongA as GetWindowLongPtrA;
250 },
251 "GetWindowLongPtrW" => quote! {
252 #[cfg(target_pointer_width = "32")]
253 pub use GetWindowLongW as GetWindowLongPtrW;
254 },
255 "SetWindowLongPtrA" => quote! {
256 #[cfg(target_pointer_width = "32")]
257 pub use SetWindowLongA as SetWindowLongPtrA;
258 },
259 "SetWindowLongPtrW" => quote! {
260 #[cfg(target_pointer_width = "32")]
261 pub use SetWindowLongW as SetWindowLongPtrW;
262 },
263 _ => quote! {},
264 }
265 }
266
267 pub fn dependencies(&self, dependencies: &mut TypeMap) {
268 self.method
269 .signature(self.namespace, &[])
270 .dependencies(dependencies);
271
272 let dependency = match self.method.name() {
273 "GetWindowLongPtrA" => Some("GetWindowLongA"),
274 "GetWindowLongPtrW" => Some("GetWindowLongW"),
275 "SetWindowLongPtrA" => Some("SetWindowLongA"),
276 "SetWindowLongPtrW" => Some("SetWindowLongW"),
277 _ => None,
278 };
279
280 if let Some(dependency) = dependency {
281 self.method
282 .reader()
283 .unwrap_full_name(self.namespace, dependency)
284 .dependencies(dependencies);
285 }
286 }
287}
288
289impl Writer {
290 pub fn write_return_sig(
291 &self,
292 method: MethodDef,
293 signature: &Signature,
294 underlying_types: bool,
295 ) -> TokenStream {
296 match &signature.return_type.0 {
297 Type::Void => {
298 if method.has_attribute("DoesNotReturnAttribute") {
299 quote! { -> ! }
300 } else {
301 quote! {}
302 }
303 }
304 ty => {
305 let ty = if underlying_types {
306 ty.underlying_type().write_default(self)
307 } else {
308 ty.write_default(self)
309 };
310
311 quote! { -> #ty }
312 }
313 }
314 }
315}
316
317fn link_fmt(tokens: TokenStream) -> TokenStream {
318 let mut tokens: String = tokens.0.replacen(pat:" ! ( ", to:"!(", count:1);
319 tokens = tokens.replacen(pat:" ( ", to:"(", count:1);
320 tokens = tokens.replace(from:" , ", to:", ");
321 tokens = tokens.replace(from:" )", to:")");
322 tokens.into()
323}
324