1 | use super::*; |
2 | |
3 | mod class; |
4 | mod cpp_const; |
5 | mod cpp_delegate; |
6 | mod cpp_enum; |
7 | mod cpp_fn; |
8 | mod cpp_interface; |
9 | mod cpp_method; |
10 | mod cpp_struct; |
11 | mod delegate; |
12 | mod r#enum; |
13 | mod interface; |
14 | mod method; |
15 | mod r#struct; |
16 | |
17 | pub use class::*; |
18 | pub use cpp_const::*; |
19 | pub use cpp_delegate::*; |
20 | pub use cpp_enum::*; |
21 | pub use cpp_fn::*; |
22 | pub use cpp_interface::*; |
23 | pub use cpp_method::*; |
24 | pub use cpp_struct::*; |
25 | pub use delegate::*; |
26 | pub use interface::*; |
27 | pub use method::*; |
28 | pub use r#enum::*; |
29 | pub use r#struct::*; |
30 | |
31 | #[derive (Clone, Debug, PartialEq, Eq, Hash)] |
32 | pub enum Type { |
33 | CppFn(CppFn), |
34 | Class(Class), |
35 | Interface(Interface), |
36 | CppInterface(CppInterface), |
37 | Delegate(Delegate), |
38 | CppDelegate(CppDelegate), |
39 | Enum(Enum), |
40 | CppEnum(CppEnum), |
41 | Struct(Struct), |
42 | CppStruct(CppStruct), |
43 | CppConst(CppConst), |
44 | |
45 | Param(&'static str), |
46 | PtrMut(Box<Self>, usize), |
47 | PtrConst(Box<Self>, usize), |
48 | ArrayFixed(Box<Self>, usize), |
49 | Array(Box<Self>), |
50 | ArrayRef(Box<Self>), |
51 | ConstRef(Box<Self>), |
52 | PrimitiveOrEnum(Box<Self>, Box<Self>), |
53 | |
54 | Void, |
55 | Bool, |
56 | Char, |
57 | I8, |
58 | U8, |
59 | I16, |
60 | U16, |
61 | I32, |
62 | U32, |
63 | I64, |
64 | U64, |
65 | F32, |
66 | F64, |
67 | ISize, |
68 | USize, |
69 | String, |
70 | Object, |
71 | Type, |
72 | |
73 | PSTR, |
74 | PCSTR, |
75 | PWSTR, |
76 | PCWSTR, |
77 | GUID, |
78 | HRESULT, |
79 | IUnknown, |
80 | BSTR, |
81 | } |
82 | |
83 | impl Ord for Type { |
84 | fn cmp(&self, other: &Self) -> Ordering { |
85 | self.sort_key().cmp(&(other.sort_key())) |
86 | } |
87 | } |
88 | |
89 | impl PartialOrd for Type { |
90 | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { |
91 | Some(self.cmp(other)) |
92 | } |
93 | } |
94 | |
95 | #[derive (PartialEq)] |
96 | pub enum Remap { |
97 | Type(Type), |
98 | Name(TypeName), |
99 | None, |
100 | } |
101 | |
102 | impl Type { |
103 | fn sort_key(&self) -> (bool, TypeName, i32, i32) { |
104 | // This sorts types as follows: |
105 | // 1. functions are placed first |
106 | // 2. type name |
107 | // 3. type namespace |
108 | // 4. architecture |
109 | // 5. overloaded types |
110 | |
111 | let kind = match self { |
112 | Self::CppFn(..) => 0, |
113 | Self::Class(..) => 1, |
114 | Self::Interface(..) => 2, |
115 | Self::CppInterface(..) => 3, |
116 | Self::Delegate(..) => 4, |
117 | Self::CppDelegate(..) => 5, |
118 | Self::Enum(..) => 6, |
119 | Self::CppEnum(..) => 7, |
120 | Self::Struct(..) => 8, |
121 | Self::CppStruct(..) => 9, |
122 | Self::CppConst(..) => 10, |
123 | _ => -1, |
124 | }; |
125 | |
126 | let arches = match self { |
127 | Self::CppFn(ty) => ty.method.arches(), |
128 | Self::CppStruct(ty) => ty.def.arches(), |
129 | Self::CppDelegate(ty) => ty.def.arches(), |
130 | _ => 0, |
131 | }; |
132 | |
133 | (kind != 0, self.type_name(), arches, kind) |
134 | } |
135 | |
136 | fn is_intrinsic(&self) -> bool { |
137 | matches!( |
138 | self, |
139 | Self::Param(..) |
140 | | Self::Void |
141 | | Self::Bool |
142 | | Self::Char |
143 | | Self::I8 |
144 | | Self::U8 |
145 | | Self::I16 |
146 | | Self::U16 |
147 | | Self::I32 |
148 | | Self::U32 |
149 | | Self::I64 |
150 | | Self::U64 |
151 | | Self::F32 |
152 | | Self::F64 |
153 | | Self::ISize |
154 | | Self::USize |
155 | ) |
156 | } |
157 | |
158 | pub fn remap(type_name: TypeName) -> Remap { |
159 | match type_name { |
160 | TypeName::GUID => Remap::Type(Self::GUID), |
161 | TypeName::HResult => Remap::Type(Self::HRESULT), |
162 | TypeName::HRESULT => Remap::Type(Self::HRESULT), |
163 | TypeName::PSTR => Remap::Type(Self::PSTR), |
164 | TypeName::PWSTR => Remap::Type(Self::PWSTR), |
165 | TypeName::HSTRING => Remap::Type(Self::String), |
166 | TypeName::BSTR => Remap::Type(Self::BSTR), |
167 | TypeName::IInspectable => Remap::Type(Self::Object), |
168 | TypeName::CHAR => Remap::Type(Self::I8), |
169 | TypeName::BOOLEAN => Remap::Type(Self::Bool), |
170 | TypeName::IUnknown => Remap::Type(Self::IUnknown), |
171 | TypeName::Type => Remap::Type(Self::Type), |
172 | TypeName::EventRegistrationToken => Remap::Type(Type::I64), |
173 | |
174 | TypeName::D2D_MATRIX_3X2_F => Remap::Name(TypeName::Matrix3x2), |
175 | TypeName::D3DMATRIX => Remap::Name(TypeName::Matrix4x4), |
176 | |
177 | _ => Remap::None, |
178 | } |
179 | } |
180 | |
181 | pub fn from_element_type(code: usize) -> Option<Self> { |
182 | match code as u8 { |
183 | ELEMENT_TYPE_VOID => Some(Self::Void), |
184 | ELEMENT_TYPE_BOOLEAN => Some(Self::Bool), |
185 | ELEMENT_TYPE_CHAR => Some(Self::Char), |
186 | ELEMENT_TYPE_I1 => Some(Self::I8), |
187 | ELEMENT_TYPE_U1 => Some(Self::U8), |
188 | ELEMENT_TYPE_I2 => Some(Self::I16), |
189 | ELEMENT_TYPE_U2 => Some(Self::U16), |
190 | ELEMENT_TYPE_I4 => Some(Self::I32), |
191 | ELEMENT_TYPE_U4 => Some(Self::U32), |
192 | ELEMENT_TYPE_I8 => Some(Self::I64), |
193 | ELEMENT_TYPE_U8 => Some(Self::U64), |
194 | ELEMENT_TYPE_R4 => Some(Self::F32), |
195 | ELEMENT_TYPE_R8 => Some(Self::F64), |
196 | ELEMENT_TYPE_I => Some(Self::ISize), |
197 | ELEMENT_TYPE_U => Some(Self::USize), |
198 | ELEMENT_TYPE_STRING => Some(Self::String), |
199 | ELEMENT_TYPE_OBJECT => Some(Self::Object), |
200 | _ => None, |
201 | } |
202 | } |
203 | |
204 | pub fn from_ref(code: TypeDefOrRef, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
205 | if let TypeDefOrRef::TypeSpec(def) = code { |
206 | let mut blob = def.blob(0); |
207 | return Self::from_blob_impl(&mut blob, None, generics); |
208 | } |
209 | |
210 | let mut code_name = code.type_name(); |
211 | |
212 | match Self::remap(code_name) { |
213 | Remap::Type(ty) => return ty, |
214 | Remap::Name(type_name) => { |
215 | code_name = type_name; |
216 | } |
217 | Remap::None => {} |
218 | } |
219 | |
220 | if let Some(outer) = enclosing { |
221 | if code_name.namespace().is_empty() { |
222 | return Type::CppStruct(outer.nested[code_name.name()].clone()); |
223 | } |
224 | } |
225 | |
226 | code.reader() |
227 | .unwrap_full_name(code_name.namespace(), code_name.name()) |
228 | } |
229 | |
230 | pub fn from_blob(blob: &mut Blob, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
231 | // Used by WinRT to indicate that a struct input parameter is passed by reference rather than by value on the ABI. |
232 | let is_const = blob.read_modifiers().iter().any(|def| { |
233 | let type_name = def.type_name(); |
234 | type_name == TypeName::IsConst |
235 | }); |
236 | |
237 | // Used by WinRT to indicate an output parameter, but there are other ways to determine this direction so here |
238 | // it is only used to distinguish between slices and heap-allocated arrays. |
239 | let is_ref = blob.try_read(ELEMENT_TYPE_BYREF as usize); |
240 | |
241 | if blob.try_read(ELEMENT_TYPE_VOID as usize) { |
242 | return Self::Void; |
243 | } |
244 | |
245 | let is_array = blob.try_read(ELEMENT_TYPE_SZARRAY as usize); // Used by WinRT to indicate an array |
246 | |
247 | let mut pointers = 0; |
248 | |
249 | while blob.try_read(ELEMENT_TYPE_PTR as usize) { |
250 | pointers += 1; |
251 | } |
252 | |
253 | let kind = Self::from_blob_impl(blob, enclosing, generics); |
254 | |
255 | if pointers > 0 { |
256 | Self::PtrMut(Box::new(kind), pointers) |
257 | } else if is_const { |
258 | Self::ConstRef(Box::new(kind)) |
259 | } else if is_array { |
260 | if is_ref { |
261 | Self::ArrayRef(Box::new(kind)) |
262 | } else { |
263 | Self::Array(Box::new(kind)) |
264 | } |
265 | } else { |
266 | kind |
267 | } |
268 | } |
269 | |
270 | fn from_blob_impl(blob: &mut Blob, enclosing: Option<&CppStruct>, generics: &[Self]) -> Self { |
271 | let code = blob.read_usize(); |
272 | |
273 | if let Some(code) = Self::from_element_type(code) { |
274 | return code; |
275 | } |
276 | |
277 | match code as u8 { |
278 | ELEMENT_TYPE_VALUETYPE | ELEMENT_TYPE_CLASS => { |
279 | Self::from_ref(blob.decode(), enclosing, generics) |
280 | } |
281 | ELEMENT_TYPE_VAR => generics |
282 | .get(blob.read_usize()) |
283 | .unwrap_or(&Self::Void) |
284 | .clone(), |
285 | ELEMENT_TYPE_ARRAY => { |
286 | let kind = Self::from_blob(blob, enclosing, generics); |
287 | let _rank = blob.read_usize(); |
288 | let _count = blob.read_usize(); |
289 | let bounds = blob.read_usize(); |
290 | Self::ArrayFixed(Box::new(kind), bounds) |
291 | } |
292 | ELEMENT_TYPE_GENERICINST => { |
293 | blob.read_usize(); // ELEMENT_TYPE_VALUETYPE or ELEMENT_TYPE_CLASS |
294 | |
295 | let code = blob.decode::<TypeDefOrRef>(); |
296 | let code_name = code.type_name(); |
297 | |
298 | let mut ty = blob |
299 | .reader() |
300 | .unwrap_full_name(code_name.namespace(), code_name.name()); |
301 | |
302 | let mut item_generics = vec![]; |
303 | |
304 | for _ in 0..blob.read_usize() { |
305 | item_generics.push(Self::from_blob_impl(blob, enclosing, generics)); |
306 | } |
307 | |
308 | ty.set_generics(item_generics); |
309 | ty |
310 | } |
311 | rest => panic!(" {rest:?}" ), |
312 | } |
313 | } |
314 | |
315 | pub fn to_const_type(&self) -> Self { |
316 | match self { |
317 | Self::PtrMut(ty, pointers) => Self::PtrMut(Box::new(ty.to_const_type()), *pointers), |
318 | Self::PtrConst(ty, pointers) => Self::PtrConst(Box::new(ty.to_const_type()), *pointers), |
319 | Self::PSTR => Self::PCSTR, |
320 | Self::PWSTR => Self::PCWSTR, |
321 | _ => self.clone(), |
322 | } |
323 | } |
324 | |
325 | pub fn to_const_ptr(&self) -> Self { |
326 | match self { |
327 | Self::PtrMut(ty, pointers) => Self::PtrConst(ty.clone(), *pointers), |
328 | _ => self.clone(), |
329 | } |
330 | } |
331 | |
332 | pub fn deref(&self) -> Self { |
333 | match self { |
334 | Self::PtrConst(ty, 1) | Self::PtrMut(ty, 1) => { |
335 | if **ty == Self::Void { |
336 | Self::U8 |
337 | } else { |
338 | *ty.clone() |
339 | } |
340 | } |
341 | Self::PtrConst(ty, pointers) => Self::PtrConst(ty.clone(), pointers - 1), |
342 | Self::PtrMut(ty, pointers) => Self::PtrMut(ty.clone(), pointers - 1), |
343 | Self::PSTR | Self::PCSTR => Self::U8, |
344 | Self::PWSTR | Self::PCWSTR => Self::U16, |
345 | _ => self.clone(), |
346 | } |
347 | } |
348 | |
349 | pub fn is_interface(&self) -> bool { |
350 | matches!( |
351 | self, |
352 | Self::Class(_) |
353 | | Self::Interface(_) |
354 | | Self::Delegate(_) |
355 | | Self::CppInterface(_) |
356 | | Self::IUnknown |
357 | | Self::Object |
358 | ) |
359 | } |
360 | |
361 | pub fn write_name(&self, writer: &Writer) -> TokenStream { |
362 | match self { |
363 | Self::Void => quote! { core::ffi::c_void }, |
364 | Self::Bool => quote! { bool }, |
365 | Self::Char => quote! { u16 }, |
366 | Self::I8 => quote! { i8 }, |
367 | Self::U8 => quote! { u8 }, |
368 | Self::I16 => quote! { i16 }, |
369 | Self::U16 => quote! { u16 }, |
370 | Self::I32 => quote! { i32 }, |
371 | Self::U32 => quote! { u32 }, |
372 | Self::I64 => quote! { i64 }, |
373 | Self::U64 => quote! { u64 }, |
374 | Self::F32 => quote! { f32 }, |
375 | Self::F64 => quote! { f64 }, |
376 | Self::ISize => quote! { isize }, |
377 | Self::USize => quote! { usize }, |
378 | Self::BSTR => { |
379 | let name = writer.write_core(); |
380 | quote! { #name BSTR } |
381 | } |
382 | Self::IUnknown => { |
383 | if writer.config.sys { |
384 | quote! { *mut core::ffi::c_void } |
385 | } else { |
386 | let name = writer.write_core(); |
387 | quote! { #name IUnknown } |
388 | } |
389 | } |
390 | Self::GUID => { |
391 | let name = writer.write_core(); |
392 | quote! { #name GUID } |
393 | } |
394 | Self::HRESULT => { |
395 | let name = writer.write_core(); |
396 | quote! { #name HRESULT } |
397 | } |
398 | Self::String => { |
399 | let name = writer.write_core(); |
400 | quote! { #name HSTRING } |
401 | } |
402 | Self::Object => { |
403 | if writer.config.sys { |
404 | quote! { *mut core::ffi::c_void } |
405 | } else { |
406 | let name = writer.write_core(); |
407 | quote! { #name IInspectable } |
408 | } |
409 | } |
410 | Self::PSTR => { |
411 | let name = writer.write_core(); |
412 | quote! { #name PSTR } |
413 | } |
414 | Self::PCSTR => { |
415 | let name = writer.write_core(); |
416 | quote! { #name PCSTR } |
417 | } |
418 | Self::PWSTR => { |
419 | let name = writer.write_core(); |
420 | quote! { #name PWSTR } |
421 | } |
422 | Self::PCWSTR => { |
423 | let name = writer.write_core(); |
424 | quote! { #name PCWSTR } |
425 | } |
426 | Self::CppInterface(ty) => ty.write_name(writer), |
427 | Self::Struct(ty) => ty.write_name(writer), |
428 | Self::Enum(ty) => ty.write_name(writer), |
429 | Self::Interface(ty) => ty.write_name(writer), |
430 | Self::CppStruct(ty) => ty.write_name(writer), |
431 | Self::CppEnum(ty) => ty.write_name(writer), |
432 | Self::CppFn(ty) => ty.write_name(writer), |
433 | Self::CppConst(ty) => ty.write_name(writer), |
434 | Self::CppDelegate(ty) => ty.write_name(writer), |
435 | Self::Delegate(ty) => ty.write_name(writer), |
436 | Self::Class(ty) => ty.write_name(writer), |
437 | Self::Param(param) => to_ident(param), |
438 | Self::PtrMut(ty, pointers) => { |
439 | let pointers = write_ptr_mut(*pointers); |
440 | let ty = ty.write_default(writer); |
441 | quote! { #pointers #ty } |
442 | } |
443 | Self::PtrConst(ty, pointers) => { |
444 | let pointers = write_ptr_const(*pointers); |
445 | let ty = ty.write_default(writer); |
446 | quote! { #pointers #ty } |
447 | } |
448 | Self::ArrayFixed(ty, len) => { |
449 | let name = ty.write_default(writer); |
450 | let len = Literal::usize_unsuffixed(*len); |
451 | quote! { [#name; #len] } |
452 | } |
453 | Self::Array(ty) => ty.write_name(writer), |
454 | Self::ArrayRef(ty) => ty.write_name(writer), |
455 | Self::ConstRef(ty) => ty.write_name(writer), |
456 | Self::PrimitiveOrEnum(primitive, ty) => { |
457 | if writer.config.sys { |
458 | primitive.write_name(writer) |
459 | } else { |
460 | ty.write_name(writer) |
461 | } |
462 | } |
463 | rest => panic!(" {rest:?}" ), |
464 | } |
465 | } |
466 | |
467 | pub fn write_default(&self, writer: &Writer) -> TokenStream { |
468 | if let Self::Array(ty) = self { |
469 | ty.write_default(writer) |
470 | } else { |
471 | let tokens = self.write_name(writer); |
472 | |
473 | if matches!(self, Self::Param(_)) { |
474 | quote! { <#tokens as windows_core::Type<#tokens>>::Default } |
475 | } else if self.is_interface() && !writer.config.sys { |
476 | quote! { Option<#tokens> } |
477 | } else { |
478 | tokens |
479 | } |
480 | } |
481 | } |
482 | |
483 | pub fn write_impl_name(&self, writer: &Writer) -> TokenStream { |
484 | match self { |
485 | Self::IUnknown | Self::Object => { |
486 | let name = writer.write_core(); |
487 | quote! { #name IUnknownImpl } |
488 | } |
489 | Self::CppInterface(ty) => ty.write_impl_name(writer), |
490 | Self::Interface(ty) => ty.write_impl_name(writer), |
491 | rest => panic!(" {rest:?}" ), |
492 | } |
493 | } |
494 | |
495 | pub fn write_abi(&self, writer: &Writer) -> TokenStream { |
496 | if writer.config.sys { |
497 | return self.write_default(writer); |
498 | } |
499 | |
500 | match self { |
501 | Self::IUnknown |
502 | | Self::Object |
503 | | Self::Delegate(_) |
504 | | Self::Class(_) |
505 | | Self::CppInterface(_) |
506 | | Self::Interface(_) |
507 | | Self::String |
508 | | Self::BSTR => quote! { *mut core::ffi::c_void }, |
509 | Self::ArrayFixed(ty, len) => { |
510 | let name = ty.write_abi(writer); |
511 | let len = Literal::usize_unsuffixed(*len); |
512 | quote! { [#name; #len] } |
513 | } |
514 | Self::Param(name) => { |
515 | let name = to_ident(name); |
516 | quote! { windows_core::AbiType<#name> } |
517 | } |
518 | Self::Struct(ty) => { |
519 | let name = self.write_name(writer); |
520 | if ty.is_copyable() { |
521 | name |
522 | } else { |
523 | quote! { core::mem::MaybeUninit<#name> } |
524 | } |
525 | } |
526 | Self::PtrMut(ty, pointers) => { |
527 | let ty = ty.write_abi(writer); |
528 | let pointers = write_ptr_mut(*pointers); |
529 | quote! { #pointers #ty } |
530 | } |
531 | Self::PtrConst(ty, pointers) => { |
532 | let ty = ty.write_abi(writer); |
533 | let pointers = write_ptr_const(*pointers); |
534 | quote! { #pointers #ty } |
535 | } |
536 | Self::PrimitiveOrEnum(ty, _) => ty.write_name(writer), |
537 | ty => ty.write_name(writer), |
538 | } |
539 | } |
540 | |
541 | pub fn runtime_signature(&self) -> String { |
542 | match self { |
543 | Self::Bool => "b1" .to_string(), |
544 | Self::Char => "c2" .to_string(), |
545 | Self::I8 => "i1" .to_string(), |
546 | Self::U8 => "u1" .to_string(), |
547 | Self::I16 => "i2" .to_string(), |
548 | Self::U16 => "u2" .to_string(), |
549 | Self::I32 => "i4" .to_string(), |
550 | Self::U32 => "u4" .to_string(), |
551 | Self::I64 => "i8" .to_string(), |
552 | Self::U64 => "u8" .to_string(), |
553 | Self::F32 => "f4" .to_string(), |
554 | Self::F64 => "f8" .to_string(), |
555 | Self::ISize => "is" .to_string(), |
556 | Self::USize => "us" .to_string(), |
557 | Self::String => "string" .to_string(), |
558 | Self::Object => "cinterface(IInspectable)" .to_string(), |
559 | Self::GUID => "g16" .to_string(), |
560 | Self::HRESULT => "struct(Windows.Foundation.HResult;i4)" .to_string(), |
561 | Self::Class(ty) => ty.runtime_signature(), |
562 | Self::Delegate(ty) => ty.runtime_signature(), |
563 | Self::Enum(ty) => ty.runtime_signature(), |
564 | Self::Interface(ty) => ty.runtime_signature(), |
565 | Self::Struct(ty) => ty.runtime_signature(), |
566 | rest => panic!(" {rest:?}" ), |
567 | } |
568 | } |
569 | |
570 | pub fn split_generic(&self) -> (Type, Vec<Type>) { |
571 | match self { |
572 | Self::Interface(ty) if !ty.generics.is_empty() => { |
573 | let base = ty |
574 | .def |
575 | .reader() |
576 | .unwrap_full_name(ty.def.namespace(), ty.def.name()); |
577 | (base, ty.generics.clone()) |
578 | } |
579 | Self::Delegate(ty) if !ty.generics.is_empty() => { |
580 | let base = ty |
581 | .def |
582 | .reader() |
583 | .unwrap_full_name(ty.def.namespace(), ty.def.name()); |
584 | (base, ty.generics.clone()) |
585 | } |
586 | _ => (self.clone(), vec![]), |
587 | } |
588 | } |
589 | |
590 | pub fn decay(&self) -> &Self { |
591 | match self { |
592 | Type::PtrMut(ty, _) => ty, |
593 | Type::PtrConst(ty, _) => ty, |
594 | Type::ArrayFixed(ty, _) => ty.decay(), |
595 | Type::Array(ty) => ty, |
596 | Type::ArrayRef(ty) => ty, |
597 | Type::ConstRef(ty) => ty, |
598 | Type::PrimitiveOrEnum(_, ty) => ty, |
599 | _ => self, |
600 | } |
601 | } |
602 | |
603 | pub fn dependencies(&self, dependencies: &mut TypeMap) { |
604 | let ty = self.decay(); |
605 | |
606 | if ty.is_intrinsic() { |
607 | return; |
608 | } |
609 | |
610 | let mut nested = false; |
611 | |
612 | if let Self::CppStruct(ty) = ty { |
613 | if ty.def.namespace().is_empty() { |
614 | nested = true; |
615 | } |
616 | } |
617 | |
618 | let (ty, generics) = ty.split_generic(); |
619 | |
620 | for ty in generics { |
621 | ty.dependencies(dependencies); |
622 | } |
623 | |
624 | if !nested && !dependencies.insert(ty.clone()) { |
625 | return; |
626 | } |
627 | |
628 | if let Some(multi) = match &ty { |
629 | Self::CppStruct(ty) => Some( |
630 | ty.def |
631 | .reader() |
632 | .with_full_name(ty.def.namespace(), ty.def.name()), |
633 | ), |
634 | Self::CppFn(ty) => Some( |
635 | ty.method |
636 | .reader() |
637 | .with_full_name(ty.namespace, ty.method.name()), |
638 | ), |
639 | _ => None, |
640 | } { |
641 | multi.for_each(|multi| { |
642 | if ty != multi { |
643 | multi.dependencies(dependencies) |
644 | } |
645 | }); |
646 | } |
647 | |
648 | match &ty { |
649 | Self::Class(ty) => ty.dependencies(dependencies), |
650 | Self::Delegate(ty) => ty.dependencies(dependencies), |
651 | Self::Enum(..) => {} |
652 | Self::Interface(ty) => ty.dependencies(dependencies), |
653 | Self::Struct(ty) => ty.dependencies(dependencies), |
654 | Self::CppConst(ty) => ty.dependencies(dependencies), |
655 | Self::CppDelegate(ty) => ty.dependencies(dependencies), |
656 | Self::CppFn(ty) => ty.dependencies(dependencies), |
657 | Self::CppInterface(ty) => ty.dependencies(dependencies), |
658 | Self::CppStruct(ty) => ty.dependencies(dependencies), |
659 | Self::CppEnum(ty) => ty.dependencies(dependencies), |
660 | |
661 | Self::IUnknown => { |
662 | Self::GUID.dependencies(dependencies); |
663 | Self::HRESULT.dependencies(dependencies); |
664 | } |
665 | |
666 | Self::Object => { |
667 | Self::IUnknown.dependencies(dependencies); |
668 | } |
669 | |
670 | _ => {} |
671 | } |
672 | } |
673 | |
674 | pub fn is_exclusive(&self) -> bool { |
675 | match self { |
676 | Self::Interface(ty) => ty.def.has_attribute("ExclusiveToAttribute" ), |
677 | _ => false, |
678 | } |
679 | } |
680 | |
681 | pub fn is_winrt_array(&self) -> bool { |
682 | matches!(self, Self::Array(_)) |
683 | } |
684 | |
685 | pub fn is_winrt_array_ref(&self) -> bool { |
686 | matches!(self, Self::ArrayRef(_)) |
687 | } |
688 | |
689 | pub fn is_async(&self) -> bool { |
690 | match self { |
691 | Self::Interface(ty) => ty.def.is_async(), |
692 | _ => false, |
693 | } |
694 | } |
695 | |
696 | pub fn is_copyable(&self) -> bool { |
697 | match self { |
698 | Self::Struct(ty) => ty.is_copyable(), |
699 | Self::CppStruct(ty) => ty.is_copyable(), |
700 | Self::Enum(_) => true, |
701 | Self::CppEnum(_) => true, |
702 | Self::CppDelegate(_) => true, |
703 | |
704 | Self::Interface(..) | Self::CppInterface(..) | Self::Class(..) | Self::Delegate(..) => { |
705 | false |
706 | } |
707 | |
708 | Self::String | Self::BSTR | Self::Object | Self::IUnknown | Self::Param(_) => false, |
709 | Self::ArrayFixed(ty, _) => ty.is_copyable(), |
710 | Self::Array(ty) => ty.is_copyable(), |
711 | _ => true, |
712 | } |
713 | } |
714 | |
715 | pub fn is_dropped(&self) -> bool { |
716 | match self { |
717 | Self::Struct(ty) => !ty.is_copyable(), |
718 | Self::CppInterface(..) => true, |
719 | Self::String | Self::BSTR | Self::Object | Self::IUnknown => true, |
720 | Self::ArrayFixed(ty, _) => ty.is_dropped(), |
721 | _ => false, |
722 | } |
723 | } |
724 | |
725 | pub fn is_convertible(&self) -> bool { |
726 | matches!( |
727 | self, |
728 | Self::Delegate(..) |
729 | | Self::Interface(..) |
730 | | Self::Class(..) |
731 | | Self::CppInterface(..) |
732 | | Self::PCSTR |
733 | | Self::PCWSTR |
734 | | Self::Object |
735 | | Self::IUnknown |
736 | | Self::Param(_) |
737 | ) |
738 | } |
739 | |
740 | pub fn is_const_ref(&self) -> bool { |
741 | matches!(self, Self::ConstRef(_)) |
742 | } |
743 | |
744 | pub fn is_primitive(&self) -> bool { |
745 | match self { |
746 | Self::Enum(_) | Self::CppEnum(_) | Self::CppDelegate(_) => true, |
747 | Self::CppStruct(ty) => ty.is_handle(), |
748 | Self::Bool |
749 | | Self::Char |
750 | | Self::I8 |
751 | | Self::U8 |
752 | | Self::I16 |
753 | | Self::U16 |
754 | | Self::I32 |
755 | | Self::U32 |
756 | | Self::I64 |
757 | | Self::U64 |
758 | | Self::F32 |
759 | | Self::F64 |
760 | | Self::ISize |
761 | | Self::USize |
762 | | Self::HRESULT |
763 | | Self::PtrConst(_, _) |
764 | | Self::PtrMut(_, _) => true, |
765 | _ => false, |
766 | } |
767 | } |
768 | |
769 | pub fn is_unsigned(&self) -> bool { |
770 | matches!( |
771 | self, |
772 | Self::U8 | Self::U16 | Self::U32 | Self::U64 | Self::USize |
773 | ) |
774 | } |
775 | |
776 | pub fn is_pointer(&self) -> bool { |
777 | matches!(self, Self::PtrConst(_, _) | Self::PtrMut(_, _)) |
778 | } |
779 | |
780 | pub fn has_explicit_layout(&self) -> bool { |
781 | match self { |
782 | Self::CppStruct(ty) => ty.has_explicit_layout(), |
783 | Self::ArrayFixed(ty, _) => ty.has_explicit_layout(), |
784 | _ => false, |
785 | } |
786 | } |
787 | |
788 | pub fn has_packing(&self) -> bool { |
789 | match self { |
790 | Self::CppStruct(ty) => ty.has_packing(), |
791 | Self::ArrayFixed(ty, _) => ty.has_packing(), |
792 | _ => false, |
793 | } |
794 | } |
795 | |
796 | pub fn is_byte_size(&self) -> bool { |
797 | match self { |
798 | Self::PtrConst(ty, _) | Self::PtrMut(ty, _) => ty.is_byte_size(), |
799 | Self::I8 | Self::U8 | Self::PSTR | Self::PCSTR => true, |
800 | _ => false, |
801 | } |
802 | } |
803 | |
804 | pub fn is_void(&self) -> bool { |
805 | match self { |
806 | Type::PtrConst(ty, _) | Type::PtrMut(ty, _) => ty.is_void(), |
807 | Type::Void => true, |
808 | _ => false, |
809 | } |
810 | } |
811 | |
812 | pub fn size(&self) -> usize { |
813 | match self { |
814 | Type::I8 | Type::U8 => 1, |
815 | Type::I16 | Type::U16 => 2, |
816 | Type::I64 | Type::U64 | Type::F64 => 8, |
817 | Type::GUID => 16, |
818 | Type::ArrayFixed(ty, len) => ty.size() * len, |
819 | Type::PrimitiveOrEnum(ty, _) => ty.size(), |
820 | Self::CppStruct(ty) => ty.size(), |
821 | Self::Struct(ty) => ty.size(), |
822 | Self::CppEnum(ty) => ty.size(), |
823 | _ => 4, |
824 | } |
825 | } |
826 | |
827 | pub fn align(&self) -> usize { |
828 | match self { |
829 | Type::I8 | Type::U8 => 1, |
830 | Type::I16 | Type::U16 => 2, |
831 | Type::I64 | Type::U64 | Type::F64 => 8, |
832 | Type::ArrayFixed(ty, len) => ty.align() * len, |
833 | Self::CppStruct(ty) => ty.align(), |
834 | Self::Struct(ty) => ty.align(), |
835 | Self::CppEnum(ty) => ty.align(), |
836 | _ => 4, |
837 | } |
838 | } |
839 | |
840 | pub fn underlying_type(&self) -> Self { |
841 | match self { |
842 | Self::Struct(ty) => ty.def.underlying_type(), |
843 | Self::CppEnum(ty) => ty.def.underlying_type(), |
844 | Self::Enum(ty) => ty.def.underlying_type(), |
845 | Self::CppStruct(ty) => ty.def.underlying_type(), |
846 | Self::HRESULT => Type::I32, |
847 | _ => self.clone(), |
848 | } |
849 | } |
850 | } |
851 | |
852 | impl Type { |
853 | fn write_no_deps(&self, writer: &Writer) -> TokenStream { |
854 | if !writer.config.no_core { |
855 | return quote! {}; |
856 | } |
857 | |
858 | match self { |
859 | Self::HRESULT => quote! { pub type HRESULT = i32; }, |
860 | |
861 | Self::PWSTR => quote! { pub type PWSTR = *mut u16; }, |
862 | Self::PCSTR => quote! { pub type PCSTR = *const u8; }, |
863 | Self::PSTR => quote! { pub type PSTR = *mut u8; }, |
864 | Self::PCWSTR => quote! { pub type PCWSTR = *const u16; }, |
865 | Self::BSTR => quote! { pub type BSTR = *const u16; }, |
866 | Self::String => { |
867 | quote! { pub type HSTRING = *mut core::ffi::c_void; } |
868 | } |
869 | Self::GUID => quote! { |
870 | #[repr(C)] |
871 | #[derive(Clone, Copy)] |
872 | pub struct GUID { |
873 | pub data1: u32, |
874 | pub data2: u16, |
875 | pub data3: u16, |
876 | pub data4: [u8; 8], |
877 | } |
878 | impl GUID { |
879 | pub const fn from_u128(uuid: u128) -> Self { |
880 | Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() } |
881 | } |
882 | } |
883 | }, |
884 | Self::IUnknown => quote! { |
885 | pub const IID_IUnknown: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046); |
886 | #[repr(C)] |
887 | pub struct IUnknown_Vtbl { |
888 | pub QueryInterface: unsafe extern "system" fn(this: *mut core::ffi::c_void, iid: *const GUID, interface: *mut *mut core::ffi::c_void) -> HRESULT, |
889 | pub AddRef: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32, |
890 | pub Release: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32, |
891 | } |
892 | }, |
893 | Self::Object => quote! { |
894 | pub const IID_IInspectable: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90); |
895 | #[repr(C)] |
896 | pub struct IInspectable_Vtbl { |
897 | pub base: IUnknown_Vtbl, |
898 | pub GetIids: unsafe extern "system" fn(this: *mut core::ffi::c_void, count: *mut u32, values: *mut *mut GUID) -> HRESULT, |
899 | pub GetRuntimeClassName: unsafe extern "system" fn(this: *mut core::ffi::c_void, value: *mut *mut core::ffi::c_void) -> HRESULT, |
900 | pub GetTrustLevel: unsafe extern "system" fn(this: *mut core::ffi::c_void, value: *mut i32) -> HRESULT, |
901 | } |
902 | }, |
903 | |
904 | _ => quote! {}, |
905 | } |
906 | } |
907 | |
908 | pub fn write(&self, writer: &Writer) -> TokenStream { |
909 | match self { |
910 | Self::Struct(ty) => ty.write(writer), |
911 | Self::Enum(ty) => ty.write(writer), |
912 | Self::Interface(ty) => ty.write(writer), |
913 | Self::CppStruct(ty) => ty.write(writer), |
914 | Self::CppEnum(ty) => ty.write(writer), |
915 | Self::CppFn(ty) => ty.write(writer), |
916 | Self::CppConst(ty) => ty.write(writer), |
917 | Self::CppDelegate(ty) => ty.write(writer), |
918 | Self::Delegate(ty) => ty.write(writer), |
919 | Self::Class(ty) => ty.write(writer), |
920 | Self::CppInterface(ty) => ty.write(writer), |
921 | |
922 | _ => self.write_no_deps(writer), |
923 | } |
924 | } |
925 | |
926 | pub fn set_generics(&mut self, generics: Vec<Type>) { |
927 | match self { |
928 | Self::Interface(ty) => ty.generics = generics, |
929 | Self::Delegate(ty) => ty.generics = generics, |
930 | rest => panic!(" {rest:?}" ), |
931 | } |
932 | } |
933 | |
934 | pub fn type_name(&self) -> TypeName { |
935 | match self { |
936 | Self::Class(ty) => ty.type_name(), |
937 | Self::Delegate(ty) => ty.type_name(), |
938 | Self::Enum(ty) => ty.type_name(), |
939 | Self::Interface(ty) => ty.type_name(), |
940 | Self::Struct(ty) => ty.type_name(), |
941 | Self::CppDelegate(ty) => ty.type_name(), |
942 | Self::CppEnum(ty) => ty.type_name(), |
943 | Self::CppInterface(ty) => ty.type_name(), |
944 | Self::CppStruct(ty) => ty.type_name(), |
945 | Self::CppConst(ty) => ty.type_name(), |
946 | Self::CppFn(ty) => ty.type_name(), |
947 | |
948 | Self::PSTR => TypeName("" , "PSTR" ), |
949 | Self::PCSTR => TypeName("" , "PCSTR" ), |
950 | Self::PWSTR => TypeName("" , "PWSTR" ), |
951 | Self::PCWSTR => TypeName("" , "PCWSTR" ), |
952 | Self::GUID => TypeName("" , "GUID" ), |
953 | Self::HRESULT => TypeName("" , "HRESULT" ), |
954 | Self::IUnknown => TypeName("" , "IUnknown" ), |
955 | Self::BSTR => TypeName("" , "BSTR" ), |
956 | Self::String => TypeName("" , "String" ), |
957 | Self::Object => TypeName("" , "Object" ), |
958 | |
959 | _ => TypeName("" , "" ), |
960 | } |
961 | } |
962 | |
963 | pub fn is_core(&self) -> bool { |
964 | matches!( |
965 | self, |
966 | Self::PSTR |
967 | | Self::PCSTR |
968 | | Self::PWSTR |
969 | | Self::PCWSTR |
970 | | Self::GUID |
971 | | Self::HRESULT |
972 | | Self::IUnknown |
973 | | Self::Object |
974 | | Self::BSTR |
975 | | Self::String |
976 | ) |
977 | } |
978 | } |
979 | |
980 | pub fn interface_signature(def: TypeDef, generics: &[Type]) -> String { |
981 | if generics.is_empty() { |
982 | let guid: GUID = def.guid_attribute().unwrap(); |
983 | format!(" {{{guid}}}" ) |
984 | } else { |
985 | let guid: GUID = def.guid_attribute().unwrap(); |
986 | let mut signature: String = format!("pinterface( {{{guid}}}" ); |
987 | |
988 | for generic: &Type in generics { |
989 | signature.push(ch:';' ); |
990 | signature.push_str(&generic.runtime_signature()) |
991 | } |
992 | |
993 | signature.push(ch:')' ); |
994 | signature |
995 | } |
996 | } |
997 | |
998 | fn write_ptr_mut(pointers: usize) -> TokenStream { |
999 | "*mut " .repeat(pointers).into() |
1000 | } |
1001 | |
1002 | fn write_ptr_const(pointers: usize) -> TokenStream { |
1003 | "*const " .repeat(pointers).into() |
1004 | } |
1005 | |