Skip to content

Commit a355375

Browse files
committed
refactor: clean up common parse function
1 parent 5bc4feb commit a355375

File tree

1 file changed

+56
-75
lines changed

1 file changed

+56
-75
lines changed

src/structures/common.rs

Lines changed: 56 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -54,89 +54,70 @@ pub struct StructureError;
5454
/// ```
5555
pub fn parse(
5656
data: &[u8],
57-
structure: &Vec<(&str, &str)>,
57+
structure: &[(&str, &str)],
5858
endianness: &str,
5959
) -> Result<HashMap<String, usize>, StructureError> {
60+
const U8_SIZE: usize = std::mem::size_of::<u8>();
61+
const U16_SIZE: usize = std::mem::size_of::<u16>();
62+
const U32_SIZE: usize = std::mem::size_of::<u32>();
63+
const U64_SIZE: usize = std::mem::size_of::<u64>();
6064
const U24_SIZE: usize = 3;
6165

62-
let mut value: usize;
63-
let mut offset: usize = 0;
64-
let mut parsed_structure = HashMap::new();
65-
66-
// Get the size of the defined structure
67-
let structure_size = size(structure);
68-
69-
if let Some(raw_data) = data.get(0..structure_size) {
70-
for (name, ctype) in structure {
71-
let data_type: String = ctype.to_string();
72-
73-
match type_to_size(ctype) {
74-
None => return Err(StructureError),
75-
Some(csize) => {
76-
if csize == std::mem::size_of::<u8>() {
77-
// u8, endianness doesn't matter
78-
value =
79-
u8::from_be_bytes(raw_data[offset..offset + csize].try_into().unwrap())
80-
as usize;
81-
} else if csize == std::mem::size_of::<u16>() {
82-
if endianness == "big" {
83-
value = u16::from_be_bytes(
84-
raw_data[offset..offset + csize].try_into().unwrap(),
85-
) as usize;
86-
} else {
87-
value = u16::from_le_bytes(
88-
raw_data[offset..offset + csize].try_into().unwrap(),
89-
) as usize;
90-
}
91-
92-
// Yes Virginia, u24's are real
93-
} else if csize == U24_SIZE {
94-
if endianness == "big" {
95-
value = ((raw_data[offset] as usize) << 16)
96-
+ ((raw_data[offset + 1] as usize) << 8)
97-
+ (raw_data[offset + 2] as usize);
98-
} else {
99-
value = ((raw_data[offset + 2] as usize) << 16)
100-
+ ((raw_data[offset + 1] as usize) << 8)
101-
+ (raw_data[offset] as usize);
102-
}
103-
} else if csize == std::mem::size_of::<u32>() {
104-
if endianness == "big" {
105-
value = u32::from_be_bytes(
106-
raw_data[offset..offset + csize].try_into().unwrap(),
107-
) as usize;
108-
} else {
109-
value = u32::from_le_bytes(
110-
raw_data[offset..offset + csize].try_into().unwrap(),
111-
) as usize;
112-
}
113-
} else if csize == std::mem::size_of::<u64>() {
114-
if endianness == "big" {
115-
value = u64::from_be_bytes(
116-
raw_data[offset..offset + csize].try_into().unwrap(),
117-
) as usize;
118-
} else {
119-
value = u64::from_le_bytes(
120-
raw_data[offset..offset + csize].try_into().unwrap(),
121-
) as usize;
122-
}
123-
} else {
124-
error!(
125-
"Cannot parse structure element with unknown data type '{data_type}'"
126-
);
127-
return Err(StructureError);
128-
}
129-
130-
offset += csize;
131-
parsed_structure.insert(name.to_string(), value);
66+
let mut parsed_structure = HashMap::with_capacity(structure.len());
67+
68+
let mut remaining_data = data;
69+
for &(name, ctype) in structure {
70+
let csize = type_to_size(ctype).ok_or(StructureError)?;
71+
let raw_bytes = remaining_data.split_off(..csize).ok_or(StructureError)?;
72+
let value = match csize {
73+
// u8, endianness doesn't matter
74+
U8_SIZE => usize::from(raw_bytes[0]),
75+
U16_SIZE => {
76+
let f = if endianness == "big" {
77+
u16::from_be_bytes
78+
} else {
79+
u16::from_le_bytes
80+
};
81+
usize::from(f(raw_bytes.try_into().unwrap()))
82+
}
83+
U32_SIZE => {
84+
let f = if endianness == "big" {
85+
u32::from_be_bytes
86+
} else {
87+
u32::from_le_bytes
88+
};
89+
f(raw_bytes.try_into().unwrap()) as usize
90+
}
91+
U64_SIZE => {
92+
let f = if endianness == "big" {
93+
u64::from_be_bytes
94+
} else {
95+
u64::from_le_bytes
96+
};
97+
f(raw_bytes.try_into().unwrap()) as usize // TODO: this will truncate on 32 bit
98+
}
99+
// Yes Virginia, u24's are real
100+
U24_SIZE => {
101+
if endianness == "big" {
102+
usize::from(raw_bytes[0]) << 16
103+
| usize::from(raw_bytes[1]) << 8
104+
| usize::from(raw_bytes[2])
105+
} else {
106+
usize::from(raw_bytes[2]) << 16
107+
| usize::from(raw_bytes[1]) << 8
108+
| usize::from(raw_bytes[0])
132109
}
133110
}
134-
}
111+
_ => {
112+
error!("Cannot parse structure element with unknown data type '{ctype}'");
113+
return Err(StructureError);
114+
}
115+
};
135116

136-
return Ok(parsed_structure);
117+
parsed_structure.insert(name.to_string(), value);
137118
}
138119

139-
Err(StructureError)
120+
Ok(parsed_structure)
140121
}
141122

142123
/// Returns the size of a given structure definition.
@@ -157,7 +138,7 @@ pub fn parse(
157138
///
158139
/// assert_eq!(struct_size, 17);
159140
/// ```
160-
pub fn size(structure: &Vec<(&str, &str)>) -> usize {
141+
pub fn size(structure: &[(&str, &str)]) -> usize {
161142
let mut struct_size: usize = 0;
162143

163144
for (_name, ctype) in structure {

0 commit comments

Comments
 (0)