1use std::collections::*;
2pub use windows_metadata::*;
3
4#[derive(Clone)]
5pub struct Interface {
6 pub ty: Type,
7 pub kind: InterfaceKind,
8}
9
10#[derive(Copy, Clone, PartialEq, Eq)]
11pub enum InterfaceKind {
12 None,
13 Default,
14 Overridable,
15 Static,
16 Base,
17}
18
19#[derive(Copy, Clone, PartialEq, Eq)]
20pub struct QueryPosition {
21 pub object: usize,
22 pub guid: usize,
23}
24
25#[derive(Copy, Clone, PartialEq, Eq)]
26pub enum SignatureKind {
27 Query(QueryPosition),
28 QueryOptional(QueryPosition),
29 ResultValue,
30 ResultVoid,
31 ReturnStruct,
32 ReturnValue,
33 ReturnVoid,
34 PreserveSig,
35}
36
37#[derive(Copy, Clone, Eq, PartialEq)]
38pub enum SignatureParamKind {
39 ArrayFixed(usize),
40 ArrayRelativeLen(usize),
41 ArrayRelativeByteLen(usize),
42 ArrayRelativePtr(usize),
43 TryInto,
44 IntoParam,
45 OptionalPointer,
46 ValueType,
47 Blittable,
48 Other,
49}
50
51pub struct Signature {
52 pub def: MethodDef,
53 pub params: Vec<SignatureParam>,
54 pub return_type: Type,
55 pub call_flags: MethodCallAttributes,
56}
57
58pub struct SignatureParam {
59 pub def: Param,
60 pub ty: Type,
61 pub kind: SignatureParamKind,
62}
63
64#[derive(PartialEq, Eq, Debug)]
65pub enum AsyncKind {
66 None,
67 Action,
68 ActionWithProgress,
69 Operation,
70 OperationWithProgress,
71}
72
73#[derive(Clone, PartialEq, Eq, Default)]
74pub struct Guid(pub u32, pub u16, pub u16, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);
75
76impl Guid {
77 pub fn from_args(args: &[(&str, Value)]) -> Self {
78 fn unwrap_u32(value: &Value) -> u32 {
79 match value {
80 Value::U32(value) => *value,
81 rest => unimplemented!("{rest:?}"),
82 }
83 }
84 fn unwrap_u16(value: &Value) -> u16 {
85 match value {
86 Value::U16(value) => *value,
87 rest => unimplemented!("{rest:?}"),
88 }
89 }
90 fn unwrap_u8(value: &Value) -> u8 {
91 match value {
92 Value::U8(value) => *value,
93 rest => unimplemented!("{rest:?}"),
94 }
95 }
96 Self(unwrap_u32(&args[0].1), unwrap_u16(&args[1].1), unwrap_u16(&args[2].1), unwrap_u8(&args[3].1), unwrap_u8(&args[4].1), unwrap_u8(&args[5].1), unwrap_u8(&args[6].1), unwrap_u8(&args[7].1), unwrap_u8(&args[8].1), unwrap_u8(&args[9].1), unwrap_u8(&args[10].1))
97 }
98
99 pub fn from_string_args(args: &[&str]) -> Self {
100 Self(args[0].parse().unwrap(), args[1].parse().unwrap(), args[2].parse().unwrap(), args[3].parse().unwrap(), args[4].parse().unwrap(), args[5].parse().unwrap(), args[6].parse().unwrap(), args[7].parse().unwrap(), args[8].parse().unwrap(), args[9].parse().unwrap(), args[10].parse().unwrap())
101 }
102}
103
104impl std::fmt::Debug for Guid {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(f, "{:08x?}-{:04x?}-{:04x?}-{:02x?}{:02x?}-{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}", self.0, self.1, self.2, self.3, self.4, self.5, self.6, self.7, self.8, self.9, self.10)
107 }
108}
109
110impl SignatureParamKind {
111 fn is_array(&self) -> bool {
112 matches!(self, Self::ArrayFixed(_) | Self::ArrayRelativeLen(_) | Self::ArrayRelativeByteLen(_) | Self::ArrayRelativePtr(_))
113 }
114}
115
116impl SignatureParam {
117 pub fn is_convertible(&self) -> bool {
118 !self.def.flags().contains(ParamAttributes::Out) && !self.ty.is_winrt_array() && !self.ty.is_pointer() && !self.kind.is_array() && (type_is_borrowed(&self.ty) || type_is_non_exclusive_winrt_interface(&self.ty) || type_is_trivially_convertible(&self.ty))
119 }
120
121 fn is_retval(&self) -> bool {
122 // The Win32 metadata uses `RetValAttribute` to call out retval methods but it is employed
123 // very sparingly, so this heuristic is used to apply the transformation more uniformly.
124 if self.def.has_attribute("RetValAttribute") {
125 return true;
126 }
127 if !self.ty.is_pointer() {
128 return false;
129 }
130 if self.ty.is_void() {
131 return false;
132 }
133 let flags = self.def.flags();
134 if flags.contains(ParamAttributes::In) || !flags.contains(ParamAttributes::Out) || flags.contains(ParamAttributes::Optional) || self.kind.is_array() {
135 return false;
136 }
137 if param_kind(self.def).is_array() {
138 return false;
139 }
140 // If it's bigger than 128 bits, best to pass as a reference.
141 if self.ty.deref().size() > 16 {
142 return false;
143 }
144 // Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid
145 // producing the `Result<Option<T>>` anti-pattern.
146 match self.ty.deref() {
147 Type::TypeDef(def, _) => !type_def_is_callback(def),
148 _ => true,
149 }
150 }
151}
152
153impl Signature {
154 pub fn kind(&self) -> SignatureKind {
155 if self.def.has_attribute("CanReturnMultipleSuccessValuesAttribute") {
156 return SignatureKind::PreserveSig;
157 }
158 match &self.return_type {
159 Type::Void if self.is_retval() => SignatureKind::ReturnValue,
160 Type::Void => SignatureKind::ReturnVoid,
161 Type::HRESULT => {
162 if self.params.len() >= 2 {
163 if let Some((guid, object)) = signature_param_is_query(&self.params) {
164 if self.params[object].def.flags().contains(ParamAttributes::Optional) {
165 return SignatureKind::QueryOptional(QueryPosition { object, guid });
166 } else {
167 return SignatureKind::Query(QueryPosition { object, guid });
168 }
169 }
170 }
171 if self.is_retval() {
172 SignatureKind::ResultValue
173 } else {
174 SignatureKind::ResultVoid
175 }
176 }
177 Type::TypeDef(def, _) if def.type_name() == TypeName::WIN32_ERROR => SignatureKind::ResultVoid,
178 Type::TypeDef(def, _) if def.type_name() == TypeName::BOOL && method_def_last_error(self.def) => SignatureKind::ResultVoid,
179 _ if type_is_struct(&self.return_type) => SignatureKind::ReturnStruct,
180 _ => SignatureKind::PreserveSig,
181 }
182 }
183
184 fn is_retval(&self) -> bool {
185 self.params.last().map_or(false, |param| param.is_retval())
186 && self.params[..self.params.len() - 1].iter().all(|param| {
187 let flags = param.def.flags();
188 !flags.contains(ParamAttributes::Out)
189 })
190 }
191}
192
193pub fn type_def_invoke_method(row: TypeDef) -> MethodDef {
194 row.methods().find(|method| method.name() == "Invoke").expect(msg:"`Invoke` method not found")
195}
196
197pub fn type_def_generics(def: TypeDef) -> Vec<Type> {
198 def.generics().map(Type::GenericParam).collect()
199}
200
201// TODO: namespace should not be required - it's a hack to accomodate Win32 metadata
202// TODO: this is very Rust-specific and Win32-metadata specific with all of its translation. Replace with literal signature parser that just returns slice of types.
203pub fn method_def_signature(namespace: &str, row: MethodDef, generics: &[Type]) -> Signature {
204 let reader = row.reader();
205 let mut blob = row.blob(4);
206 let call_flags = MethodCallAttributes(blob.read_usize() as u8);
207 let _param_count = blob.read_usize();
208 let mut return_type = reader.type_from_blob(&mut blob, None, generics);
209
210 let mut params: Vec<SignatureParam> = row
211 .params()
212 .filter_map(|param| {
213 let param_is_const = param.has_attribute("ConstAttribute");
214 if param.sequence() == 0 {
215 if param_is_const {
216 return_type = return_type.clone().to_const_type();
217 }
218 None
219 } else {
220 let is_output = param.flags().contains(ParamAttributes::Out);
221 let mut ty = reader.type_from_blob(&mut blob, None, generics);
222
223 if let Some(name) = param_or_enum(param) {
224 let def = reader.get_type_def(namespace, &name).next().expect("Enum not found");
225 ty = Type::PrimitiveOrEnum(Box::new(ty), Box::new(Type::TypeDef(def, Vec::new())));
226 }
227
228 if param_is_const || !is_output {
229 ty = ty.to_const_type();
230 }
231 if !is_output {
232 ty = ty.to_const_ptr();
233 }
234 let kind = param_kind(param);
235 Some(SignatureParam { def: param, ty, kind })
236 }
237 })
238 .collect();
239
240 for position in 0..params.len() {
241 // Point len params back to the corresponding ptr params.
242 match params[position].kind {
243 SignatureParamKind::ArrayRelativeLen(relative) | SignatureParamKind::ArrayRelativeByteLen(relative) => {
244 // The len params must be input only.
245 if !params[relative].def.flags().contains(ParamAttributes::Out) && position != relative && !params[relative].ty.is_pointer() {
246 params[relative].kind = SignatureParamKind::ArrayRelativePtr(position);
247 } else {
248 params[position].kind = SignatureParamKind::Other;
249 }
250 }
251 SignatureParamKind::ArrayFixed(_) => {
252 if params[position].def.has_attribute("FreeWithAttribute") {
253 params[position].kind = SignatureParamKind::Other;
254 }
255 }
256 _ => {}
257 }
258 }
259
260 let mut sets = BTreeMap::<usize, Vec<usize>>::new();
261
262 // Finds sets of ptr params pointing at the same len param.
263 for (position, param) in params.iter().enumerate() {
264 match param.kind {
265 SignatureParamKind::ArrayRelativeLen(relative) | SignatureParamKind::ArrayRelativeByteLen(relative) => {
266 sets.entry(relative).or_default().push(position);
267 }
268 _ => {}
269 }
270 }
271
272 // Remove all sets.
273 for (len, ptrs) in sets {
274 if ptrs.len() > 1 {
275 params[len].kind = SignatureParamKind::Other;
276 for ptr in ptrs {
277 params[ptr].kind = SignatureParamKind::Other;
278 }
279 }
280 }
281
282 // Remove any byte arrays that aren't byte-sized types.
283 for position in 0..params.len() {
284 if let SignatureParamKind::ArrayRelativeByteLen(relative) = params[position].kind {
285 if !params[position].ty.is_byte_size() {
286 params[position].kind = SignatureParamKind::Other;
287 params[relative].kind = SignatureParamKind::Other;
288 }
289 }
290 }
291
292 for param in &mut params {
293 if param.kind == SignatureParamKind::Other {
294 if param.is_convertible() {
295 if type_is_non_exclusive_winrt_interface(&param.ty) {
296 param.kind = SignatureParamKind::TryInto;
297 } else {
298 param.kind = SignatureParamKind::IntoParam;
299 }
300 } else {
301 let flags = param.def.flags();
302 if param.ty.is_pointer() && (flags.contains(ParamAttributes::Optional) || param.def.has_attribute("ReservedAttribute")) {
303 param.kind = SignatureParamKind::OptionalPointer;
304 } else if type_is_primitive(&param.ty) && (!param.ty.is_pointer() || type_is_blittable(&param.ty.deref())) {
305 param.kind = SignatureParamKind::ValueType;
306 } else if type_is_blittable(&param.ty) {
307 param.kind = SignatureParamKind::Blittable;
308 }
309 }
310 }
311 }
312
313 Signature { def: row, params, return_type, call_flags }
314}
315
316fn param_kind(row: Param) -> SignatureParamKind {
317 for attribute: Attribute in row.attributes() {
318 match attribute.name() {
319 "NativeArrayInfoAttribute" => {
320 for (_, value: Value) in attribute.args() {
321 match value {
322 Value::I16(value: i16) => return SignatureParamKind::ArrayRelativeLen(value as usize),
323 Value::I32(value: i32) => return SignatureParamKind::ArrayFixed(value as usize),
324 _ => {}
325 }
326 }
327 }
328 "MemorySizeAttribute" => {
329 for (_, value: Value) in attribute.args() {
330 if let Value::I16(value: i16) = value {
331 return SignatureParamKind::ArrayRelativeByteLen(value as usize);
332 }
333 }
334 }
335 _ => {}
336 }
337 }
338 SignatureParamKind::Other
339}
340
341// TODO: this is a terribly broken Win32 metadata attribute - need to get rid of it.
342fn param_or_enum(row: Param) -> Option<String> {
343 row.find_attribute(name:"AssociatedEnumAttribute").and_then(|attribute: Attribute| {
344 for (_, arg: Value) in attribute.args() {
345 if let Value::String(name: String) = arg {
346 return Some(name);
347 }
348 }
349 None
350 })
351}
352
353fn signature_param_is_query(params: &[SignatureParam]) -> Option<(usize, usize)> {
354 if let Some(guid: usize) = params.iter().rposition(|param: &SignatureParam| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !param.def.flags().contains(ParamAttributes::Out)) {
355 if let Some(object: usize) = params.iter().rposition(|param: &SignatureParam| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && param.def.has_attribute(name:"ComOutPtrAttribute")) {
356 return Some((guid, object));
357 }
358 }
359
360 None
361}
362
363fn method_def_last_error(row: MethodDef) -> bool {
364 if let Some(map: ImplMap) = row.impl_map() {
365 map.flags().contains(PInvokeAttributes::SupportsLastError)
366 } else {
367 false
368 }
369}
370
371pub fn type_is_borrowed(ty: &Type) -> bool {
372 match ty {
373 Type::TypeDef(row: &TypeDef, _) => !type_def_is_blittable(*row),
374 Type::BSTR | Type::PCSTR | Type::PCWSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => true,
375 _ => false,
376 }
377}
378
379pub fn type_is_non_exclusive_winrt_interface(ty: &Type) -> bool {
380 match ty {
381 Type::TypeDef(row: &TypeDef, _) => {
382 let flags: TypeAttributes = row.flags();
383 if !flags.contains(TypeAttributes::WindowsRuntime) {
384 false
385 } else {
386 match row.kind() {
387 TypeKind::Interface => !type_def_is_exclusive(*row),
388 TypeKind::Class => row.has_attribute(name:"ComposableAttribute"),
389 _ => false,
390 }
391 }
392 }
393 _ => false,
394 }
395}
396
397fn type_is_trivially_convertible(ty: &Type) -> bool {
398 match ty {
399 Type::TypeDef(row: &TypeDef, _) => match row.kind() {
400 TypeKind::Struct => type_def_is_handle(*row),
401 _ => false,
402 },
403 _ => false,
404 }
405}
406
407fn type_def_is_callback(row: TypeDef) -> bool {
408 !row.flags().contains(TypeAttributes::WindowsRuntime) && row.kind() == TypeKind::Delegate
409}
410
411pub fn type_has_callback(ty: &Type) -> bool {
412 match ty {
413 Type::TypeDef(row: &TypeDef, _) => type_def_has_callback(*row),
414 Type::Win32Array(ty: &Box, _) => type_has_callback(ty),
415 _ => false,
416 }
417}
418
419pub fn type_def_has_callback(row: TypeDef) -> bool {
420 if type_def_is_callback(row) {
421 return true;
422 }
423 if row.kind() != TypeKind::Struct {
424 return false;
425 }
426 fn check(row: TypeDef) -> bool {
427 if row.fields().any(|field| type_has_callback(&field.ty(Some(row)))) {
428 return true;
429 }
430 false
431 }
432 let type_name = row.type_name();
433 if type_name.namespace.is_empty() {
434 check(row)
435 } else {
436 for row in row.reader().get_type_def(type_name.namespace, type_name.name) {
437 if check(row) {
438 return true;
439 }
440 }
441 false
442 }
443}
444
445pub fn type_interfaces(ty: &Type) -> Vec<Interface> {
446 // TODO: collect into btree map and then return collected vec
447 // This will both sort the results and should make finding dupes faster
448 fn walk(result: &mut Vec<Interface>, parent: &Type, is_base: bool) {
449 if let Type::TypeDef(row, generics) = parent {
450 for mut child in type_def_interfaces(*row, generics) {
451 child.kind = if !is_base && child.kind == InterfaceKind::Default {
452 InterfaceKind::Default
453 } else if child.kind == InterfaceKind::Overridable {
454 continue;
455 } else if is_base {
456 InterfaceKind::Base
457 } else {
458 InterfaceKind::None
459 };
460 let mut found = false;
461 for existing in result.iter_mut() {
462 if existing.ty == child.ty {
463 found = true;
464 if child.kind == InterfaceKind::Default {
465 existing.kind = child.kind
466 }
467 }
468 }
469 if !found {
470 walk(result, &child.ty, is_base);
471 result.push(child);
472 }
473 }
474 }
475 }
476 let mut result = Vec::new();
477 walk(&mut result, ty, false);
478 if let Type::TypeDef(row, _) = ty {
479 if row.kind() == TypeKind::Class {
480 for base in type_def_bases(*row) {
481 walk(&mut result, &Type::TypeDef(base, Vec::new()), true);
482 }
483 for attribute in row.attributes() {
484 match attribute.name() {
485 "StaticAttribute" | "ActivatableAttribute" => {
486 for (_, arg) in attribute.args() {
487 if let Value::TypeName(type_name) = arg {
488 let def = row.reader().get_type_def(type_name.namespace, type_name.name).next().expect("Type not found");
489 result.push(Interface { ty: Type::TypeDef(def, Vec::new()), kind: InterfaceKind::Static });
490 break;
491 }
492 }
493 }
494 _ => {}
495 }
496 }
497 }
498 }
499 result.sort_by(|a, b| type_name(&a.ty).cmp(type_name(&b.ty)));
500 result
501}
502
503fn type_name(ty: &Type) -> &str {
504 match ty {
505 Type::TypeDef(row: &TypeDef, _) => row.name(),
506 _ => "",
507 }
508}
509
510pub fn field_is_blittable(row: Field, enclosing: TypeDef) -> bool {
511 type_is_blittable(&row.ty(enclosing:Some(enclosing)))
512}
513
514pub fn field_is_copyable(row: Field, enclosing: TypeDef) -> bool {
515 type_is_copyable(&row.ty(enclosing:Some(enclosing)))
516}
517
518pub fn type_is_blittable(ty: &Type) -> bool {
519 match ty {
520 Type::TypeDef(row: &TypeDef, _) => type_def_is_blittable(*row),
521 Type::String | Type::BSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false,
522 Type::Win32Array(kind: &Box, _) => type_is_blittable(ty:kind),
523 Type::WinrtArray(kind: &Box) => type_is_blittable(ty:kind),
524 _ => true,
525 }
526}
527
528fn type_is_copyable(ty: &Type) -> bool {
529 match ty {
530 Type::TypeDef(row: &TypeDef, _) => type_def_is_copyable(*row),
531 Type::String | Type::BSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false,
532 Type::Win32Array(kind: &Box, _) => type_is_copyable(ty:kind),
533 Type::WinrtArray(kind: &Box) => type_is_copyable(ty:kind),
534 _ => true,
535 }
536}
537
538pub fn type_def_is_blittable(row: TypeDef) -> bool {
539 match row.kind() {
540 TypeKind::Struct => {
541 if row.flags().contains(TypeAttributes::WindowsRuntime) {
542 row.fields().all(|field: Field| field_is_blittable(row:field, enclosing:row))
543 } else {
544 true
545 }
546 }
547 TypeKind::Enum => true,
548 TypeKind::Delegate => !row.flags().contains(TypeAttributes::WindowsRuntime),
549 _ => false,
550 }
551}
552
553pub fn type_def_is_copyable(row: TypeDef) -> bool {
554 match row.kind() {
555 TypeKind::Struct => row.fields().all(|field: Field| field_is_copyable(row:field, enclosing:row)),
556 TypeKind::Enum => true,
557 TypeKind::Delegate => !row.flags().contains(TypeAttributes::WindowsRuntime),
558 _ => false,
559 }
560}
561
562pub fn type_def_is_exclusive(row: TypeDef) -> bool {
563 row.has_attribute(name:"ExclusiveToAttribute")
564}
565
566pub fn type_is_struct(ty: &Type) -> bool {
567 // This check is used to detect virtual functions that return C-style PODs that affect how the stack is packed for x86.
568 // It could be defined as a struct with more than one field but that check is complicated as it would have to detect
569 // nested structs. Fortunately, this is rare enough that this check is sufficient.
570 match ty {
571 Type::TypeDef(row: &TypeDef, _) => row.kind() == TypeKind::Struct && !type_def_is_handle(*row),
572 Type::GUID => true,
573 _ => false,
574 }
575}
576
577fn type_def_is_primitive(row: TypeDef) -> bool {
578 match row.kind() {
579 TypeKind::Enum => true,
580 TypeKind::Struct => type_def_is_handle(row),
581 TypeKind::Delegate => !row.flags().contains(TypeAttributes::WindowsRuntime),
582 _ => false,
583 }
584}
585
586pub fn type_is_primitive(ty: &Type) -> bool {
587 match ty {
588 Type::TypeDef(row: &TypeDef, _) => type_def_is_primitive(*row),
589 Type::Bool | Type::Char | Type::I8 | Type::U8 | Type::I16 | Type::U16 | Type::I32 | Type::U32 | Type::I64 | Type::U64 | Type::F32 | Type::F64 | Type::ISize | Type::USize | Type::HRESULT | Type::ConstPtr(_, _) | Type::MutPtr(_, _) => true,
590 _ => false,
591 }
592}
593
594fn type_has_explicit_layout(ty: &Type) -> bool {
595 match ty {
596 Type::TypeDef(row: &TypeDef, _) => type_def_has_explicit_layout(*row),
597 Type::Win32Array(ty: &Box, _) => type_has_explicit_layout(ty),
598 _ => false,
599 }
600}
601
602pub fn type_def_has_explicit_layout(row: TypeDef) -> bool {
603 if row.kind() != TypeKind::Struct {
604 return false;
605 }
606 fn check(row: TypeDef) -> bool {
607 if row.flags().contains(TypeAttributes::ExplicitLayout) {
608 return true;
609 }
610 if row.fields().any(|field| type_has_explicit_layout(&field.ty(Some(row)))) {
611 return true;
612 }
613 false
614 }
615 let type_name = row.type_name();
616 if type_name.namespace.is_empty() {
617 check(row)
618 } else {
619 for row in row.reader().get_type_def(type_name.namespace, type_name.name) {
620 if check(row) {
621 return true;
622 }
623 }
624 false
625 }
626}
627
628fn type_has_packing(ty: &Type) -> bool {
629 match ty {
630 Type::TypeDef(row: &TypeDef, _) => type_def_has_packing(*row),
631 Type::Win32Array(ty: &Box, _) => type_has_packing(ty),
632 _ => false,
633 }
634}
635
636pub fn type_def_has_packing(row: TypeDef) -> bool {
637 if row.kind() != TypeKind::Struct {
638 return false;
639 }
640 fn check(row: TypeDef) -> bool {
641 if row.class_layout().is_some() {
642 return true;
643 }
644 if row.fields().any(|field| type_has_packing(&field.ty(Some(row)))) {
645 return true;
646 }
647 false
648 }
649 let type_name = row.type_name();
650 if type_name.namespace.is_empty() {
651 check(row)
652 } else {
653 for row in row.reader().get_type_def(type_name.namespace, type_name.name) {
654 if check(row) {
655 return true;
656 }
657 }
658 false
659 }
660}
661
662pub fn type_def_interfaces(def: TypeDef, generics: &[Type]) -> impl Iterator<Item = Interface> + '_ {
663 def.interface_impls().map(|imp: InterfaceImpl| {
664 let kind: InterfaceKind = if imp.has_attribute(name:"DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None };
665 Interface { kind, ty: imp.ty(generics) }
666 })
667}
668
669pub fn type_def_default_interface(row: TypeDef) -> Option<Type> {
670 type_def_interfaces(def:row, &[]).find_map(move |interface: Interface| if interface.kind == InterfaceKind::Default { Some(interface.ty) } else { None })
671}
672
673fn type_signature(ty: &Type) -> String {
674 match ty {
675 Type::Bool => "b1".to_string(),
676 Type::Char => "c2".to_string(),
677 Type::I8 => "i1".to_string(),
678 Type::U8 => "u1".to_string(),
679 Type::I16 => "i2".to_string(),
680 Type::U16 => "u2".to_string(),
681 Type::I32 => "i4".to_string(),
682 Type::U32 => "u4".to_string(),
683 Type::I64 => "i8".to_string(),
684 Type::U64 => "u8".to_string(),
685 Type::F32 => "f4".to_string(),
686 Type::F64 => "f8".to_string(),
687 Type::ISize => "is".to_string(),
688 Type::USize => "us".to_string(),
689 Type::String => "string".to_string(),
690 Type::IInspectable => "cinterface(IInspectable)".to_string(),
691 Type::GUID => "g16".to_string(),
692 Type::HRESULT => "struct(Windows.Foundation.HResult;i4)".to_string(),
693 Type::TypeDef(row: &TypeDef, generics: &Vec) => type_def_signature(*row, generics),
694 rest: &Type => unimplemented!("{rest:?}"),
695 }
696}
697
698pub fn type_def_signature(row: TypeDef, generics: &[Type]) -> String {
699 match row.kind() {
700 TypeKind::Interface => type_def_interface_signature(row, generics),
701 TypeKind::Class => {
702 if let Some(Type::TypeDef(default, generics)) = type_def_default_interface(row) {
703 format!("rc({};{})", row.type_name(), type_def_interface_signature(default, &generics))
704 } else {
705 unimplemented!();
706 }
707 }
708 TypeKind::Enum => format!("enum({};{})", row.type_name(), type_signature(&row.underlying_type())),
709 TypeKind::Struct => {
710 let mut result = format!("struct({}", row.type_name());
711 for field in row.fields() {
712 result.push(';');
713 result.push_str(&type_signature(&field.ty(Some(row))));
714 }
715 result.push(')');
716 result
717 }
718 TypeKind::Delegate => {
719 if generics.is_empty() {
720 format!("delegate({})", type_def_interface_signature(row, generics))
721 } else {
722 type_def_interface_signature(row, generics)
723 }
724 }
725 }
726}
727
728fn type_def_interface_signature(row: TypeDef, generics: &[Type]) -> String {
729 let guid: Guid = type_def_guid(row).unwrap();
730 if generics.is_empty() {
731 format!("{{{guid:#?}}}")
732 } else {
733 let mut result: String = format!("pinterface({{{guid:#?}}}");
734 for generic: &Type in generics {
735 result.push(ch:';');
736 result.push_str(&type_signature(ty:generic));
737 }
738 result.push(ch:')');
739 result
740 }
741}
742
743pub fn type_def_is_handle(row: TypeDef) -> bool {
744 row.has_attribute(name:"NativeTypedefAttribute")
745}
746
747pub fn type_def_guid(row: TypeDef) -> Option<Guid> {
748 row.find_attribute(name:"GuidAttribute").map(|attribute: Attribute| Guid::from_args(&attribute.args()))
749}
750
751pub fn type_def_bases(mut row: TypeDef) -> Vec<TypeDef> {
752 let mut bases: Vec = Vec::new();
753 loop {
754 match row.extends() {
755 Some(base: TypeName) if base != TypeName::Object => {
756 row = row.reader().get_type_def(base.namespace, base.name).next().expect(msg:"Type not found");
757 bases.push(row);
758 }
759 _ => break,
760 }
761 }
762 bases
763}
764
765pub fn type_def_invalid_values(row: TypeDef) -> Vec<i64> {
766 let mut values: Vec = Vec::new();
767 for attribute: Attribute in row.attributes() {
768 if attribute.name() == "InvalidHandleValueAttribute" {
769 if let Some((_, Value::I64(value: &i64))) = attribute.args().first() {
770 values.push(*value);
771 }
772 }
773 }
774 values
775}
776
777fn type_def_is_nullable(row: TypeDef) -> bool {
778 match row.kind() {
779 TypeKind::Interface | TypeKind::Class => true,
780 // Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid them
781 // from being doubly wrapped in `Option`.
782 TypeKind::Delegate => row.flags().contains(TypeAttributes::WindowsRuntime),
783 _ => false,
784 }
785}
786
787pub fn type_is_nullable(ty: &Type) -> bool {
788 match ty {
789 Type::TypeDef(row: &TypeDef, _) => type_def_is_nullable(*row),
790 Type::IInspectable | Type::IUnknown => true,
791 _ => false,
792 }
793}
794
795pub fn type_def_vtables(row: TypeDef) -> Vec<Type> {
796 let mut result = Vec::new();
797 if row.flags().contains(TypeAttributes::WindowsRuntime) {
798 result.push(Type::IUnknown);
799 if row.kind() != TypeKind::Delegate {
800 result.push(Type::IInspectable);
801 }
802 } else {
803 let mut next = row;
804 while let Some(base) = next.interface_impls().map(move |imp| imp.ty(&[])).next() {
805 match base {
806 Type::TypeDef(row, _) => {
807 next = row;
808 result.insert(0, base);
809 }
810 Type::IInspectable => {
811 result.insert(0, Type::IUnknown);
812 result.insert(1, Type::IInspectable);
813 break;
814 }
815 Type::IUnknown => {
816 result.insert(0, Type::IUnknown);
817 break;
818 }
819 rest => unimplemented!("{rest:?}"),
820 }
821 }
822 }
823 result
824}
825