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#[derive(Debug, Clone)]
14pub enum TypeKind<'input> {
15 Void,
17 Base(BaseType<'input>),
19 Def(TypeDef<'input>),
21 Struct(StructType<'input>),
23 Union(UnionType<'input>),
25 Enumeration(EnumerationType<'input>),
27 Array(ArrayType<'input>),
29 Function(FunctionType<'input>),
31 Unspecified(UnspecifiedType<'input>),
33 PointerToMember(PointerToMemberType),
35 Modifier(TypeModifier<'input>),
37 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#[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 #[inline]
80 pub fn is_none(self) -> bool {
81 self == Self::none()
82 }
83
84 #[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#[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 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 #[inline]
148 pub fn is_void(&self) -> bool {
149 matches!(self.kind, TypeKind::Void)
150 }
151
152 #[inline]
154 pub fn id(&self) -> usize {
155 self.id.get()
156 }
157
158 #[inline]
160 pub fn set_id(&self, id: usize) {
161 self.id.set(id)
162 }
163
164 #[inline]
166 pub fn offset(&self) -> TypeOffset {
167 self.offset
168 }
169
170 #[inline]
172 pub fn kind(&self) -> &TypeKind<'input> {
173 &self.kind
174 }
175
176 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 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 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 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 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#[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 pub(crate) address_size: Option<u64>,
301}
302
303#[derive(Debug, PartialEq, Eq, Clone, Copy)]
305pub enum TypeModifierKind {
306 Pointer,
308 Reference,
310 Const,
312 Packed,
314 Volatile,
316 Restrict,
318 Shared,
320 RvalueReference,
322 Atomic,
324 #[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 #[inline]
354 pub fn name(&self) -> Option<&'input str> {
355 self.name
356 }
357
358 #[inline]
360 pub fn kind(&self) -> TypeModifierKind {
361 self.kind
362 }
363
364 #[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 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 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#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
433pub enum Endianity {
434 #[default]
436 Default,
437 Big,
439 Little,
441}
442
443#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
445pub enum BaseTypeEncoding {
446 #[default]
448 Other,
449 Boolean,
451 Address,
453 Signed,
455 SignedChar,
457 Unsigned,
459 UnsignedChar,
461 Float,
463}
464
465impl BaseTypeEncoding {
466 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#[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 #[inline]
493 pub fn name(&self) -> Option<&'input str> {
494 self.name
495 }
496
497 #[inline]
499 pub fn byte_size(&self) -> Option<u64> {
500 self.byte_size.get()
501 }
502
503 #[inline]
505 pub fn encoding(&self) -> BaseTypeEncoding {
506 self.encoding
507 }
508
509 #[inline]
511 pub fn endianity(&self) -> Endianity {
512 self.endianity
513 }
514
515 fn cmp_id(a: &BaseType, b: &BaseType) -> cmp::Ordering {
522 a.name.cmp(&b.name)
523 }
524}
525
526#[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 pub fn namespace(&self) -> Option<&Namespace<'input>> {
538 self.namespace.as_deref()
539 }
540
541 #[inline]
543 pub fn name(&self) -> Option<&'input str> {
544 self.name
545 }
546
547 #[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 #[inline]
555 pub fn source(&self) -> &Source<'input> {
556 &self.source
557 }
558
559 pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
561 self.ty(hash).and_then(|v| v.byte_size(hash))
562 }
563
564 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#[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 pub fn namespace(&self) -> Option<&Namespace<'input>> {
592 self.namespace.as_deref()
593 }
594
595 #[inline]
597 pub fn name(&self) -> Option<&'input str> {
598 self.name
599 }
600
601 #[inline]
603 pub fn source(&self) -> &Source<'input> {
604 &self.source
605 }
606
607 #[inline]
609 pub fn bit_size(&self) -> Option<u64> {
610 self.byte_size.get().map(|v| v * 8)
611 }
612
613 #[inline]
615 pub fn byte_size(&self) -> Option<u64> {
616 self.byte_size.get()
617 }
618
619 #[inline]
621 pub fn is_declaration(&self) -> bool {
622 self.declaration
623 }
624
625 pub fn is_anon(&self) -> bool {
627 self.name.is_none() || Namespace::is_anon_type(&self.namespace)
628 }
629
630 #[inline]
632 pub fn members(&self) -> &[Member<'input>] {
633 &self.members
634 }
635
636 #[inline]
638 pub fn variant_parts(&self) -> &[VariantPart<'input>] {
639 &self.variant_parts
640 }
641
642 #[inline]
644 pub fn inherits(&self) -> &[Inherit] {
645 &self.inherits
646 }
647
648 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 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#[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 pub fn namespace(&self) -> Option<&Namespace<'input>> {
685 self.namespace.as_deref()
686 }
687
688 #[inline]
690 pub fn name(&self) -> Option<&'input str> {
691 self.name
692 }
693
694 #[inline]
696 pub fn source(&self) -> &Source<'input> {
697 &self.source
698 }
699
700 #[inline]
702 pub fn byte_size(&self) -> Option<u64> {
703 self.byte_size.get()
704 }
705
706 #[inline]
708 pub fn is_declaration(&self) -> bool {
709 self.declaration
710 }
711
712 pub fn is_anon(&self) -> bool {
714 self.name.is_none() || Namespace::is_anon_type(&self.namespace)
715 }
716
717 #[inline]
719 pub fn members(&self) -> &[Member<'input>] {
720 &self.members
721 }
722
723 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#[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 #[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 #[inline]
755 pub fn variants(&self) -> &[Variant<'input>] {
756 &self.variants
757 }
758
759 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 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#[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 #[inline]
807 pub fn discriminant_value(&self) -> Option<u64> {
808 self.discr_value
809 }
810
811 #[inline]
815 pub fn name(&self) -> Option<&'input str> {
816 self.name
817 }
818
819 #[inline]
823 pub fn source(&self) -> &Source<'input> {
824 &self.source
825 }
826
827 #[inline]
829 pub fn members(&self) -> &[Member<'input>] {
830 &self.members
831 }
832
833 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 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 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 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#[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#[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 pub(crate) bit_offset: u64,
926 pub(crate) bit_size: Size,
927}
928
929impl<'input> Member<'input> {
930 #[inline]
932 pub fn name(&self) -> Option<&'input str> {
933 self.name
934 }
935
936 #[inline]
938 pub fn source(&self) -> &Source<'input> {
939 &self.source
940 }
941
942 #[inline]
944 pub fn offset(&self) -> MemberOffset {
945 self.offset
946 }
947
948 #[inline]
950 pub fn type_offset(&self) -> TypeOffset {
951 self.ty
952 }
953
954 pub fn ty<'a>(&self, hash: &'a FileHash<'input>) -> Option<Cow<'a, Type<'input>>> {
956 Type::from_offset(hash, self.ty)
957 }
958
959 #[inline]
961 pub fn bit_offset(&self) -> u64 {
962 self.bit_offset
963 }
964
965 #[inline]
967 pub fn is_bit_field(&self) -> bool {
968 self.bit_size.is_some()
969 }
970
971 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 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#[derive(Debug, Default, Clone)]
1000pub struct Inherit {
1001 pub(crate) ty: TypeOffset,
1002 pub(crate) bit_offset: u64,
1004}
1005
1006impl Inherit {
1007 #[inline]
1009 pub fn type_offset(&self) -> TypeOffset {
1010 self.ty
1011 }
1012
1013 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 #[inline]
1020 pub fn bit_offset(&self) -> u64 {
1021 self.bit_offset
1022 }
1023
1024 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#[derive(Debug, Clone)]
1032pub struct Layout<'input, 'item>
1033where
1034 'input: 'item,
1035{
1036 pub bit_offset: u64,
1038 pub bit_size: Size,
1040 pub item: LayoutItem<'input, 'item>,
1042}
1043
1044#[derive(Debug, Clone)]
1046pub enum LayoutItem<'input, 'item> {
1047 Padding,
1049 Member(&'item Member<'input>),
1051 VariantPart(&'item VariantPart<'input>),
1053 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#[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 pub fn namespace(&self) -> Option<&Namespace<'input>> {
1134 self.namespace.as_deref()
1135 }
1136
1137 #[inline]
1139 pub fn name(&self) -> Option<&'input str> {
1140 self.name
1141 }
1142
1143 #[inline]
1145 pub fn source(&self) -> &Source<'input> {
1146 &self.source
1147 }
1148
1149 #[inline]
1151 pub fn is_declaration(&self) -> bool {
1152 self.declaration
1153 }
1154
1155 #[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 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 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 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 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#[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 #[inline]
1208 pub fn name(&self) -> Option<&'input str> {
1209 self.name
1210 }
1211
1212 #[inline]
1214 pub fn value(&self) -> EnumeratorValue {
1215 self.value
1216 }
1217}
1218
1219#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
1221pub enum EnumeratorValue {
1222 #[default]
1224 Other,
1225 Signed(i64),
1229 Unsigned(u64),
1233}
1234
1235#[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 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 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 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 pub fn counts(&self) -> impl Iterator<Item = Option<u64>> + '_ {
1291 self.counts_as_slice().iter().map(|v| v.get())
1292 }
1293
1294 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#[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 #[inline]
1338 pub fn name(&self) -> Option<&'input str> {
1339 self.name
1340 }
1341
1342 #[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 #[inline]
1350 pub fn lower(&self) -> Option<u64> {
1351 self.lower
1352 }
1353
1354 #[inline]
1356 pub fn upper(&self) -> Option<u64> {
1357 self.upper
1358 }
1359
1360 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 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#[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 #[inline]
1411 pub fn parameters(&self) -> &[ParameterType<'input>] {
1412 &self.parameters
1413 }
1414
1415 #[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 #[inline]
1423 pub fn byte_size(&self) -> Option<u64> {
1424 self.byte_size.get()
1425 }
1426
1427 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#[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 #[inline]
1483 pub fn name(&self) -> Option<&'input str> {
1484 self.name
1485 }
1486
1487 #[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 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#[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 pub fn namespace(&self) -> Option<&Namespace<'input>> {
1522 self.namespace.as_deref()
1523 }
1524
1525 #[inline]
1527 pub fn name(&self) -> Option<&'input str> {
1528 self.name
1529 }
1530
1531 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#[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 pub(crate) address_size: Option<u64>,
1550}
1551
1552impl PointerToMemberType {
1553 #[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 #[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 pub fn byte_size(&self, hash: &FileHash) -> Option<u64> {
1573 if self.byte_size.is_some() {
1574 return self.byte_size.get();
1575 }
1576 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 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}