Skip to main content

ddbug_parser/
types.rs

1use std::borrow::Cow;
2use std::cmp;
3use std::marker;
4use std::sync::Arc;
5
6use crate::file::FileHash;
7use crate::function::ParameterOffset;
8use crate::namespace::Namespace;
9use crate::source::Source;
10use crate::{Id, Size};
11
12/// The kind of a type.
13#[derive(Debug, Clone)]
14pub enum TypeKind<'input> {
15    /// The void type.
16    Void,
17    /// A base type.
18    Base(BaseType<'input>),
19    /// A type alias definition.
20    Def(TypeDef<'input>),
21    /// A struct type.
22    Struct(StructType<'input>),
23    /// A union type.
24    Union(UnionType<'input>),
25    /// An enumeration type.
26    Enumeration(EnumerationType<'input>),
27    /// A type for an array of elements.
28    Array(ArrayType<'input>),
29    /// A function type.
30    Function(FunctionType<'input>),
31    /// An unspecified type.
32    Unspecified(UnspecifiedType<'input>),
33    /// The type of a pointer to a member.
34    PointerToMember(PointerToMemberType),
35    /// A type that is obtained by adding a modifier to another type.
36    Modifier(TypeModifier<'input>),
37    /// A subrange of another type.
38    Subrange(SubrangeType<'input>),
39}
40
41impl<'input> TypeKind<'input> {
42    fn discriminant_value(&self) -> u8 {
43        match *self {
44            TypeKind::Void => 1,
45            TypeKind::Base(..) => 2,
46            TypeKind::Def(..) => 3,
47            TypeKind::Struct(..) => 4,
48            TypeKind::Union(..) => 5,
49            TypeKind::Enumeration(..) => 6,
50            TypeKind::Array(..) => 7,
51            TypeKind::Function(..) => 8,
52            TypeKind::Unspecified(..) => 9,
53            TypeKind::PointerToMember(..) => 10,
54            TypeKind::Modifier(..) => 11,
55            TypeKind::Subrange(..) => 12,
56        }
57    }
58}
59
60/// The debuginfo offset of a type.
61///
62/// This is unique for all types in a file.
63#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
64pub struct TypeOffset(usize);
65
66impl TypeOffset {
67    #[inline]
68    pub(crate) fn new(offset: usize) -> TypeOffset {
69        debug_assert!(TypeOffset(offset) != TypeOffset::none());
70        TypeOffset(offset)
71    }
72
73    #[inline]
74    pub(crate) fn none() -> TypeOffset {
75        TypeOffset(usize::MAX)
76    }
77
78    /// Return true if the type is unknown or `void`.
79    #[inline]
80    pub fn is_none(self) -> bool {
81        self == Self::none()
82    }
83
84    /// Return true if the type is known and not `void`.
85    #[inline]
86    pub fn is_some(self) -> bool {
87        self != Self::none()
88    }
89
90    #[inline]
91    pub(crate) fn get(self) -> Option<usize> {
92        if self.is_none() { None } else { Some(self.0) }
93    }
94}
95
96impl Default for TypeOffset {
97    #[inline]
98    fn default() -> Self {
99        TypeOffset::none()
100    }
101}
102
103/// A type.
104#[derive(Debug, Clone)]
105pub struct Type<'input> {
106    pub(crate) id: Id,
107    pub(crate) offset: TypeOffset,
108    pub(crate) kind: TypeKind<'input>,
109}
110
111impl<'input> Default for Type<'input> {
112    fn default() -> Self {
113        Type {
114            id: Id::new(0),
115            offset: TypeOffset::none(),
116            kind: TypeKind::Base(BaseType::default()),
117        }
118    }
119}
120
121impl<'input> Type<'input> {
122    /// Lookup a type given its offset.
123    ///
124    /// Returns `None` if the type offset is invalid.
125    pub fn from_offset<'a>(
126        hash: &'a FileHash<'input>,
127        offset: TypeOffset,
128    ) -> Option<Cow<'a, Type<'input>>> {
129        if offset.is_none() {
130            return Some(Cow::Borrowed(&hash.void));
131        }
132        hash.types
133            .get(&offset)
134            .map(|ty| Cow::Borrowed(*ty))
135            .or_else(|| hash.file.get_type(offset).map(Cow::Owned))
136    }
137
138    pub(crate) fn void() -> Type<'static> {
139        Type {
140            id: Id::new(usize::MAX),
141            offset: TypeOffset(usize::MAX),
142            kind: TypeKind::Void,
143        }
144    }
145
146    /// Return true if the type is the void type.
147    #[inline]
148    pub fn is_void(&self) -> bool {
149        matches!(self.kind, TypeKind::Void)
150    }
151
152    /// The user defined id for this type.
153    #[inline]
154    pub fn id(&self) -> usize {
155        self.id.get()
156    }
157
158    /// Set a user defined id for this type.
159    #[inline]
160    pub fn set_id(&self, id: usize) {
161        self.id.set(id)
162    }
163
164    /// The debuginfo offset of this type.
165    #[inline]
166    pub fn offset(&self) -> TypeOffset {
167        self.offset
168    }
169
170    /// The kind of this type.
171    #[inline]
172    pub fn kind(&self) -> &TypeKind<'input> {
173        &self.kind
174    }
175
176    /// The size in bytes of an instance of this type.
177    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
178        match &self.kind {
179            TypeKind::Void => Some(0),
180            TypeKind::Base(val) => val.byte_size(),
181            TypeKind::Def(val) => val.byte_size(hash),
182            TypeKind::Struct(val) => val.byte_size(),
183            TypeKind::Union(val) => val.byte_size(),
184            TypeKind::Enumeration(val) => val.byte_size(hash),
185            TypeKind::Array(val) => val.byte_size(hash),
186            TypeKind::Function(val) => val.byte_size(),
187            TypeKind::Unspecified(..) => None,
188            TypeKind::PointerToMember(val) => val.byte_size(hash),
189            TypeKind::Modifier(val) => val.byte_size(hash),
190            TypeKind::Subrange(val) => val.byte_size(hash),
191        }
192    }
193
194    /// Return true if this is an anonymous type, or defined within an anonymous type.
195    pub fn is_anon(&self) -> bool {
196        match &self.kind {
197            TypeKind::Struct(val) => val.is_anon(),
198            TypeKind::Union(val) => val.is_anon(),
199            TypeKind::Void
200            | TypeKind::Base(..)
201            | TypeKind::Def(..)
202            | TypeKind::Enumeration(..)
203            | TypeKind::Array(..)
204            | TypeKind::Function(..)
205            | TypeKind::Unspecified(..)
206            | TypeKind::PointerToMember(..)
207            | TypeKind::Modifier(..)
208            | TypeKind::Subrange(..) => false,
209        }
210    }
211
212    /// Return true if this is the type of a function (including aliases and modifiers).
213    fn is_function(&self, hash: &FileHash) -> bool {
214        match &self.kind {
215            TypeKind::Function(..) => true,
216            TypeKind::Def(val) => match val.ty(hash) {
217                Some(ty) => ty.is_function(hash),
218                None => false,
219            },
220            TypeKind::Modifier(val) => match val.ty(hash) {
221                Some(ty) => ty.is_function(hash),
222                None => false,
223            },
224            TypeKind::Void
225            | TypeKind::Struct(..)
226            | TypeKind::Union(..)
227            | TypeKind::Base(..)
228            | TypeKind::Enumeration(..)
229            | TypeKind::Array(..)
230            | TypeKind::Unspecified(..)
231            | TypeKind::PointerToMember(..)
232            | TypeKind::Subrange(..) => false,
233        }
234    }
235
236    /// The members of this type.
237    pub fn members(&self) -> &[Member<'input>] {
238        match &self.kind {
239            TypeKind::Struct(val) => val.members(),
240            TypeKind::Union(val) => val.members(),
241            TypeKind::Void
242            | TypeKind::Enumeration(..)
243            | TypeKind::Def(..)
244            | TypeKind::Base(..)
245            | TypeKind::Array(..)
246            | TypeKind::Function(..)
247            | TypeKind::Unspecified(..)
248            | TypeKind::PointerToMember(..)
249            | TypeKind::Modifier(..)
250            | TypeKind::Subrange(..) => &[],
251        }
252    }
253
254    /// Compare the identifying information of two types.
255    ///
256    /// Equal types must have the same type kind. Further requirements for equality
257    /// depend on the specific type kind.
258    ///
259    /// This can be used to sort, and to determine if two types refer to the same definition
260    /// (even if there are differences in the definitions).
261    pub fn cmp_id(
262        hash_a: &FileHash,
263        type_a: &Type,
264        hash_b: &FileHash,
265        type_b: &Type,
266    ) -> cmp::Ordering {
267        use self::TypeKind::*;
268        match (&type_a.kind, &type_b.kind) {
269            (Base(a), Base(b)) => BaseType::cmp_id(a, b),
270            (Def(a), Def(b)) => TypeDef::cmp_id(a, b),
271            (Struct(a), Struct(b)) => StructType::cmp_id(a, b),
272            (Union(a), Union(b)) => UnionType::cmp_id(a, b),
273            (Enumeration(a), Enumeration(b)) => EnumerationType::cmp_id(a, b),
274            (Array(a), Array(b)) => ArrayType::cmp_id(hash_a, a, hash_b, b),
275            (Function(a), Function(b)) => FunctionType::cmp_id(hash_a, a, hash_b, b),
276            (Unspecified(a), Unspecified(b)) => UnspecifiedType::cmp_id(a, b),
277            (PointerToMember(a), PointerToMember(b)) => {
278                PointerToMemberType::cmp_id(hash_a, a, hash_b, b)
279            }
280            (Modifier(a), Modifier(b)) => TypeModifier::cmp_id(hash_a, a, hash_b, b),
281            (Subrange(a), Subrange(b)) => SubrangeType::cmp_id(hash_a, a, hash_b, b),
282            _ => {
283                let discr_a = type_a.kind.discriminant_value();
284                let discr_b = type_b.kind.discriminant_value();
285                debug_assert_ne!(discr_a, discr_b);
286                discr_a.cmp(&discr_b)
287            }
288        }
289    }
290}
291
292/// A type that is obtained by adding a modifier to another type.
293#[derive(Debug, Clone)]
294pub struct TypeModifier<'input> {
295    pub(crate) kind: TypeModifierKind,
296    pub(crate) ty: TypeOffset,
297    pub(crate) name: Option<&'input str>,
298    pub(crate) byte_size: Size,
299    // TODO: hack
300    pub(crate) address_size: Option<u64>,
301}
302
303/// The kind of a type modifier.
304#[derive(Debug, PartialEq, Eq, Clone, Copy)]
305pub enum TypeModifierKind {
306    /// The resulting type is a pointer to the type being modified.
307    Pointer,
308    /// The resulting type is a reference to the type being modified.
309    Reference,
310    /// The resulting type is a constant.
311    Const,
312    /// The resulting type is packed.
313    Packed,
314    /// The resulting type is volatile.
315    Volatile,
316    /// The resulting type has restricted aliasing.
317    Restrict,
318    /// The resulting type is shared (for example, in UPC).
319    Shared,
320    /// The resulting type is a rvalue reference to the type being modified.
321    RvalueReference,
322    /// The resulting type is atomic.
323    Atomic,
324    // TODO:
325    // Immutable,
326    /// Any other type modifier.
327    // PDB is disabled
328    #[allow(dead_code)]
329    Other,
330}
331
332impl TypeModifierKind {
333    fn discriminant_value(self) -> u8 {
334        match self {
335            TypeModifierKind::Pointer => 1,
336            TypeModifierKind::Reference => 2,
337            TypeModifierKind::Const => 3,
338            TypeModifierKind::Packed => 4,
339            TypeModifierKind::Volatile => 5,
340            TypeModifierKind::Restrict => 6,
341            TypeModifierKind::Shared => 7,
342            TypeModifierKind::RvalueReference => 8,
343            TypeModifierKind::Atomic => 9,
344            TypeModifierKind::Other => 10,
345        }
346    }
347}
348
349impl<'input> TypeModifier<'input> {
350    /// The name of the type.
351    ///
352    /// If this is `None` then the name should be derived from the type that is being modified.
353    #[inline]
354    pub fn name(&self) -> Option<&'input str> {
355        self.name
356    }
357
358    /// The kind of this type modifier.
359    #[inline]
360    pub fn kind(&self) -> TypeModifierKind {
361        self.kind
362    }
363
364    /// The type that is being modified.
365    #[inline]
366    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
367        Type::from_offset(hash, self.ty)
368    }
369
370    fn is_pointer_like(&self) -> bool {
371        match self.kind {
372            TypeModifierKind::Const
373            | TypeModifierKind::Packed
374            | TypeModifierKind::Volatile
375            | TypeModifierKind::Restrict
376            | TypeModifierKind::Shared
377            | TypeModifierKind::Atomic
378            | TypeModifierKind::Other => false,
379            TypeModifierKind::Pointer
380            | TypeModifierKind::Reference
381            | TypeModifierKind::RvalueReference => true,
382        }
383    }
384
385    /// The size in bytes of an instance of this type.
386    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
387        if self.byte_size.is_some() {
388            return self.byte_size.get();
389        }
390        if self.is_pointer_like() {
391            self.address_size
392        } else {
393            self.ty(hash).and_then(|v| v.byte_size(hash))
394        }
395    }
396
397    /// Compare the identifying information of two types.
398    ///
399    /// Type modifiers are equal if the modifiers are the same and the types being modified
400    /// are equal.
401    ///
402    /// This can be used to sort, and to determine if two types refer to the same definition
403    /// (even if there are differences in the definitions).
404    pub fn cmp_id(
405        hash_a: &FileHash,
406        a: &TypeModifier,
407        hash_b: &FileHash,
408        b: &TypeModifier,
409    ) -> cmp::Ordering {
410        match (&a.ty(hash_a), &b.ty(hash_b)) {
411            (Some(ty_a), Some(ty_b)) => {
412                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
413                if ord != cmp::Ordering::Equal {
414                    return ord;
415                }
416            }
417            (Some(_), None) => {
418                return cmp::Ordering::Less;
419            }
420            (None, Some(_)) => {
421                return cmp::Ordering::Greater;
422            }
423            (None, None) => {}
424        }
425        let discr_a = a.kind.discriminant_value();
426        let discr_b = b.kind.discriminant_value();
427        discr_a.cmp(&discr_b)
428    }
429}
430
431/// The endianity of an object.
432#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
433pub enum Endianity {
434    /// Default endianity encoding.
435    #[default]
436    Default,
437    /// Big-endian encoding.
438    Big,
439    /// Little-endian encoding.
440    Little,
441}
442
443/// The encoding of a base type.
444#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
445pub enum BaseTypeEncoding {
446    /// Unsupported or unspecified encoding.
447    #[default]
448    Other,
449    /// True or false.
450    Boolean,
451    /// Linear machine address.
452    Address,
453    /// Signed binary integer.
454    Signed,
455    /// Signed character.
456    SignedChar,
457    /// Unsigned binary integer.
458    Unsigned,
459    /// Unsigned character.
460    UnsignedChar,
461    /// Binary floating-point number.
462    Float,
463}
464
465impl BaseTypeEncoding {
466    /// Return true if this is an unsigned integer type.
467    pub fn is_unsigned(self) -> bool {
468        match self {
469            BaseTypeEncoding::Unsigned
470            | BaseTypeEncoding::UnsignedChar
471            | BaseTypeEncoding::Boolean
472            | BaseTypeEncoding::Address => true,
473            BaseTypeEncoding::Other
474            | BaseTypeEncoding::Signed
475            | BaseTypeEncoding::SignedChar
476            | BaseTypeEncoding::Float => false,
477        }
478    }
479}
480
481/// A base type.
482#[derive(Debug, Default, Clone)]
483pub struct BaseType<'input> {
484    pub(crate) name: Option<&'input str>,
485    pub(crate) byte_size: Size,
486    pub(crate) encoding: BaseTypeEncoding,
487    pub(crate) endianity: Endianity,
488}
489
490impl<'input> BaseType<'input> {
491    /// The name of the type.
492    #[inline]
493    pub fn name(&self) -> Option<&'input str> {
494        self.name
495    }
496
497    /// The size in bytes of an instance of this type.
498    #[inline]
499    pub fn byte_size(&self) -> Option<u64> {
500        self.byte_size.get()
501    }
502
503    /// How the base type is encoded an interpreted.
504    #[inline]
505    pub fn encoding(&self) -> BaseTypeEncoding {
506        self.encoding
507    }
508
509    /// The endianity of the value, if applicable.
510    #[inline]
511    pub fn endianity(&self) -> Endianity {
512        self.endianity
513    }
514
515    /// Compare the identifying information of two types.
516    ///
517    /// Base types are considered equal if their names are equal.
518    ///
519    /// This can be used to sort, and to determine if two types refer to the same definition
520    /// (even if there are differences in the definitions).
521    fn cmp_id(a: &BaseType, b: &BaseType) -> cmp::Ordering {
522        a.name.cmp(&b.name)
523    }
524}
525
526/// A type alias definition.
527#[derive(Debug, Default, Clone)]
528pub struct TypeDef<'input> {
529    pub(crate) namespace: Option<Arc<Namespace<'input>>>,
530    pub(crate) name: Option<&'input str>,
531    pub(crate) ty: TypeOffset,
532    pub(crate) source: Source<'input>,
533}
534
535impl<'input> TypeDef<'input> {
536    /// The namespace of the type.
537    pub fn namespace(&self) -> Option<&Namespace<'input>> {
538        self.namespace.as_deref()
539    }
540
541    /// The name of the type definition.
542    #[inline]
543    pub fn name(&self) -> Option<&'input str> {
544        self.name
545    }
546
547    /// The type that the alias is being defined for.
548    #[inline]
549    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
550        Type::from_offset(hash, self.ty)
551    }
552
553    /// The source information for the type definition.
554    #[inline]
555    pub fn source(&self) -> &Source<'input> {
556        &self.source
557    }
558
559    /// The size in bytes of an instance of this type.
560    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
561        self.ty(hash).and_then(|v| v.byte_size(hash))
562    }
563
564    /// Compare the identifying information of two types.
565    ///
566    /// Type definitions are considered equal if their names are equal, even if the type being
567    /// aliased is different.
568    ///
569    /// This can be used to sort, and to determine if two types refer to the same definition
570    /// (even if there are differences in the definitions).
571    pub fn cmp_id(a: &TypeDef, b: &TypeDef) -> cmp::Ordering {
572        Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
573    }
574}
575
576/// A struct type.
577#[derive(Debug, Default, Clone)]
578pub struct StructType<'input> {
579    pub(crate) namespace: Option<Arc<Namespace<'input>>>,
580    pub(crate) name: Option<&'input str>,
581    pub(crate) source: Source<'input>,
582    pub(crate) byte_size: Size,
583    pub(crate) declaration: bool,
584    pub(crate) members: Vec<Member<'input>>,
585    pub(crate) variant_parts: Vec<VariantPart<'input>>,
586    pub(crate) inherits: Vec<Inherit>,
587}
588
589impl<'input> StructType<'input> {
590    /// The namespace of the type.
591    pub fn namespace(&self) -> Option<&Namespace<'input>> {
592        self.namespace.as_deref()
593    }
594
595    /// The name of the type.
596    #[inline]
597    pub fn name(&self) -> Option<&'input str> {
598        self.name
599    }
600
601    /// The source information for the type.
602    #[inline]
603    pub fn source(&self) -> &Source<'input> {
604        &self.source
605    }
606
607    /// The size in bytes of an instance of this type.
608    #[inline]
609    pub fn bit_size(&self) -> Option<u64> {
610        self.byte_size.get().map(|v| v * 8)
611    }
612
613    /// The size in bytes of an instance of this type.
614    #[inline]
615    pub fn byte_size(&self) -> Option<u64> {
616        self.byte_size.get()
617    }
618
619    /// Return true if this is a declaration.
620    #[inline]
621    pub fn is_declaration(&self) -> bool {
622        self.declaration
623    }
624
625    /// Return true if this is an anonymous type, or defined within an anonymous type.
626    pub fn is_anon(&self) -> bool {
627        self.name.is_none() || Namespace::is_anon_type(&self.namespace)
628    }
629
630    /// The members of this type.
631    #[inline]
632    pub fn members(&self) -> &[Member<'input>] {
633        &self.members
634    }
635
636    /// The variant parts of this type.
637    #[inline]
638    pub fn variant_parts(&self) -> &[VariantPart<'input>] {
639        &self.variant_parts
640    }
641
642    /// The inherited types.
643    #[inline]
644    pub fn inherits(&self) -> &[Inherit] {
645        &self.inherits
646    }
647
648    /// The layout of members of this type.
649    pub fn layout<'me>(&'me self, hash: &FileHash) -> Vec<Layout<'input, 'me>> {
650        layout(
651            &self.members,
652            &self.inherits,
653            &self.variant_parts,
654            0,
655            self.bit_size(),
656            hash,
657        )
658    }
659
660    /// Compare the identifying information of two types.
661    ///
662    /// Structs are considered equal if their names are equal.
663    ///
664    /// This can be used to sort, and to determine if two types refer to the same definition
665    /// (even if there are differences in the definitions).
666    pub fn cmp_id(a: &StructType, b: &StructType) -> cmp::Ordering {
667        Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
668    }
669}
670
671/// A union type.
672#[derive(Debug, Default, Clone)]
673pub struct UnionType<'input> {
674    pub(crate) namespace: Option<Arc<Namespace<'input>>>,
675    pub(crate) name: Option<&'input str>,
676    pub(crate) source: Source<'input>,
677    pub(crate) byte_size: Size,
678    pub(crate) declaration: bool,
679    pub(crate) members: Vec<Member<'input>>,
680}
681
682impl<'input> UnionType<'input> {
683    /// The namespace of the type.
684    pub fn namespace(&self) -> Option<&Namespace<'input>> {
685        self.namespace.as_deref()
686    }
687
688    /// The name of the type.
689    #[inline]
690    pub fn name(&self) -> Option<&'input str> {
691        self.name
692    }
693
694    /// The source information for the type.
695    #[inline]
696    pub fn source(&self) -> &Source<'input> {
697        &self.source
698    }
699
700    /// The size in bytes of an instance of this type.
701    #[inline]
702    pub fn byte_size(&self) -> Option<u64> {
703        self.byte_size.get()
704    }
705
706    /// Return true if this is a declaration.
707    #[inline]
708    pub fn is_declaration(&self) -> bool {
709        self.declaration
710    }
711
712    /// Return true if this is an anonymous type, or defined within an anonymous type.
713    pub fn is_anon(&self) -> bool {
714        self.name.is_none() || Namespace::is_anon_type(&self.namespace)
715    }
716
717    /// The members of this type.
718    #[inline]
719    pub fn members(&self) -> &[Member<'input>] {
720        &self.members
721    }
722
723    /// Compare the identifying information of two types.
724    ///
725    /// Unions are considered equal if their names are equal.
726    ///
727    /// This can be used to sort, and to determine if two types refer to the same definition
728    /// (even if there are differences in the definitions).
729    pub fn cmp_id(a: &UnionType, b: &UnionType) -> cmp::Ordering {
730        Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
731    }
732}
733
734/// A variant part.
735///
736/// A variant part is a discriminant member and list of variants that are
737/// selected based on the value of the discriminant member.
738#[derive(Debug, Default, Clone)]
739pub struct VariantPart<'input> {
740    pub(crate) discr: MemberOffset,
741    pub(crate) variants: Vec<Variant<'input>>,
742}
743
744impl<'input> VariantPart<'input> {
745    /// The discriminant member for this variant part.
746    ///
747    /// The given members should be from the type containing this variant part.
748    #[inline]
749    pub fn discriminant<'a>(&self, members: &'a [Member<'input>]) -> Option<&'a Member<'input>> {
750        members.iter().find(|member| member.offset == self.discr)
751    }
752
753    /// The variants for this variant part.
754    #[inline]
755    pub fn variants(&self) -> &[Variant<'input>] {
756        &self.variants
757    }
758
759    /// The smallest offset in bits for a variant of this variant part.
760    pub fn bit_offset(&self) -> u64 {
761        let mut bit_offset = u64::MAX;
762        for variant in &self.variants {
763            let o = variant.bit_offset();
764            if bit_offset > o {
765                bit_offset = o;
766            }
767        }
768        if bit_offset < u64::MAX { bit_offset } else { 0 }
769    }
770
771    /// The largest size in bits for the variants of this variant part,
772    /// excluding leading and trailing padding.
773    pub fn bit_size(&self, hash: &FileHash) -> Option<u64> {
774        let start = self.bit_offset();
775        let mut end = start;
776        for variant in &self.variants {
777            let o = variant.bit_offset();
778            if let Some(size) = variant.bit_size(hash) {
779                if end < o + size {
780                    end = o + size;
781                }
782            } else {
783                return None;
784            }
785        }
786        Some(end - start)
787    }
788}
789
790/// A variant.
791///
792/// A variant consists of a discriminant value that selects the variant,
793/// and a list of members that are valid when the variant is selected.
794#[derive(Debug, Default, Clone)]
795pub struct Variant<'input> {
796    pub(crate) discr_value: Option<u64>,
797    pub(crate) name: Option<&'input str>,
798    pub(crate) members: Vec<Member<'input>>,
799    pub(crate) source: Source<'input>,
800}
801
802impl<'input> Variant<'input> {
803    /// The discriminant value which selects this variant.
804    ///
805    /// The sign of this value depends on the type of the discriminant member.
806    #[inline]
807    pub fn discriminant_value(&self) -> Option<u64> {
808        self.discr_value
809    }
810
811    /// The name of the variant.
812    ///
813    /// Currently this is only set for Rust enums.
814    #[inline]
815    pub fn name(&self) -> Option<&'input str> {
816        self.name
817    }
818
819    /// The source information for the variant.
820    ///
821    /// This field is semingly only set in Rust when the variant comes from an async fn.
822    #[inline]
823    pub fn source(&self) -> &Source<'input> {
824        &self.source
825    }
826
827    /// The members for this variant.
828    #[inline]
829    pub fn members(&self) -> &[Member<'input>] {
830        &self.members
831    }
832
833    /// The smallest offset in bits for a member of this variant.
834    pub fn bit_offset(&self) -> u64 {
835        let mut bit_offset = u64::MAX;
836        for member in &self.members {
837            let o = member.bit_offset();
838            if bit_offset > o {
839                bit_offset = o;
840            }
841        }
842        if bit_offset < u64::MAX { bit_offset } else { 0 }
843    }
844
845    /// The size in bits for the members of this variant, excluding leading and trailing padding.
846    pub fn bit_size(&self, hash: &FileHash) -> Option<u64> {
847        let start = self.bit_offset();
848        let mut end = start;
849        for member in &self.members {
850            let o = member.bit_offset();
851            if let Some(size) = member.bit_size(hash) {
852                if end < o + size {
853                    end = o + size;
854                }
855            } else {
856                return None;
857            }
858        }
859        Some(end - start)
860    }
861
862    /// The layout of members of this variant within a variant part.
863    ///
864    /// The given bit_offset and bit_size should be for the variant part.
865    pub fn layout<'me>(
866        &'me self,
867        bit_offset: u64,
868        bit_size: Option<u64>,
869        hash: &FileHash<'input>,
870    ) -> Vec<Layout<'input, 'me>> {
871        layout(&self.members, &[], &[], bit_offset, bit_size, hash)
872    }
873
874    /// Compare the identifying information of two types.
875    ///
876    /// Variants are considered equal if the discriminant values are equal.
877    ///
878    /// This can be used to sort, and to determine if two types refer to the same definition
879    /// (even if there are differences in the definitions).
880    // TODO: compare discriminant member too
881    pub fn cmp_id(
882        _hash_a: &FileHash,
883        a: &Variant,
884        _hash_b: &FileHash,
885        b: &Variant,
886    ) -> cmp::Ordering {
887        a.discr_value.cmp(&b.discr_value)
888    }
889}
890
891/// The debuginfo offset of a member.
892///
893/// This is unique for all members in a file.
894#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
895pub struct MemberOffset(usize);
896
897impl MemberOffset {
898    #[inline]
899    pub(crate) fn new(offset: usize) -> MemberOffset {
900        debug_assert!(MemberOffset(offset) != MemberOffset::none());
901        MemberOffset(offset)
902    }
903
904    #[inline]
905    pub(crate) fn none() -> MemberOffset {
906        MemberOffset(usize::MAX)
907    }
908}
909
910impl Default for MemberOffset {
911    #[inline]
912    fn default() -> Self {
913        MemberOffset::none()
914    }
915}
916
917/// A member of a struct or union.
918#[derive(Debug, Default, Clone)]
919pub struct Member<'input> {
920    pub(crate) offset: MemberOffset,
921    pub(crate) name: Option<&'input str>,
922    pub(crate) source: Source<'input>,
923    pub(crate) ty: TypeOffset,
924    // Defaults to 0, so always present.
925    pub(crate) bit_offset: u64,
926    pub(crate) bit_size: Size,
927}
928
929impl<'input> Member<'input> {
930    /// The name of the member.
931    #[inline]
932    pub fn name(&self) -> Option<&'input str> {
933        self.name
934    }
935
936    /// The source information for the member.
937    #[inline]
938    pub fn source(&self) -> &Source<'input> {
939        &self.source
940    }
941
942    /// The debuginfo offset of this member.
943    #[inline]
944    pub fn offset(&self) -> MemberOffset {
945        self.offset
946    }
947
948    /// The debuginfo offset of the type of this member.
949    #[inline]
950    pub fn type_offset(&self) -> TypeOffset {
951        self.ty
952    }
953
954    /// The type of this member.
955    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
956        Type::from_offset(hash, self.ty)
957    }
958
959    /// The offset in bits of this member.
960    #[inline]
961    pub fn bit_offset(&self) -> u64 {
962        self.bit_offset
963    }
964
965    /// Return true if this member defines a bit size instead of using the size of the type.
966    #[inline]
967    pub fn is_bit_field(&self) -> bool {
968        self.bit_size.is_some()
969    }
970
971    /// The size in bits of this member.
972    pub fn bit_size(&self, hash: &FileHash) -> Option<u64> {
973        if self.bit_size.is_some() {
974            self.bit_size.get()
975        } else {
976            self.ty(hash).and_then(|v| v.byte_size(hash).map(|v| v * 8))
977        }
978    }
979
980    /// Return true if this member defines an inline type.
981    pub fn is_inline(&self, hash: &FileHash) -> bool {
982        match self.name() {
983            Some(s) => {
984                if s.starts_with("RUST$ENCODED$ENUM$") {
985                    return true;
986                }
987            }
988            None => return true,
989        };
990        if let Some(ty) = self.ty(hash) {
991            ty.is_anon()
992        } else {
993            false
994        }
995    }
996}
997
998/// An inherited type of a struct or union.
999#[derive(Debug, Default, Clone)]
1000pub struct Inherit {
1001    pub(crate) ty: TypeOffset,
1002    // Defaults to 0, so always present.
1003    pub(crate) bit_offset: u64,
1004}
1005
1006impl Inherit {
1007    /// The debuginfo offset of the inherited type.
1008    #[inline]
1009    pub fn type_offset(&self) -> TypeOffset {
1010        self.ty
1011    }
1012
1013    /// The inherited type.
1014    pub fn ty<'a, 'input>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1015        Type::from_offset(hash, self.ty)
1016    }
1017
1018    /// The offset in bits of the inherited type within the struct.
1019    #[inline]
1020    pub fn bit_offset(&self) -> u64 {
1021        self.bit_offset
1022    }
1023
1024    /// The size in bits of the inherited type.
1025    pub fn bit_size(&self, hash: &FileHash) -> Option<u64> {
1026        self.ty(hash).and_then(|v| v.byte_size(hash).map(|v| v * 8))
1027    }
1028}
1029
1030/// The layout of an item (member or padding) within a struct.
1031#[derive(Debug, Clone)]
1032pub struct Layout<'input, 'item>
1033where
1034    'input: 'item,
1035{
1036    /// The offset in bits of the item within the struct.
1037    pub bit_offset: u64,
1038    /// The size in bits of the item.
1039    pub bit_size: Size,
1040    /// The member or padding.
1041    pub item: LayoutItem<'input, 'item>,
1042}
1043
1044/// The item in a `Layout`.
1045#[derive(Debug, Clone)]
1046pub enum LayoutItem<'input, 'item> {
1047    /// Padding.
1048    Padding,
1049    /// A member.
1050    Member(&'item Member<'input>),
1051    /// A variant part.
1052    VariantPart(&'item VariantPart<'input>),
1053    /// An inherited type.
1054    Inherit(&'item Inherit),
1055}
1056
1057fn layout<'input, 'item>(
1058    members: &'item [Member<'input>],
1059    inherits: &'item [Inherit],
1060    variant_parts: &'item [VariantPart<'input>],
1061    base_bit_offset: u64,
1062    bit_size: Option<u64>,
1063    hash: &FileHash,
1064) -> Vec<Layout<'input, 'item>> {
1065    let mut members: Vec<_> = members
1066        .iter()
1067        .map(|member| Layout {
1068            bit_offset: member.bit_offset() - base_bit_offset,
1069            bit_size: member.bit_size(hash).into(),
1070            item: LayoutItem::Member(member),
1071        })
1072        .collect();
1073    members.extend(inherits.iter().map(|inherit| Layout {
1074        bit_offset: inherit.bit_offset() - base_bit_offset,
1075        bit_size: inherit.bit_size(hash).into(),
1076        item: LayoutItem::Inherit(inherit),
1077    }));
1078    members.extend(variant_parts.iter().map(|variant_part| Layout {
1079        bit_offset: variant_part.bit_offset() - base_bit_offset,
1080        bit_size: variant_part.bit_size(hash).into(),
1081        item: LayoutItem::VariantPart(variant_part),
1082    }));
1083    members.sort_by(|a, b| {
1084        a.bit_offset
1085            .cmp(&b.bit_offset)
1086            .then_with(|| a.bit_size.cmp(&b.bit_size))
1087    });
1088
1089    let mut next_bit_offset = bit_size;
1090    let mut layout = Vec::new();
1091    for member in members.into_iter().rev() {
1092        if let (Some(bit_size), Some(next_bit_offset)) = (member.bit_size.get(), next_bit_offset) {
1093            let bit_offset = member.bit_offset + bit_size;
1094            if next_bit_offset > bit_offset {
1095                let bit_size = next_bit_offset - bit_offset;
1096                layout.push(Layout {
1097                    bit_offset,
1098                    bit_size: Size::new(bit_size),
1099                    item: LayoutItem::Padding,
1100                });
1101            }
1102        }
1103        next_bit_offset = Some(member.bit_offset);
1104        layout.push(member);
1105    }
1106    if let Some(first_bit_offset) = layout.last().map(|x| x.bit_offset)
1107        && first_bit_offset > 0
1108    {
1109        layout.push(Layout {
1110            bit_offset: 0,
1111            bit_size: Size::new(first_bit_offset),
1112            item: LayoutItem::Padding,
1113        });
1114    }
1115    layout.reverse();
1116    layout
1117}
1118
1119/// An enumeration type.
1120#[derive(Debug, Default, Clone)]
1121pub struct EnumerationType<'input> {
1122    pub(crate) offset: TypeOffset,
1123    pub(crate) namespace: Option<Arc<Namespace<'input>>>,
1124    pub(crate) name: Option<&'input str>,
1125    pub(crate) source: Source<'input>,
1126    pub(crate) declaration: bool,
1127    pub(crate) ty: TypeOffset,
1128    pub(crate) byte_size: Size,
1129}
1130
1131impl<'input> EnumerationType<'input> {
1132    /// The namespace of the type.
1133    pub fn namespace(&self) -> Option<&Namespace<'input>> {
1134        self.namespace.as_deref()
1135    }
1136
1137    /// The name of the type.
1138    #[inline]
1139    pub fn name(&self) -> Option<&'input str> {
1140        self.name
1141    }
1142
1143    /// The source information for the type.
1144    #[inline]
1145    pub fn source(&self) -> &Source<'input> {
1146        &self.source
1147    }
1148
1149    /// Return true if this is a declaration.
1150    #[inline]
1151    pub fn is_declaration(&self) -> bool {
1152        self.declaration
1153    }
1154
1155    /// The underlying type of the enumeration.
1156    #[inline]
1157    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1158        Type::from_offset(hash, self.ty)
1159    }
1160
1161    /// The size in bytes of an instance of this type.
1162    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
1163        if self.byte_size.is_some() {
1164            self.byte_size.get()
1165        } else {
1166            self.ty(hash).and_then(|v| v.byte_size(hash))
1167        }
1168    }
1169
1170    /// The encoding of the underlying type, if it is a base type.
1171    pub fn encoding(&self, hash: &FileHash) -> Option<BaseTypeEncoding> {
1172        let ty = self.ty(hash)?;
1173        if let TypeKind::Base(base) = &ty.kind {
1174            return Some(base.encoding());
1175        }
1176        None
1177    }
1178
1179    /// The enumerators of this type.
1180    pub fn enumerators(&self, hash: &FileHash<'input>) -> Vec<Enumerator<'input>> {
1181        hash.file.get_enumerators(
1182            self.offset,
1183            self.encoding(hash).unwrap_or(BaseTypeEncoding::Signed),
1184        )
1185    }
1186
1187    /// Compare the identifying information of two types.
1188    ///
1189    /// Enumerations are considered equal if their names are equal.
1190    ///
1191    /// This can be used to sort, and to determine if two types refer to the same definition
1192    /// (even if there are differences in the definitions).
1193    pub fn cmp_id(a: &EnumerationType, b: &EnumerationType) -> cmp::Ordering {
1194        Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
1195    }
1196}
1197
1198/// A member of an enumeration.
1199#[derive(Debug, Default, Clone)]
1200pub struct Enumerator<'input> {
1201    pub(crate) name: Option<&'input str>,
1202    pub(crate) value: EnumeratorValue,
1203}
1204
1205impl<'input> Enumerator<'input> {
1206    /// The name of the enumerator.
1207    #[inline]
1208    pub fn name(&self) -> Option<&'input str> {
1209        self.name
1210    }
1211
1212    /// The value of the enumerator.
1213    #[inline]
1214    pub fn value(&self) -> EnumeratorValue {
1215        self.value
1216    }
1217}
1218
1219/// The encoding of a base type.
1220#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1221pub enum EnumeratorValue {
1222    /// Unsupported or unspecified value.
1223    #[default]
1224    Other,
1225    /// A signed integer value.
1226    ///
1227    /// The size is determined by the enumeration.
1228    Signed(i64),
1229    /// An unsigned integer value.
1230    ///
1231    /// The size is determined by the enumeration.
1232    Unsigned(u64),
1233}
1234
1235/// A type for an array of elements.
1236#[derive(Debug, Default, Clone)]
1237pub struct ArrayType<'input> {
1238    pub(crate) ty: TypeOffset,
1239    pub(crate) count: Size,
1240    pub(crate) counts: Box<[Size]>,
1241    pub(crate) byte_size: Size,
1242    pub(crate) phantom: marker::PhantomData<&'input str>,
1243}
1244
1245impl<'input> ArrayType<'input> {
1246    /// The type of the elements in the array.
1247    pub fn element_type<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1248        Type::from_offset(hash, self.ty)
1249    }
1250
1251    /// The size in bytes of an element in the array.
1252    pub fn element_byte_size<'a>(&self, hash: &'a FileHash<'input>) -> Option<u64> {
1253        let ty = self.element_type(hash)?;
1254        ty.byte_size(hash)
1255    }
1256
1257    /// The size in bytes of an instance of this type.
1258    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
1259        if self.byte_size.is_some() {
1260            self.byte_size.get()
1261        } else if let Some(mut size) = self.element_byte_size(hash) {
1262            let counts = self.counts_as_slice();
1263            if counts.is_empty() {
1264                return None;
1265            }
1266            for count in counts.iter().copied() {
1267                if let Some(count) = count.get() {
1268                    size *= count;
1269                } else {
1270                    return None;
1271                }
1272            }
1273            Some(size)
1274        } else {
1275            None
1276        }
1277    }
1278
1279    fn counts_as_slice(&self) -> &[Size] {
1280        if self.counts.is_empty() {
1281            std::slice::from_ref(&self.count)
1282        } else {
1283            &self.counts[..]
1284        }
1285    }
1286
1287    /// The number of elements in each dimension of the array.
1288    ///
1289    /// `None` is used for unknown dimensions.
1290    pub fn counts(&self) -> impl Iterator<Item = Option<u64>> + '_ {
1291        self.counts_as_slice().iter().map(|v| v.get())
1292    }
1293
1294    /// Compare the identifying information of two types.
1295    ///
1296    /// Array types are considered equal if the element identifiers and counts are equal.
1297    ///
1298    /// This can be used to sort, and to determine if two types refer to the same definition
1299    /// (even if there are differences in the definitions).
1300    pub fn cmp_id(
1301        hash_a: &FileHash,
1302        a: &ArrayType,
1303        hash_b: &FileHash,
1304        b: &ArrayType,
1305    ) -> cmp::Ordering {
1306        match (&a.element_type(hash_a), &b.element_type(hash_b)) {
1307            (Some(ty_a), Some(ty_b)) => {
1308                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
1309                if ord != cmp::Ordering::Equal {
1310                    return ord;
1311                }
1312            }
1313            (Some(_), None) => {
1314                return cmp::Ordering::Less;
1315            }
1316            (None, Some(_)) => {
1317                return cmp::Ordering::Greater;
1318            }
1319            (None, None) => {}
1320        }
1321        a.count.cmp(&b.count)
1322    }
1323}
1324
1325/// A subrange of another type.
1326#[derive(Debug, Default, Clone)]
1327pub struct SubrangeType<'input> {
1328    pub(crate) name: Option<&'input str>,
1329    pub(crate) ty: TypeOffset,
1330    pub(crate) lower: Option<u64>,
1331    pub(crate) upper: Option<u64>,
1332    pub(crate) byte_size: Size,
1333}
1334
1335impl<'input> SubrangeType<'input> {
1336    /// The name of the subrange.
1337    #[inline]
1338    pub fn name(&self) -> Option<&'input str> {
1339        self.name
1340    }
1341
1342    /// The underlying type of the subrange.
1343    #[inline]
1344    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1345        Type::from_offset(hash, self.ty)
1346    }
1347
1348    /// The lower bound of the subrange (inclusive).
1349    #[inline]
1350    pub fn lower(&self) -> Option<u64> {
1351        self.lower
1352    }
1353
1354    /// The upper bound of the subrange (inclusive).
1355    #[inline]
1356    pub fn upper(&self) -> Option<u64> {
1357        self.upper
1358    }
1359
1360    /// The size in bytes of an instance of this type.
1361    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
1362        if self.byte_size.is_some() {
1363            self.byte_size.get()
1364        } else {
1365            self.ty(hash).and_then(|v| v.byte_size(hash))
1366        }
1367    }
1368
1369    /// Compare the identifying information of two types.
1370    ///
1371    /// Subrange types are considered equal if the underlying type and bounds are equal.
1372    ///
1373    /// This can be used to sort, and to determine if two types refer to the same definition
1374    /// (even if there are differences in the definitions).
1375    pub fn cmp_id(
1376        hash_a: &FileHash,
1377        a: &SubrangeType,
1378        hash_b: &FileHash,
1379        b: &SubrangeType,
1380    ) -> cmp::Ordering {
1381        match (&a.ty(hash_a), &b.ty(hash_b)) {
1382            (Some(ty_a), Some(ty_b)) => {
1383                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
1384                if ord != cmp::Ordering::Equal {
1385                    return ord;
1386                }
1387            }
1388            (Some(_), None) => {
1389                return cmp::Ordering::Less;
1390            }
1391            (None, Some(_)) => {
1392                return cmp::Ordering::Greater;
1393            }
1394            (None, None) => {}
1395        }
1396        a.lower.cmp(&b.lower).then_with(|| a.upper.cmp(&b.upper))
1397    }
1398}
1399
1400/// A function type.
1401#[derive(Debug, Default, Clone)]
1402pub struct FunctionType<'input> {
1403    pub(crate) parameters: Vec<ParameterType<'input>>,
1404    pub(crate) return_type: TypeOffset,
1405    pub(crate) byte_size: Size,
1406}
1407
1408impl<'input> FunctionType<'input> {
1409    /// The parameters of the function.
1410    #[inline]
1411    pub fn parameters(&self) -> &[ParameterType<'input>] {
1412        &self.parameters
1413    }
1414
1415    /// The return type of the function.
1416    #[inline]
1417    pub fn return_type<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1418        Type::from_offset(hash, self.return_type)
1419    }
1420
1421    /// The size in bytes of an instance of this type.
1422    #[inline]
1423    pub fn byte_size(&self) -> Option<u64> {
1424        self.byte_size.get()
1425    }
1426
1427    /// Compare the identifying information of two types.
1428    ///
1429    /// Function types are considered equal if they have the same parameter types and
1430    /// return types. Parameter names are ignored.
1431    ///
1432    /// This can be used to sort, and to determine if two types refer to the same definition
1433    /// (even if there are differences in the definitions).
1434    pub fn cmp_id(
1435        hash_a: &FileHash,
1436        a: &FunctionType,
1437        hash_b: &FileHash,
1438        b: &FunctionType,
1439    ) -> cmp::Ordering {
1440        for (parameter_a, parameter_b) in a.parameters.iter().zip(b.parameters.iter()) {
1441            let ord = ParameterType::cmp_id(hash_a, parameter_a, hash_b, parameter_b);
1442            if ord != cmp::Ordering::Equal {
1443                return ord;
1444            }
1445        }
1446
1447        let ord = a.parameters.len().cmp(&b.parameters.len());
1448        if ord != cmp::Ordering::Equal {
1449            return ord;
1450        }
1451
1452        match (&a.return_type(hash_a), &b.return_type(hash_b)) {
1453            (Some(ty_a), Some(ty_b)) => {
1454                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
1455                if ord != cmp::Ordering::Equal {
1456                    return ord;
1457                }
1458            }
1459            (Some(_), None) => {
1460                return cmp::Ordering::Less;
1461            }
1462            (None, Some(_)) => {
1463                return cmp::Ordering::Greater;
1464            }
1465            (None, None) => {}
1466        }
1467
1468        cmp::Ordering::Equal
1469    }
1470}
1471
1472/// The type of a function parameter.
1473#[derive(Debug, Default, Clone)]
1474pub struct ParameterType<'input> {
1475    pub(crate) offset: ParameterOffset,
1476    pub(crate) name: Option<&'input str>,
1477    pub(crate) ty: TypeOffset,
1478}
1479
1480impl<'input> ParameterType<'input> {
1481    /// The name of the parameter.
1482    #[inline]
1483    pub fn name(&self) -> Option<&'input str> {
1484        self.name
1485    }
1486
1487    /// The type of the parameter.
1488    #[inline]
1489    pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
1490        Type::from_offset(hash, self.ty)
1491    }
1492
1493    /// Compare the identifying information of two types.
1494    ///
1495    /// Parameters are considered equal if they have the same types.
1496    /// Parameter names are ignored.
1497    pub fn cmp_id(
1498        hash_a: &FileHash,
1499        a: &ParameterType,
1500        hash_b: &FileHash,
1501        b: &ParameterType,
1502    ) -> cmp::Ordering {
1503        match (&a.ty(hash_a), &b.ty(hash_b)) {
1504            (Some(ty_a), Some(ty_b)) => Type::cmp_id(hash_a, ty_a, hash_b, ty_b),
1505            (Some(_), None) => cmp::Ordering::Less,
1506            (None, Some(_)) => cmp::Ordering::Greater,
1507            (None, None) => cmp::Ordering::Equal,
1508        }
1509    }
1510}
1511
1512/// An unspecified type.
1513#[derive(Debug, Default, Clone)]
1514pub struct UnspecifiedType<'input> {
1515    pub(crate) namespace: Option<Arc<Namespace<'input>>>,
1516    pub(crate) name: Option<&'input str>,
1517}
1518
1519impl<'input> UnspecifiedType<'input> {
1520    /// The namespace of the type.
1521    pub fn namespace(&self) -> Option<&Namespace<'input>> {
1522        self.namespace.as_deref()
1523    }
1524
1525    /// The name of the type.
1526    #[inline]
1527    pub fn name(&self) -> Option<&'input str> {
1528        self.name
1529    }
1530
1531    /// Compare the identifying information of two types.
1532    ///
1533    /// Unspecified types are considered equal if they have the same name.
1534    ///
1535    /// This can be used to sort, and to determine if two types refer to the same definition
1536    /// (even if there are differences in the definitions).
1537    pub fn cmp_id(a: &UnspecifiedType, b: &UnspecifiedType) -> cmp::Ordering {
1538        Namespace::cmp_ns_and_name(a.namespace(), a.name(), b.namespace(), b.name())
1539    }
1540}
1541
1542/// A type for a pointer to a member of a containing type.
1543#[derive(Debug, Default, Clone)]
1544pub struct PointerToMemberType {
1545    pub(crate) ty: TypeOffset,
1546    pub(crate) containing_ty: TypeOffset,
1547    pub(crate) byte_size: Size,
1548    // TODO: hack
1549    pub(crate) address_size: Option<u64>,
1550}
1551
1552impl PointerToMemberType {
1553    /// The type of the member.
1554    #[inline]
1555    pub fn member_type<'a, 'input>(
1556        &self,
1557        hash: &'a FileHash<'input>,
1558    ) -> Option<Cow<'a, Type<'input>>> {
1559        Type::from_offset(hash, self.ty)
1560    }
1561
1562    /// The containing type.
1563    #[inline]
1564    pub fn containing_type<'a, 'input>(
1565        &self,
1566        hash: &'a FileHash<'input>,
1567    ) -> Option<Cow<'a, Type<'input>>> {
1568        Type::from_offset(hash, self.containing_ty)
1569    }
1570
1571    /// The size in bytes of an instance of this type.
1572    pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
1573        if self.byte_size.is_some() {
1574            return self.byte_size.get();
1575        }
1576        // TODO: this probably depends on the ABI
1577        self.member_type(hash).and_then(|ty| {
1578            if ty.is_function(hash) {
1579                self.address_size.map(|v| v * 2)
1580            } else {
1581                self.address_size
1582            }
1583        })
1584    }
1585
1586    /// Compare the identifying information of two types.
1587    ///
1588    /// Pointer to member types are considered equal if both the member type and containing
1589    /// type are equal.
1590    ///
1591    /// This can be used to sort, and to determine if two types refer to the same definition
1592    /// (even if there are differences in the definitions).
1593    pub fn cmp_id(
1594        hash_a: &FileHash,
1595        a: &PointerToMemberType,
1596        hash_b: &FileHash,
1597        b: &PointerToMemberType,
1598    ) -> cmp::Ordering {
1599        match (&a.containing_type(hash_a), &b.containing_type(hash_b)) {
1600            (Some(ty_a), Some(ty_b)) => {
1601                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
1602                if ord != cmp::Ordering::Equal {
1603                    return ord;
1604                }
1605            }
1606            (Some(_), None) => {
1607                return cmp::Ordering::Less;
1608            }
1609            (None, Some(_)) => {
1610                return cmp::Ordering::Greater;
1611            }
1612            (None, None) => {}
1613        }
1614        match (&a.member_type(hash_a), &b.member_type(hash_b)) {
1615            (Some(ty_a), Some(ty_b)) => {
1616                let ord = Type::cmp_id(hash_a, ty_a, hash_b, ty_b);
1617                if ord != cmp::Ordering::Equal {
1618                    return ord;
1619                }
1620            }
1621            (Some(_), None) => {
1622                return cmp::Ordering::Less;
1623            }
1624            (None, Some(_)) => {
1625                return cmp::Ordering::Greater;
1626            }
1627            (None, None) => {}
1628        }
1629        cmp::Ordering::Equal
1630    }
1631}