1use crate::{Base, Profile, Struct, Type};
7
8#[allow(missing_docs)]
10pub enum FieldValue<'a> {
11 Void,
12 Bool(bool),
13 Char8(u8),
14 Char16(u16),
15 Char32(u32),
16
17 I8(i8),
18 I16(i16),
19 I32(i32),
20 I64(i64),
21 I128(i128),
22
23 U8(u8),
24 U16(u16),
25 U32(u32),
26 U64(u64),
27 U128(u128),
28
29 F8(u8),
30 F16(u16),
31 F32(f32),
32 F64(f64),
33 F128(u128),
34
35 Enum {
36 type_name: &'a str,
37 size: u64,
38 value: u64,
39 },
40 Struct {
41 type_name: &'a str,
42 size: u64,
43 data: &'a [u8],
44 },
45 Array {
46 subtype: Box<FieldValueKind<'a>>,
47 dims: Vec<u64>,
48 size: u64,
49 data: &'a [u8],
50 },
51 Pointer {
52 subtype: Box<FieldValueKind<'a>>,
53 size: u64,
54 value: u64,
55 },
56 Bitfield {
57 bit_position: u64,
58 bit_length: u64,
59 size: u64,
60 value: u64,
61 },
62 Function {
63 value: u64,
64 },
65}
66
67impl FieldValue<'_> {
68 pub fn size(&self) -> u64 {
70 match self {
71 Self::Void => 0,
72 Self::Char8(_) | Self::I8(_) | Self::U8(_) | Self::F8(_) | Self::Bool(_) => 1,
73 Self::Char16(_) | Self::I16(_) | Self::U16(_) | Self::F16(_) => 2,
74 Self::Char32(_) | Self::I32(_) | Self::U32(_) | Self::F32(_) => 4,
75 Self::I64(_) | Self::U64(_) | Self::F64(_) => 8,
76 Self::I128(_) | Self::U128(_) | Self::F128(_) => 16,
77 Self::Enum { size, .. } => *size,
78 Self::Struct { size, .. } => *size,
79 Self::Array { size, .. } => *size,
80 Self::Pointer { size, .. } => *size,
81 Self::Bitfield { size, .. } => *size,
82 Self::Function { .. } => 0,
83 }
84 }
85}
86
87#[allow(missing_docs)]
89pub enum FieldValueKind<'a> {
90 Void,
91 Bool,
92 Char8,
93 Char16,
94 Char32,
95
96 I8,
97 I16,
98 I32,
99 I64,
100 I128,
101
102 U8,
103 U16,
104 U32,
105 U64,
106 U128,
107
108 F8,
109 F16,
110 F32,
111 F64,
112 F128,
113
114 Enum {
115 type_name: &'a str,
116 size: u64,
117 },
118 Struct {
119 type_name: &'a str,
120 size: u64,
121 },
122 Array {
123 subtype: Box<FieldValueKind<'a>>,
124 dims: Vec<u64>,
125 size: u64,
126 },
127 Pointer {
128 subtype: Box<FieldValueKind<'a>>,
129 size: u64,
130 },
131 Bitfield {
132 bit_position: u64,
133 bit_length: u64,
134 size: u64,
135 },
136 Function,
137}
138
139impl FieldValueKind<'_> {
140 pub fn size(&self) -> u64 {
142 match self {
143 Self::Void => 0,
144 Self::Char8 | Self::I8 | Self::U8 | Self::F8 | Self::Bool => 1,
145 Self::Char16 | Self::I16 | Self::U16 | Self::F16 => 2,
146 Self::Char32 | Self::I32 | Self::U32 | Self::F32 => 4,
147 Self::I64 | Self::U64 | Self::F64 => 8,
148 Self::I128 | Self::U128 | Self::F128 => 16,
149 Self::Enum { size, .. } => *size,
150 Self::Struct { size, .. } => *size,
151 Self::Array { size, .. } => *size,
152 Self::Pointer { size, .. } => *size,
153 Self::Bitfield { size, .. } => *size,
154 Self::Function { .. } => 0,
155 }
156 }
157}
158
159impl<'a> From<FieldValue<'a>> for FieldValueKind<'a> {
160 fn from(value: FieldValue<'a>) -> Self {
161 match value {
162 FieldValue::Void => Self::Void,
163 FieldValue::Bool(_) => Self::Bool,
164 FieldValue::Char8(_) => Self::Char8,
165 FieldValue::Char16(_) => Self::Char16,
166 FieldValue::Char32(_) => Self::Char32,
167
168 FieldValue::I8(_) => Self::I8,
169 FieldValue::I16(_) => Self::I16,
170 FieldValue::I32(_) => Self::I32,
171 FieldValue::I64(_) => Self::I64,
172 FieldValue::I128(_) => Self::I128,
173
174 FieldValue::U8(_) => Self::U8,
175 FieldValue::U16(_) => Self::U16,
176 FieldValue::U32(_) => Self::U32,
177 FieldValue::U64(_) => Self::U64,
178 FieldValue::U128(_) => Self::U128,
179
180 FieldValue::F8(_) => Self::F8,
181 FieldValue::F16(_) => Self::F16,
182 FieldValue::F32(_) => Self::F32,
183 FieldValue::F64(_) => Self::F64,
184 FieldValue::F128(_) => Self::F128,
185
186 FieldValue::Enum {
187 type_name, size, ..
188 } => Self::Enum { type_name, size },
189 FieldValue::Struct {
190 type_name, size, ..
191 } => Self::Struct { type_name, size },
192 FieldValue::Array {
193 subtype,
194 dims,
195 size,
196 ..
197 } => Self::Array {
198 subtype: Box::new(*subtype),
199 dims,
200 size,
201 },
202 FieldValue::Pointer { subtype, size, .. } => Self::Pointer {
203 subtype: Box::new(*subtype),
204 size,
205 },
206 FieldValue::Bitfield {
207 bit_position,
208 bit_length,
209 size,
210 ..
211 } => Self::Bitfield {
212 bit_position,
213 bit_length,
214 size,
215 },
216 FieldValue::Function { .. } => Self::Function,
217 }
218 }
219}
220
221pub struct StructField<'a> {
223 pub name: &'a str,
225
226 pub offset: usize,
228
229 pub value: FieldValue<'a>,
231}
232
233pub struct StructFieldKind<'a> {
235 pub name: &'a str,
237
238 pub offset: usize,
240
241 pub value: FieldValueKind<'a>,
243}
244
245pub fn visit_struct<E>(
250 profile: &Profile,
251 struct_def: &Struct,
252 mut visitor: impl FnMut(&StructField) -> Result<(), E>,
253 data: &[u8],
254) -> Result<(), E> {
255 for field in struct_def.fields() {
256 let offset = field.offset() as usize;
257 let value = make_value(profile, field.ty(), data, offset);
258
259 visitor(&StructField {
260 name: field.name(),
261 offset,
262 value,
263 })?;
264 }
265
266 Ok(())
267}
268
269pub fn visit_struct_schema<E>(
274 profile: &Profile,
275 struct_def: Struct,
276 mut visitor: impl FnMut(&StructFieldKind) -> Result<(), E>,
277) -> Result<(), E> {
278 for field in struct_def.fields() {
279 let offset = field.offset() as usize;
280 let value = make_value_kind(profile, field.ty());
281
282 visitor(&StructFieldKind {
283 name: field.name(),
284 offset,
285 value,
286 })?;
287 }
288
289 Ok(())
290}
291
292#[expect(clippy::unnecessary_cast)]
293fn make_value<'a>(
294 profile: &Profile,
295 ty: Type<'a>,
296 data: &'a [u8],
297 offset: usize,
298) -> FieldValue<'a> {
299 match &ty {
300 Type::Base(base) => match base {
301 Base::Void => FieldValue::Void,
302 Base::Bool => FieldValue::Bool(read_uint(data, offset, 1) != 0),
303 Base::Char8 => FieldValue::Char8(read_uint(data, offset, 1) as u8),
304 Base::Char16 => FieldValue::Char16(read_uint(data, offset, 2) as u16),
305 Base::Char32 => FieldValue::Char32(read_uint(data, offset, 4) as u32),
306
307 Base::I8 => FieldValue::I8(read_uint(data, offset, 1) as i8),
308 Base::I16 => FieldValue::I16(read_uint(data, offset, 2) as u16 as i16),
309 Base::I32 => FieldValue::I32(read_uint(data, offset, 4) as u32 as i32),
310 Base::I64 => FieldValue::I64(read_uint(data, offset, 8) as i64),
311 Base::I128 => FieldValue::I128(read_uint(data, offset, 16) as i128),
312
313 Base::U8 => FieldValue::U8(read_uint(data, offset, 1) as u8),
314 Base::U16 => FieldValue::U16(read_uint(data, offset, 2) as u16),
315 Base::U32 => FieldValue::U32(read_uint(data, offset, 4) as u32),
316 Base::U64 => FieldValue::U64(read_uint(data, offset, 8) as u64),
317 Base::U128 => FieldValue::U128(read_uint(data, offset, 16) as u128),
318 _ => {
319 let size = base.size() as usize;
320 let val = read_uint(data, offset, size);
321 match size {
322 1 => FieldValue::U8(val as u8),
323 2 => FieldValue::U16(val as u16),
324 4 => FieldValue::U32(val as u32),
325 8 => FieldValue::U64(val as u64),
326 16 => FieldValue::U128(val as u128),
327 _ => FieldValue::Void,
328 }
329 }
330 },
331 Type::Struct(sref) => FieldValue::Struct {
332 type_name: sref.name(),
333 size: profile.type_size(ty).unwrap_or(0),
334 data: &data[offset..],
335 },
336 Type::Pointer(ptr) => FieldValue::Pointer {
337 subtype: Box::new(make_value_kind(profile, ptr.subtype())),
338 size: profile.type_size(ty).unwrap_or(0),
339 value: read_uint(data, offset, ptr.size() as usize) as u64,
340 },
341 Type::Array(arr) => FieldValue::Array {
342 subtype: Box::new(make_value_kind(profile, arr.subtype())),
343 dims: arr.dims().collect(),
344 size: profile.type_size(ty).unwrap_or(0),
345 data: &data[offset..],
346 },
347 Type::Bitfield(bf) => {
348 let base_size = match bf.subtype() {
349 Type::Base(base) => base.size() as usize,
350 _ => (bf.bit_position() + bf.bit_length()).div_ceil(8) as usize,
351 };
352 FieldValue::Bitfield {
353 bit_position: bf.bit_position(),
354 bit_length: bf.bit_length(),
355 size: profile.type_size(ty).unwrap_or(0),
356 value: read_uint(data, offset, base_size) as u64,
357 }
358 }
359 Type::Enum(eref) => FieldValue::Enum {
360 type_name: eref.name(),
361 size: profile.type_size(ty).unwrap_or(0),
362 value: read_uint(data, offset, 8) as u64,
363 },
364 Type::Function => FieldValue::Function {
365 value: read_uint(data, offset, 8) as u64,
366 },
367 }
368}
369
370fn make_value_kind<'a>(profile: &Profile, ty: Type<'a>) -> FieldValueKind<'a> {
371 match &ty {
372 Type::Base(base) => match base {
373 Base::Void => FieldValueKind::Void,
374 Base::Bool => FieldValueKind::Bool,
375 Base::Char8 => FieldValueKind::Char8,
376 Base::Char16 => FieldValueKind::Char16,
377 Base::Char32 => FieldValueKind::Char32,
378
379 Base::I8 => FieldValueKind::I8,
380 Base::I16 => FieldValueKind::I16,
381 Base::I32 => FieldValueKind::I32,
382 Base::I64 => FieldValueKind::I64,
383 Base::I128 => FieldValueKind::I128,
384
385 Base::U8 => FieldValueKind::U8,
386 Base::U16 => FieldValueKind::U16,
387 Base::U32 => FieldValueKind::U32,
388 Base::U64 => FieldValueKind::U64,
389 Base::U128 => FieldValueKind::U128,
390 _ => {
391 let size = base.size() as usize;
392 match size {
393 1 => FieldValueKind::U8,
394 2 => FieldValueKind::U16,
395 4 => FieldValueKind::U32,
396 8 => FieldValueKind::U64,
397 16 => FieldValueKind::U128,
398 _ => FieldValueKind::Void,
399 }
400 }
401 },
402 Type::Struct(sref) => FieldValueKind::Struct {
403 type_name: sref.name(),
404 size: profile.struct_size(sref.name()).unwrap_or(0),
405 },
406 Type::Pointer(ptr) => FieldValueKind::Pointer {
407 subtype: Box::new(make_value_kind(profile, ptr.subtype())),
408 size: profile.type_size(ty).unwrap_or(0),
409 },
410 Type::Array(arr) => FieldValueKind::Array {
411 subtype: Box::new(make_value_kind(profile, arr.subtype())),
412 dims: arr.dims().collect(),
413 size: profile.type_size(ty).unwrap_or(0),
414 },
415 Type::Bitfield(bf) => FieldValueKind::Bitfield {
416 bit_position: bf.bit_position(),
417 bit_length: bf.bit_length(),
418 size: profile.type_size(bf.subtype()).unwrap_or(0),
419 },
420 Type::Enum(eref) => FieldValueKind::Enum {
421 type_name: eref.name(),
422 size: profile.type_size(ty).unwrap_or(0),
423 },
424 Type::Function => FieldValueKind::Function,
425 }
426}
427
428fn read_uint(data: &[u8], offset: usize, size: usize) -> u128 {
430 if offset + size > data.len() {
431 return 0;
432 }
433
434 let slice = &data[offset..offset + size];
435 match size {
436 1 => slice[0] as u128,
437 2 => u16::from_le_bytes(slice.try_into().unwrap()) as u128,
438 4 => u32::from_le_bytes(slice.try_into().unwrap()) as u128,
439 8 => u64::from_le_bytes(slice.try_into().unwrap()) as u128,
440 16 => u128::from_le_bytes(slice.try_into().unwrap()),
441 _ => 0,
442 }
443}