1use super::*;
2
3// This is WinRT methods only
4#[derive(Clone, Debug, PartialEq, Eq)]
5pub struct Method {
6 pub def: MethodDef,
7 pub signature: Signature,
8 pub dependencies: TypeMap,
9}
10
11impl Method {
12 pub fn new(def: MethodDef, generics: &[Type]) -> Self {
13 let signature = def.signature("", generics);
14
15 let mut dependencies = TypeMap::new();
16 signature.dependencies(&mut dependencies);
17
18 Self {
19 def,
20 signature,
21 dependencies,
22 }
23 }
24
25 pub fn write_upcall(&self, inner: TokenStream, this: bool) -> TokenStream {
26 let noexcept = self.def.has_attribute("NoExceptionAttribute");
27
28 let invoke_args = self.signature
29 .params
30 .iter()
31 .map(|param| {
32 let name = to_ident(&param.1.name().to_lowercase());
33 let abi_size_name: TokenStream = format!("{}_array_size", param.1.name().to_lowercase()).into();
34
35 if param.1.flags().contains(ParamAttributes::In) {
36 if param.0.is_winrt_array() {
37 quote! { core::slice::from_raw_parts(core::mem::transmute_copy(&#name), #abi_size_name as usize) }
38 } else if param.0.is_primitive() {
39 quote! { #name }
40 } else if param.0.is_const_ref() || param.0.is_interface() {
41 quote! { core::mem::transmute_copy(&#name) }
42 } else {
43 quote! { core::mem::transmute(&#name) }
44 }
45 } else if param.0.is_winrt_array() {
46 quote! { core::slice::from_raw_parts_mut(core::mem::transmute_copy(&#name), #abi_size_name as usize) }
47 } else if param.0.is_winrt_array_ref() {
48 quote! { windows_core::ArrayProxy::from_raw_parts(core::mem::transmute_copy(&#name), #abi_size_name).as_array() }
49 } else {
50 quote! { core::mem::transmute_copy(&#name) }
51 }
52 });
53
54 let this = if this {
55 quote! { this, }
56 } else {
57 quote! {}
58 };
59
60 match &self.signature.return_type.0 {
61 Type::Void => {
62 if noexcept {
63 quote! {
64 #inner(#this #(#invoke_args,)*);
65 windows_core::HRESULT(0)
66 }
67 } else {
68 quote! {
69 #inner(#this #(#invoke_args,)*).into()
70 }
71 }
72 }
73 _ if self.signature.return_type.0.is_winrt_array() => {
74 if noexcept {
75 quote! {
76 let ok__ = #inner(#this #(#invoke_args,)*);
77 let (ok_data__, ok_data_len__) = ok__.into_abi();
78 result__.write(core::mem::transmute(ok_data__));
79 result_size__.write(ok_data_len__);
80 windows_core::HRESULT(0)
81 }
82 } else {
83 quote! {
84 match #inner(#this #(#invoke_args,)*) {
85 Ok(ok__) => {
86 let (ok_data__, ok_data_len__) = ok__.into_abi();
87 // use `ptr::write` since `result` could be uninitialized
88 result__.write(core::mem::transmute(ok_data__));
89 result_size__.write(ok_data_len__);
90 windows_core::HRESULT(0)
91 }
92 Err(err) => err.into()
93 }
94 }
95 }
96 }
97 _ => {
98 let forget = if self.signature.return_type.0.is_copyable() {
99 quote! {}
100 } else {
101 quote! { core::mem::forget(ok__); }
102 };
103
104 if noexcept {
105 quote! {
106 let ok__ = #inner(#this #(#invoke_args,)*);
107 // use `ptr::write` since `result` could be uninitialized
108 result__.write(core::mem::transmute_copy(&ok__));
109 #forget
110 windows_core::HRESULT(0)
111 }
112 } else {
113 quote! {
114 match #inner(#this #(#invoke_args,)*) {
115 Ok(ok__) => {
116 // use `ptr::write` since `result` could be uninitialized
117 result__.write(core::mem::transmute_copy(&ok__));
118 #forget
119 windows_core::HRESULT(0)
120 }
121 Err(err) => err.into()
122 }
123 }
124 }
125 }
126 }
127 }
128
129 pub fn write_impl_signature(
130 &self,
131 writer: &Writer,
132 named_params: bool,
133 has_this: bool,
134 ) -> TokenStream {
135 let noexcept = self.def.has_attribute("NoExceptionAttribute");
136
137 let params = self.signature.params.iter().map(|p| {
138 let default_type = p.0.write_default(writer);
139
140 let sig = if p.1.flags().contains(ParamAttributes::In) {
141 if p.0.is_winrt_array() {
142 quote! { &[#default_type] }
143 } else if p.0.is_primitive() {
144 quote! { #default_type }
145 } else if p.0.is_interface() {
146 let type_name = p.0.write_name(writer);
147 quote! { windows_core::Ref<'_, #type_name> }
148 } else {
149 quote! { &#default_type }
150 }
151 } else if p.0.is_winrt_array() {
152 quote! { &mut [#default_type] }
153 } else if p.0.is_winrt_array_ref() {
154 let kind = p.0.write_name(writer);
155 quote! { &mut windows_core::Array<#kind> }
156 } else if p.0.is_interface() {
157 let type_name = p.0.write_name(writer);
158 quote! { windows_core::OutRef<'_, #type_name> }
159 } else {
160 quote! { &mut #default_type }
161 };
162
163 if named_params {
164 let name = to_ident(p.1.name());
165 quote! { #name: #sig }
166 } else {
167 sig
168 }
169 });
170
171 let return_type_tokens = if self.signature.return_type.0 == Type::Void {
172 quote! { () }
173 } else {
174 let tokens = self.signature.return_type.0.write_name(writer);
175
176 if self.signature.return_type.0.is_winrt_array() {
177 quote! { windows_core::Array<#tokens> }
178 } else {
179 tokens
180 }
181 };
182
183 let return_type_tokens = if noexcept {
184 if self.signature.return_type.0.is_interface() {
185 quote! { -> Option<#return_type_tokens> }
186 } else if self.signature.return_type.0 == Type::Void {
187 quote! {}
188 } else {
189 quote! { -> #return_type_tokens }
190 }
191 } else {
192 quote! { -> windows_core::Result<#return_type_tokens> }
193 };
194
195 if has_this {
196 quote! {
197 (&self, #(#params),*) #return_type_tokens
198 }
199 } else {
200 quote! {
201 (#(#params),*) #return_type_tokens
202 }
203 }
204 }
205
206 pub fn write_abi(&self, writer: &Writer, named_params: bool) -> TokenStream {
207 let args = self.signature.params.iter().map(|param| {
208 let name = to_ident(&param.1.name().to_lowercase());
209 let abi = param.0.write_abi(writer);
210 let abi_size_name: TokenStream = format!("{}_array_size", name.as_str()).into();
211
212 if param.1.flags().contains(ParamAttributes::In) {
213 if param.0.is_winrt_array() {
214 if named_params {
215 quote! { #abi_size_name: u32, #name: *const #abi }
216 } else {
217 quote! { u32, *const #abi }
218 }
219 } else if param.0.is_const_ref() {
220 if named_params {
221 quote! { #name: &#abi }
222 } else {
223 quote! { &#abi }
224 }
225 } else if named_params {
226 quote! { #name: #abi }
227 } else {
228 quote! { #abi }
229 }
230 } else if param.0.is_winrt_array() {
231 if named_params {
232 quote! { #abi_size_name: u32, #name: *mut #abi }
233 } else {
234 quote! { u32, *mut #abi }
235 }
236 } else if param.0.is_winrt_array_ref() {
237 if named_params {
238 quote! { #abi_size_name: *mut u32, #name: *mut *mut #abi }
239 } else {
240 quote! { *mut u32, *mut *mut #abi }
241 }
242 } else if named_params {
243 quote! { #name: *mut #abi }
244 } else {
245 quote! { *mut #abi }
246 }
247 });
248
249 let return_arg = match &self.signature.return_type.0 {
250 Type::Void => quote! {},
251 Type::Array(ty) => {
252 let ty = ty.write_abi(writer);
253 if named_params {
254 quote! { result_size__: *mut u32, result__: *mut *mut #ty }
255 } else {
256 quote! { *mut u32, *mut *mut #ty }
257 }
258 }
259 ty => {
260 let ty = ty.write_abi(writer);
261 if named_params {
262 quote! { result__: *mut #ty }
263 } else {
264 quote! { *mut #ty }
265 }
266 }
267 };
268
269 if named_params {
270 quote! {
271 this: *mut core::ffi::c_void, #(#args,)* #return_arg
272 }
273 } else {
274 quote! {
275 *mut core::ffi::c_void, #(#args,)* #return_arg
276 }
277 }
278 }
279
280 pub fn write(
281 &self,
282 writer: &Writer,
283 interface: Option<&Interface>,
284 kind: InterfaceKind,
285 method_names: &mut MethodNames,
286 virtual_names: &mut MethodNames,
287 ) -> TokenStream {
288 let params = if kind == InterfaceKind::Composable {
289 &self.signature.params[..self.signature.params.len() - 2]
290 } else {
291 &self.signature.params
292 };
293
294 let name = if kind == InterfaceKind::Composable && params.is_empty() {
295 quote!(new)
296 } else {
297 method_names.add(self.def)
298 };
299
300 let args = {
301 let args = params.iter().map(|param|{
302 let name = to_ident(&param.1.name().to_lowercase());
303
304 if param.1.flags().contains(ParamAttributes::In) {
305 if param.0.is_winrt_array() {
306 if param.0.is_copyable() {
307 quote! { #name.len().try_into().unwrap(), #name.as_ptr() }
308 } else {
309 quote! { #name.len().try_into().unwrap(), core::mem::transmute(#name.as_ptr()) }
310 }
311 } else if param.0.is_convertible() {
312 quote! { #name.param().abi() }
313 } else if param.0.is_copyable() {
314 if param.0.is_const_ref() {
315 quote! { &#name }
316 } else {
317 quote! { #name }
318 }
319 } else {
320 quote! { core::mem::transmute_copy(#name) }
321 }
322 } else if param.0.is_winrt_array() {
323 if param.0.is_copyable() {
324 quote! { #name.len().try_into().unwrap(), #name.as_mut_ptr() }
325 } else {
326 quote! { #name.len().try_into().unwrap(), core::mem::transmute_copy(&#name) }
327 }
328 } else if param.0.is_winrt_array_ref() {
329 quote! { #name.set_abi_len(), #name as *mut _ as _ }
330 } else if param.0.is_copyable() {
331 quote! { #name }
332 } else {
333 quote! { #name as *mut _ as _ }
334 }
335 });
336
337 let return_arg = match &self.signature.return_type.0 {
338 Type::Void => quote! {},
339 ty => {
340 if ty.is_winrt_array() {
341 let ty = ty.write_name(writer);
342 quote! { windows_core::Array::<#ty>::set_abi_len(core::mem::transmute(&mut result__)), result__.as_mut_ptr() as *mut _ as _ }
343 } else {
344 quote! { &mut result__ }
345 }
346 }
347 };
348
349 if kind == InterfaceKind::Composable {
350 quote! {
351 #(#args,)* core::ptr::null_mut(), &mut core::ptr::null_mut(), #return_arg
352 }
353 } else {
354 quote! {
355 #(#args,)* #return_arg
356 }
357 }
358 };
359
360 let generics = params
361 .iter()
362 .enumerate()
363 .filter_map(|(position, (ty, def))| {
364 if is_convertible(ty, *def) {
365 let name: TokenStream = format!("P{position}").into();
366 Some(name)
367 } else {
368 None
369 }
370 });
371
372 let where_clause = {
373 let constraints: Vec<_> = params
374 .iter()
375 .enumerate()
376 .filter_map(|(position, (ty, def))| {
377 if is_convertible(ty, *def) {
378 let name: TokenStream = format!("P{position}").into();
379 let ty = ty.write_name(writer);
380
381 Some(quote! { #name: windows_core::Param<#ty>, })
382 } else {
383 None
384 }
385 })
386 .collect();
387
388 if constraints.is_empty() {
389 quote! {}
390 } else {
391 quote! { where #(#constraints)* }
392 }
393 };
394
395 let params = params.iter().enumerate().map(|(position, param)| {
396 let name = to_ident(&param.1.name().to_lowercase());
397 let kind = param.0.write_name(writer);
398 let default_type = param.0.write_default(writer);
399
400 if param.1.flags().contains(ParamAttributes::In) {
401 if param.0.is_winrt_array() {
402 quote! { #name: &[#default_type], }
403 } else if is_convertible(&param.0, param.1) {
404 let kind: TokenStream = format!("P{position}").into();
405 quote! { #name: #kind, }
406 } else if param.0.is_copyable() {
407 quote! { #name: #kind, }
408 } else {
409 quote! { #name: &#kind, }
410 }
411 } else if param.0.is_winrt_array() {
412 quote! { #name: &mut [#default_type], }
413 } else if param.0.is_winrt_array_ref() {
414 quote! { #name: &mut windows_core::Array<#kind>, }
415 } else {
416 quote! { #name: &mut #default_type, }
417 }
418 });
419
420 let return_type = match &self.signature.return_type.0 {
421 Type::Void => quote! { () },
422 _ => {
423 let tokens = self.signature.return_type.0.write_name(writer);
424 if self.signature.return_type.0.is_winrt_array() {
425 quote! { windows_core::Array<#tokens> }
426 } else {
427 quote! { #tokens }
428 }
429 }
430 };
431
432 let noexcept = self.def.has_attribute("NoExceptionAttribute");
433
434 let return_type = if noexcept {
435 if self.signature.return_type.0.is_interface() {
436 quote! { -> Option<#return_type> }
437 } else if self.signature.return_type.0 == Type::Void {
438 quote! {}
439 } else {
440 quote! { -> #return_type }
441 }
442 } else {
443 quote! { -> windows_core::Result<#return_type> }
444 };
445
446 let vname = virtual_names.add(self.def);
447 let vcall = quote! { (windows_core::Interface::vtable(this).#vname)(windows_core::Interface::as_raw(this), #args) };
448
449 let vcall = match &self.signature.return_type.0 {
450 Type::Void => {
451 if noexcept {
452 quote! {
453 let hresult__ = #vcall;
454 debug_assert!(hresult__.0 == 0);
455 }
456 } else {
457 quote! {
458 #vcall.ok()
459 }
460 }
461 }
462 _ if self.signature.return_type.0.is_winrt_array() => {
463 if noexcept {
464 quote! {
465 let mut result__ = core::mem::MaybeUninit::zeroed();
466 let hresult__ = #vcall;
467 debug_assert!(hresult__.0 == 0);
468 result__.assume_init()
469 }
470 } else {
471 quote! {
472 let mut result__ = core::mem::MaybeUninit::zeroed();
473 #vcall
474 .map(|| result__.assume_init())
475 }
476 }
477 }
478 _ => {
479 if noexcept {
480 if self.signature.return_type.0.is_copyable() {
481 quote! {
482 let mut result__ = core::mem::zeroed();
483 let hresult__ = #vcall;
484 debug_assert!(hresult__.0 == 0);
485 result__ }
486 } else {
487 quote! {
488 let mut result__ = core::mem::zeroed();
489 let hresult__ = #vcall;
490 debug_assert!(hresult__.0 == 0);
491 core::mem::transmute(result__) }
492 }
493 } else if !self.signature.return_type.0.is_convertible() {
494 if self.signature.return_type.0.is_primitive() {
495 quote! {
496 let mut result__ = core::mem::zeroed();
497 #vcall
498 .map(||result__) }
499 } else {
500 quote! {
501 let mut result__ = core::mem::zeroed();
502 #vcall
503 .map(||core::mem::transmute(result__)) }
504 }
505 } else {
506 quote! { let mut result__ = core::mem::zeroed();
507 #vcall.and_then(|| windows_core::Type::from_abi(result__)) }
508 }
509 }
510 };
511
512 match kind {
513 InterfaceKind::Default => quote! {
514 pub fn #name<#(#generics,)*>(&self, #(#params)*) #return_type #where_clause {
515 let this = self;
516 unsafe {
517 #vcall
518 }
519 }
520 },
521 InterfaceKind::None | InterfaceKind::Base => {
522 let unwrap = if noexcept {
523 quote! { .unwrap() }
524 } else {
525 quote! { ? }
526 };
527
528 let interface_name = interface.unwrap().write_name(writer);
529
530 quote! {
531 pub fn #name<#(#generics,)*>(&self, #(#params)*) #return_type #where_clause {
532 let this = &windows_core::Interface::cast::<#interface_name>(self)#unwrap;
533 unsafe {
534 #vcall
535 }
536 }
537 }
538 }
539 InterfaceKind::Static | InterfaceKind::Composable => {
540 let interface_name = to_ident(interface.unwrap().def.name());
541
542 quote! {
543 pub fn #name<#(#generics,)*>(#(#params)*) #return_type #where_clause {
544 Self::#interface_name(|this| unsafe { #vcall })
545 }
546 }
547 }
548 }
549 }
550}
551
552fn is_convertible(ty: &Type, param: Param) -> bool {
553 param.flags().contains(ParamAttributes::In) && ty.is_convertible()
554}
555