use crate::profile::Component;
use crate::raw_value::RawValue;
use crate::transforms::bit_stream::BitStream;
#[derive(Debug, Clone, PartialEq)]
pub struct UnpackedComponent {
pub target_name: &'static str,
pub raw: u64,
pub bits: u8,
pub scale: Option<f64>,
pub offset: Option<f64>,
pub units: Option<&'static str>,
pub accumulate: bool,
}
pub fn unpack_bytes(components: &'static [Component], wire_bytes: &[u8]) -> Vec<UnpackedComponent> {
if components.is_empty() {
return Vec::new();
}
let mut bs = BitStream::new(wire_bytes);
components
.iter()
.map(|c| UnpackedComponent {
target_name: c.name,
raw: bs.read_bits(c.bits as u32),
bits: c.bits,
scale: c.scale,
offset: c.offset,
units: c.units,
accumulate: c.accumulate,
})
.collect()
}
pub fn unpack_scalar(components: &'static [Component], scalar: u64) -> Vec<UnpackedComponent> {
let total_bits: u32 = components.iter().map(|c| c.bits as u32).sum();
let nbytes = total_bits.div_ceil(8).max(1) as usize;
let bytes: Vec<u8> = (0..nbytes)
.map(|i| ((scalar >> (i * 8)) & 0xFF) as u8)
.collect();
unpack_bytes(components, &bytes)
}
#[inline]
pub fn scalar_as_u64(raw: &RawValue) -> Option<u64> {
raw.scalar_u64()
}
#[cfg(test)]
mod tests {
use super::*;
static GEAR_CHANGE_COMPONENTS: &[Component] = &[
Component {
name: "rear_gear",
bits: 8,
scale: None,
offset: None,
units: None,
accumulate: false,
},
Component {
name: "rear_gear_num",
bits: 8,
scale: None,
offset: None,
units: None,
accumulate: false,
},
Component {
name: "front_gear",
bits: 8,
scale: None,
offset: None,
units: None,
accumulate: false,
},
Component {
name: "front_gear_num",
bits: 8,
scale: None,
offset: None,
units: None,
accumulate: false,
},
];
#[test]
fn unpacks_gear_change_data_from_bytes() {
let bytes = [0x04, 0x03, 0x02, 0x01]; let unpacked = unpack_bytes(GEAR_CHANGE_COMPONENTS, &bytes);
assert_eq!(unpacked.len(), 4);
assert_eq!(unpacked[0].target_name, "rear_gear");
assert_eq!(unpacked[0].raw, 4);
assert_eq!(unpacked[1].raw, 3);
assert_eq!(unpacked[2].raw, 2);
assert_eq!(unpacked[3].raw, 1);
}
#[test]
fn unpacks_gear_change_from_scalar() {
let scalar = 0x01_02_03_04u64;
let unpacked = unpack_scalar(GEAR_CHANGE_COMPONENTS, scalar);
assert_eq!(unpacked[0].raw, 4);
assert_eq!(unpacked[3].raw, 1);
}
#[test]
fn empty_components_yields_empty() {
let unpacked = unpack_bytes(&[], &[1, 2, 3, 4]);
assert!(unpacked.is_empty());
}
#[test]
fn scalar_as_u64_handles_common_cases() {
assert_eq!(scalar_as_u64(&RawValue::U8Scalar(42)), Some(42));
assert_eq!(scalar_as_u64(&RawValue::U16Scalar(1234)), Some(1234));
assert_eq!(
scalar_as_u64(&RawValue::U32Scalar(995749880)),
Some(995749880)
);
assert_eq!(scalar_as_u64(&RawValue::Invalid), None);
assert_eq!(scalar_as_u64(&RawValue::String("foo".into())), None);
assert_eq!(
scalar_as_u64(&RawValue::U8Array(vec![1u8, 2].into_boxed_slice())),
None
);
}
}