fit/transforms/
components.rs1use crate::profile::Component;
11use crate::raw_value::RawValue;
12use crate::transforms::bit_stream::BitStream;
13
14#[derive(Debug, Clone, PartialEq)]
16pub struct UnpackedComponent {
17 pub target_name: &'static str,
20 pub raw: u64,
23 pub bits: u8,
24 pub scale: Option<f64>,
25 pub offset: Option<f64>,
26 pub units: Option<&'static str>,
27 pub accumulate: bool,
28}
29
30pub fn unpack_bytes(components: &'static [Component], wire_bytes: &[u8]) -> Vec<UnpackedComponent> {
39 if components.is_empty() {
40 return Vec::new();
41 }
42 let mut bs = BitStream::new(wire_bytes);
43 components
44 .iter()
45 .map(|c| UnpackedComponent {
46 target_name: c.name,
47 raw: bs.read_bits(c.bits as u32),
48 bits: c.bits,
49 scale: c.scale,
50 offset: c.offset,
51 units: c.units,
52 accumulate: c.accumulate,
53 })
54 .collect()
55}
56
57pub fn unpack_scalar(components: &'static [Component], scalar: u64) -> Vec<UnpackedComponent> {
61 let total_bits: u32 = components.iter().map(|c| c.bits as u32).sum();
62 let nbytes = total_bits.div_ceil(8).max(1) as usize;
63 let bytes: Vec<u8> = (0..nbytes)
64 .map(|i| ((scalar >> (i * 8)) & 0xFF) as u8)
65 .collect();
66 unpack_bytes(components, &bytes)
67}
68
69#[inline]
72pub fn scalar_as_u64(raw: &RawValue) -> Option<u64> {
73 raw.scalar_u64()
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79
80 static GEAR_CHANGE_COMPONENTS: &[Component] = &[
82 Component {
83 name: "rear_gear",
84 bits: 8,
85 scale: None,
86 offset: None,
87 units: None,
88 accumulate: false,
89 },
90 Component {
91 name: "rear_gear_num",
92 bits: 8,
93 scale: None,
94 offset: None,
95 units: None,
96 accumulate: false,
97 },
98 Component {
99 name: "front_gear",
100 bits: 8,
101 scale: None,
102 offset: None,
103 units: None,
104 accumulate: false,
105 },
106 Component {
107 name: "front_gear_num",
108 bits: 8,
109 scale: None,
110 offset: None,
111 units: None,
112 accumulate: false,
113 },
114 ];
115
116 #[test]
117 fn unpacks_gear_change_data_from_bytes() {
118 let bytes = [0x04, 0x03, 0x02, 0x01]; let unpacked = unpack_bytes(GEAR_CHANGE_COMPONENTS, &bytes);
120 assert_eq!(unpacked.len(), 4);
121 assert_eq!(unpacked[0].target_name, "rear_gear");
122 assert_eq!(unpacked[0].raw, 4);
123 assert_eq!(unpacked[1].raw, 3);
124 assert_eq!(unpacked[2].raw, 2);
125 assert_eq!(unpacked[3].raw, 1);
126 }
127
128 #[test]
129 fn unpacks_gear_change_from_scalar() {
130 let scalar = 0x01_02_03_04u64;
132 let unpacked = unpack_scalar(GEAR_CHANGE_COMPONENTS, scalar);
133 assert_eq!(unpacked[0].raw, 4);
134 assert_eq!(unpacked[3].raw, 1);
135 }
136
137 #[test]
138 fn empty_components_yields_empty() {
139 let unpacked = unpack_bytes(&[], &[1, 2, 3, 4]);
140 assert!(unpacked.is_empty());
141 }
142
143 #[test]
144 fn scalar_as_u64_handles_common_cases() {
145 assert_eq!(scalar_as_u64(&RawValue::U8Scalar(42)), Some(42));
146 assert_eq!(scalar_as_u64(&RawValue::U16Scalar(1234)), Some(1234));
147 assert_eq!(
148 scalar_as_u64(&RawValue::U32Scalar(995749880)),
149 Some(995749880)
150 );
151 assert_eq!(scalar_as_u64(&RawValue::Invalid), None);
152 assert_eq!(scalar_as_u64(&RawValue::String("foo".into())), None);
153 assert_eq!(
155 scalar_as_u64(&RawValue::U8Array(vec![1u8, 2].into_boxed_slice())),
156 None
157 );
158 }
159}