msft_typelib/typeinfo.rs
1//! [`TypeInfoEntry`] -- zero-copy view of an `MSFT_TypeInfoBase` (0x64 bytes).
2//!
3//! Each TypeInfo describes one top-level type in the library: an enum,
4//! record (struct), module, COM interface, dispatch interface, coclass,
5//! alias (typedef), or union. The 0x64-byte structure contains the type
6//! kind, function/variable counts, a GUID, flags, offsets into the name
7//! and string tables, version, custom data offset, and more.
8
9use crate::{
10 TypeKind,
11 util::{read_i16_le, read_i32_le, read_u32_le},
12};
13
14/// Zero-copy view of an `MSFT_TypeInfoBase` structure (0x64 bytes).
15///
16/// Each TypeInfo describes one type in the library: an enum, struct,
17/// module, COM interface, dispatch interface, coclass, alias, or union.
18///
19/// Constructed by [`TypeLib::typeinfo`](crate::TypeLib::typeinfo);
20/// the backing slice is guaranteed to be at least [`SIZE`](Self::SIZE) bytes.
21#[derive(Clone, Copy, Debug)]
22pub struct TypeInfoEntry<'a> {
23 bytes: &'a [u8],
24}
25
26impl<'a> TypeInfoEntry<'a> {
27 /// Wraps a 0x64-byte slice as a `TypeInfoEntry`.
28 pub(crate) fn new(bytes: &'a [u8]) -> Self {
29 Self { bytes }
30 }
31
32 /// Size of the fixed `MSFT_TypeInfoBase` structure in bytes.
33 pub const SIZE: usize = 0x64;
34
35 /// Returns the raw backing bytes.
36 #[inline]
37 pub fn as_bytes(&self) -> &'a [u8] {
38 self.bytes
39 }
40
41 /// Type kind (low 4 bits of the `typekind` field).
42 #[inline]
43 pub fn typekind(&self) -> TypeKind {
44 let raw = read_u32_le(self.bytes, 0x00).unwrap_or(0);
45 TypeKind::from_raw((raw & 0x0F) as u8)
46 }
47
48 /// Raw `typekind` field (includes alignment in bits 11-15).
49 #[inline]
50 pub fn typekind_raw(&self) -> u32 {
51 read_u32_le(self.bytes, 0x00).unwrap_or(0)
52 }
53
54 /// Absolute file offset to the func/var data block.
55 ///
56 /// Returns a negative value when no data block exists.
57 #[inline]
58 pub fn memoffset(&self) -> i32 {
59 read_i32_le(self.bytes, 0x04).unwrap_or(-1)
60 }
61
62 /// First reference offset in `pRefTab` (for coclasses), or `-1`.
63 #[inline]
64 pub fn res2(&self) -> i32 {
65 read_i32_le(self.bytes, 0x08).unwrap_or(-1)
66 }
67
68 /// Raw `cElement` field.
69 ///
70 /// Low 16 bits = function count, high 16 bits = variable count.
71 #[inline]
72 pub fn celement(&self) -> u32 {
73 read_u32_le(self.bytes, 0x18).unwrap_or(0)
74 }
75
76 /// Number of functions (low 16 bits of `cElement`).
77 #[inline]
78 pub fn func_count(&self) -> u16 {
79 (self.celement() & 0xFFFF) as u16
80 }
81
82 /// Number of variables (high 16 bits of `cElement`).
83 #[inline]
84 pub fn var_count(&self) -> u16 {
85 (self.celement() >> 16) as u16
86 }
87
88 /// Offset into the GUID table, or `-1` if this type has no GUID.
89 #[inline]
90 pub fn guid_offset(&self) -> i32 {
91 read_i32_le(self.bytes, 0x2C).unwrap_or(-1)
92 }
93
94 /// `TYPEFLAG_*` flags.
95 #[inline]
96 pub fn flags(&self) -> u32 {
97 read_u32_le(self.bytes, 0x30).unwrap_or(0)
98 }
99
100 /// Offset into the name table for this type's name.
101 #[inline]
102 pub fn name_offset(&self) -> i32 {
103 read_i32_le(self.bytes, 0x34).unwrap_or(-1)
104 }
105
106 /// Element version (set with `SetVersion`).
107 #[inline]
108 pub fn version(&self) -> u32 {
109 read_u32_le(self.bytes, 0x38).unwrap_or(0)
110 }
111
112 /// Offset into the string table for the doc string, or `-1`.
113 #[inline]
114 pub fn docstring_offset(&self) -> i32 {
115 read_i32_le(self.bytes, 0x3C).unwrap_or(-1)
116 }
117
118 /// Number of implemented interfaces (for coclasses).
119 #[inline]
120 pub fn cimpltypes(&self) -> i16 {
121 read_i16_le(self.bytes, 0x4C).unwrap_or(0)
122 }
123
124 /// Virtual function table size in bytes.
125 #[inline]
126 pub fn cb_size_vft(&self) -> i16 {
127 read_i16_le(self.bytes, 0x4E).unwrap_or(0)
128 }
129
130 /// Instance size in bytes.
131 #[inline]
132 pub fn size(&self) -> i32 {
133 read_i32_le(self.bytes, 0x50).unwrap_or(0)
134 }
135
136 /// For `ALIAS` types: the aliased type descriptor. Otherwise `-1`.
137 #[inline]
138 pub fn datatype1(&self) -> i32 {
139 read_i32_le(self.bytes, 0x54).unwrap_or(-1)
140 }
141
142 /// For `ALIAS` types: secondary aliased type descriptor. Otherwise `-1`.
143 #[inline]
144 pub fn datatype2(&self) -> i32 {
145 read_i32_le(self.bytes, 0x58).unwrap_or(-1)
146 }
147
148 /// Help string context at offset 0x40.
149 #[inline]
150 pub fn helpstringcontext(&self) -> i32 {
151 read_i32_le(self.bytes, 0x40).unwrap_or(0)
152 }
153
154 /// Help context at offset 0x44.
155 #[inline]
156 pub fn helpcontext(&self) -> i32 {
157 read_i32_le(self.bytes, 0x44).unwrap_or(0)
158 }
159
160 /// Offset into the CDGuids directory for this type's custom data, or `-1`.
161 #[inline]
162 pub fn cust_data_offset(&self) -> i32 {
163 read_i32_le(self.bytes, 0x48).unwrap_or(-1)
164 }
165
166 /// Reserved field at offset 0x0C (`-1` if no element, else `(N-1)*0x38`).
167 #[inline]
168 pub fn res3(&self) -> i32 {
169 read_i32_le(self.bytes, 0x0C).unwrap_or(-1)
170 }
171
172 /// Reserved field at offset 0x5C (always 0).
173 #[inline]
174 pub fn res18(&self) -> i32 {
175 read_i32_le(self.bytes, 0x5C).unwrap_or(0)
176 }
177
178 /// Reserved field at offset 0x60 (always `-1`).
179 #[inline]
180 pub fn res19(&self) -> i32 {
181 read_i32_le(self.bytes, 0x60).unwrap_or(-1)
182 }
183}