1use std::fmt::Display;
4
5use device_driver_common::{
6 interner::Istr,
7 specifiers::{BaseType, ByteOrder, Integer, RepeatSource},
8};
9
10use crate::model::{Enum, Field, FieldSet, Manifest, Object};
11
12#[derive(Debug)]
13pub struct DecodedFieldset {
14 pub fields: Vec<DecodedField>,
15}
16
17#[derive(Debug)]
18pub struct DecodedField {
19 pub name: Istr,
20 pub index_name: Option<String>,
21 pub base_value: FieldBaseValue,
22 pub converted_value: Option<String>,
23}
24
25#[derive(Debug)]
26pub enum FieldBaseValue {
27 Integer(i128),
28 Bool(bool),
29}
30
31impl Display for FieldBaseValue {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 match self {
34 FieldBaseValue::Integer(val) => write!(f, "{val}"),
35 FieldBaseValue::Bool(val) => write!(f, "{val}"),
36 }
37 }
38}
39
40impl FieldBaseValue {
41 pub fn as_integer(&self) -> Option<i128> {
42 if let Self::Integer(v) = self {
43 Some(*v)
44 } else {
45 None
46 }
47 }
48}
49
50pub fn decode_fieldset(
51 manifest: &Manifest,
52 fieldset_model: &FieldSet,
53 bytes: &[u8],
54) -> Result<DecodedFieldset, DecodeError> {
55 if bytes.len() != fieldset_model.size_bytes.value as usize {
56 return Err(DecodeError::SizeBytesMismatch);
57 }
58
59 let mut fields = Vec::new();
60
61 for field_id in fieldset_model.fields.iter() {
62 let field = manifest.fields.get(*field_id).unwrap();
63
64 let offsets = field
65 .repeat
66 .as_ref()
67 .map(|repeat| match &repeat.source.value {
68 RepeatSource::Count(non_zero) => (0..non_zero.get())
69 .map(|index| (index as i128 * repeat.stride.value, Some(index.to_string())))
70 .collect(),
71 RepeatSource::Enum(identifier_ref) => {
72 let enum_model = manifest
73 .search_object(identifier_ref)
74 .unwrap()
75 .as_enum()
76 .unwrap();
77 enum_model
78 .iter_variants_with_discriminant(&manifest.enum_variants)
79 .map(|(index, variant_id)| {
80 (
81 index * repeat.stride.value,
82 Some(
83 manifest
84 .enum_variants
85 .get(variant_id)
86 .unwrap()
87 .name
88 .original()
89 .to_string(),
90 ),
91 )
92 })
93 .collect()
94 }
95 })
96 .unwrap_or_else(|| vec![(0, None)]);
97
98 for (offset, index_name) in offsets {
99 let start =
100 (field.field_address.start as usize).strict_add_signed(offset.try_into().unwrap());
101 let end =
102 (field.field_address.end as usize).strict_add_signed(offset.try_into().unwrap());
103
104 let value = match field.base_type.value {
105 BaseType::Bool => FieldBaseValue::Bool(
106 load_integer(
107 bytes,
108 fieldset_model.byte_order.unwrap(),
109 Integer::U8,
110 start,
111 end,
112 ) != 0,
113 ),
114 BaseType::FixedSize(integer) => FieldBaseValue::Integer(load_integer(
115 bytes,
116 fieldset_model.byte_order.unwrap(),
117 integer,
118 start,
119 end,
120 )),
121 BaseType::Unspecified | BaseType::Uint | BaseType::Int => unreachable!(),
122 };
123
124 fields.push(decode_field(manifest, field, index_name, value));
125 }
126 }
127
128 Ok(DecodedFieldset { fields })
129}
130
131pub fn decode_field(
132 manifest: &Manifest,
133 field_model: &Field,
134 index_name: Option<String>,
135 value: FieldBaseValue,
136) -> DecodedField {
137 let converted_value = if let Some(conversion) = &field_model.field_conversion {
138 let target_type = manifest.search_type(&conversion.type_ref.value).unwrap();
139 match target_type {
140 Object::Enum(e) => match decode_enum(manifest, e, value.as_integer().unwrap()) {
141 Ok(active_variant) => Some(format!("{}::{active_variant}", e.name.original())),
142 Err(e) => Some(format!("<{e}>")),
143 },
144 Object::Extern(_) => Some("<extern>".into()),
145 _ => unreachable!(),
146 }
147 } else {
148 None
149 };
150
151 DecodedField {
152 name: field_model.name.original(),
153 index_name,
154 base_value: value,
155 converted_value,
156 }
157}
158
159pub fn decode_enum(
160 manifest: &Manifest,
161 enum_model: &Enum,
162 value: i128,
163) -> Result<Istr, DecodeError> {
164 let mut fallback_variant = None;
165
166 for (variant_value, variant_id) in
167 enum_model.iter_variants_with_discriminant(&manifest.enum_variants)
168 {
169 let variant = manifest.enum_variants.get(variant_id).unwrap();
170
171 if variant_value == value {
172 return Ok(variant.name.original());
173 }
174
175 if variant.value.is_catch_all() {
176 fallback_variant = Some(variant.name.original());
178 }
179 if variant.value.is_default() && fallback_variant.is_none() {
180 fallback_variant = Some(variant.name.original());
182 }
183 }
184
185 if let Some(fallback) = fallback_variant {
186 return Ok(fallback);
187 }
188
189 Err(DecodeError::InvalidValue)
190}
191
192pub enum DecodeError {
193 InvalidValue,
194 SizeBytesMismatch,
195}
196
197impl Display for DecodeError {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 DecodeError::InvalidValue => write!(f, "invalid value"),
201 DecodeError::SizeBytesMismatch => write!(f, "size-bytes mismatch"),
202 }
203 }
204}
205
206pub fn load_integer(
207 bytes: &[u8],
208 byte_order: ByteOrder,
209 base_type: Integer,
210 start: usize,
211 end: usize,
212) -> i128 {
213 let mut val = 0;
214
215 for index in start..=end {
216 let byte_index = match byte_order {
217 ByteOrder::LE => index / 8,
218 ByteOrder::BE => bytes.len() - (index / 8) - 1,
219 };
220 let bit_index = index % 8;
221
222 let byte = bytes[byte_index];
223 let bit = byte & (1 << bit_index);
224
225 if bit > 0 {
226 let val_bit_index = index - start;
227 val |= 1 << val_bit_index;
228 }
229 }
230
231 if base_type.is_signed() {
232 let sign_bit_index = end - start;
234 if val & (1 << sign_bit_index) > 0 {
235 val |= !0i128 << sign_bit_index;
236 }
237 }
238
239 val
240}
241
242#[cfg(test)]
243mod tests {
244 use super::*;
245
246 #[test]
247 fn load_unsigned_integer() {
248 assert_eq!(
249 load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 0, 3),
250 0b1101
251 );
252 assert_eq!(
253 load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 1, 3),
254 0b110
255 );
256 assert_eq!(
257 load_integer(&0b1101u16.to_le_bytes(), ByteOrder::LE, Integer::U8, 0, 2),
258 0b101
259 );
260
261 assert_eq!(
262 load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 0, 3),
263 0b1101
264 );
265 assert_eq!(
266 load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 1, 3),
267 0b110
268 );
269 assert_eq!(
270 load_integer(&0b1101u16.to_be_bytes(), ByteOrder::BE, Integer::U8, 0, 2),
271 0b101
272 );
273 }
274
275 #[test]
276 fn load_signed_integer() {
277 assert_eq!(
278 load_integer(&(-5i16).to_le_bytes(), ByteOrder::LE, Integer::I8, 0, 3),
279 -5
280 );
281 assert_eq!(
282 load_integer(&(-5i16).to_be_bytes(), ByteOrder::BE, Integer::I8, 0, 3),
283 -5
284 );
285 }
286}