1use std::array;
23
24use smallvec::SmallVec;
25
26use crate::base_type::BaseType;
27use crate::error::FitError;
28use crate::stream::{ByteStream, Endian};
29
30pub const FIELDS_INLINE: usize = 48;
34pub const DEV_FIELDS_INLINE: usize = 8;
36
37pub const LOCAL_DEFINITION_SLOTS: usize = 16;
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub struct FieldDefinition {
43 pub field_def_num: u8,
45 pub size: u8,
49 pub base_type: BaseType,
51 pub base_type_byte: u8,
54}
55
56impl FieldDefinition {
57 pub fn element_count(&self) -> usize {
61 let stride = self.base_type.element_size();
62 if stride == 0 || (self.size as usize) % stride != 0 {
63 0
64 } else {
65 (self.size as usize) / stride
66 }
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
78pub struct DeveloperFieldDefinition {
79 pub field_def_num: u8,
81 pub size: u8,
83 pub developer_data_index: u8,
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct MessageDefinition {
95 pub global_mesg_num: u16,
97 pub endian: Endian,
99 pub fields: SmallVec<[FieldDefinition; FIELDS_INLINE]>,
101 pub dev_fields: SmallVec<[DeveloperFieldDefinition; DEV_FIELDS_INLINE]>,
104 pub reserved: u8,
107}
108
109impl MessageDefinition {
110 pub fn parse(stream: &mut ByteStream<'_>, has_dev_data: bool) -> Result<Self, FitError> {
115 let reserved = stream.read_u8()?;
116 let architecture = stream.read_u8()?;
117 let endian = if architecture == 0 {
118 Endian::Little
119 } else {
120 Endian::Big
121 };
122
123 let global_mesg_num = stream.read_u16(endian)?;
124 let field_count = stream.read_u8()? as usize;
125
126 let mut fields: SmallVec<[FieldDefinition; FIELDS_INLINE]> =
127 SmallVec::with_capacity(field_count);
128 for _ in 0..field_count {
129 let field_def_num = stream.read_u8()?;
130 let size = stream.read_u8()?;
131 let base_type_byte = stream.read_u8()?;
132 let base_type = BaseType::from_byte(base_type_byte)?;
133 let stride = base_type.element_size();
138 if !base_type.is_string()
139 && !base_type.is_byte()
140 && (size == 0 || (size as usize) % stride != 0)
141 {
142 return Err(FitError::MalformedField {
143 field_def_num,
144 size,
145 element_size: stride,
146 });
147 }
148 fields.push(FieldDefinition {
149 field_def_num,
150 size,
151 base_type,
152 base_type_byte,
153 });
154 }
155
156 let mut dev_fields: SmallVec<[DeveloperFieldDefinition; DEV_FIELDS_INLINE]> =
157 SmallVec::new();
158 if has_dev_data {
159 let dev_count = stream.read_u8()? as usize;
160 dev_fields.reserve_exact(dev_count);
161 for _ in 0..dev_count {
162 let field_def_num = stream.read_u8()?;
163 let size = stream.read_u8()?;
164 let developer_data_index = stream.read_u8()?;
165 dev_fields.push(DeveloperFieldDefinition {
166 field_def_num,
167 size,
168 developer_data_index,
169 });
170 }
171 }
172
173 Ok(Self {
174 global_mesg_num,
175 endian,
176 fields,
177 dev_fields,
178 reserved,
179 })
180 }
181
182 pub fn data_size(&self) -> usize {
185 let core: usize = self.fields.iter().map(|f| f.size as usize).sum();
186 let dev: usize = self.dev_fields.iter().map(|f| f.size as usize).sum();
187 core + dev
188 }
189
190 pub fn field(&self, field_def_num: u8) -> Option<&FieldDefinition> {
192 self.fields
193 .iter()
194 .find(|f| f.field_def_num == field_def_num)
195 }
196}
197
198#[derive(Debug, Default)]
207pub struct LocalDefinitions {
208 slots: [Option<MessageDefinition>; LOCAL_DEFINITION_SLOTS],
209}
210
211impl LocalDefinitions {
212 pub fn new() -> Self {
214 Self {
215 slots: array::from_fn(|_| None),
216 }
217 }
218
219 pub fn get(&self, local_mesg_num: u8) -> Option<&MessageDefinition> {
221 self.slots
222 .get(local_mesg_num as usize)
223 .and_then(Option::as_ref)
224 }
225
226 pub fn require(&self, local_mesg_num: u8) -> Result<&MessageDefinition, FitError> {
228 self.get(local_mesg_num)
229 .ok_or(FitError::UndefinedLocalMesgNum(local_mesg_num))
230 }
231
232 pub fn set(&mut self, local_mesg_num: u8, def: MessageDefinition) {
234 if let Some(slot) = self.slots.get_mut(local_mesg_num as usize) {
235 *slot = Some(def);
236 }
237 }
238
239 pub fn clear(&mut self) {
241 for slot in self.slots.iter_mut() {
242 *slot = None;
243 }
244 }
245
246 pub fn occupied(&self) -> usize {
248 self.slots.iter().filter(|s| s.is_some()).count()
249 }
250}
251
252#[cfg(test)]
253mod tests {
254 use super::*;
255
256 fn sample_le_definition_bytes() -> Vec<u8> {
258 vec![
263 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x01, 0x02, 0x84, 0x02, 0x02, 0x84, 0x03, 0x04, 0x86, 0x04, 0x04, 0x8C, ]
270 }
271
272 #[test]
273 fn parses_canonical_le_definition() {
274 let bytes = sample_le_definition_bytes();
275 let mut stream = ByteStream::new(&bytes);
276 let def = MessageDefinition::parse(&mut stream, false).unwrap();
277
278 assert_eq!(def.global_mesg_num, 0);
279 assert_eq!(def.endian, Endian::Little);
280 assert_eq!(def.reserved, 0);
281 assert_eq!(def.fields.len(), 5);
282 assert!(def.dev_fields.is_empty());
283
284 assert_eq!(def.fields[0].field_def_num, 0);
286 assert_eq!(def.fields[0].size, 1);
287 assert_eq!(def.fields[0].base_type, BaseType::Enum);
288
289 assert_eq!(def.fields[1].base_type, BaseType::UInt16);
291 assert!(BaseType::endian_flag_set(def.fields[1].base_type_byte));
292
293 assert_eq!(def.fields[4].base_type, BaseType::UInt32z);
295 assert_eq!(def.fields[4].element_count(), 1);
296
297 assert_eq!(def.data_size(), 1 + 2 + 2 + 4 + 4);
298 }
299
300 #[test]
301 fn parses_big_endian_definition() {
302 let bytes = vec![
304 0x00, 0x01, 0x00, 0x14, 0x01, 253, 0x04, 0x86, ];
307 let mut stream = ByteStream::new(&bytes);
308 let def = MessageDefinition::parse(&mut stream, false).unwrap();
309 assert_eq!(def.endian, Endian::Big);
310 assert_eq!(def.global_mesg_num, 20);
311 assert_eq!(def.fields.len(), 1);
312 assert_eq!(def.fields[0].field_def_num, 253);
313 assert_eq!(def.fields[0].base_type, BaseType::UInt32);
314 }
315
316 #[test]
317 fn parses_definition_with_dev_data() {
318 let mut bytes = sample_le_definition_bytes();
319 bytes.extend_from_slice(&[
320 0x02, 0x00, 0x04, 0x00, 0x05, 0x02, 0x01, ]);
324 let mut stream = ByteStream::new(&bytes);
325 let def = MessageDefinition::parse(&mut stream, true).unwrap();
326
327 assert_eq!(def.dev_fields.len(), 2);
328 assert_eq!(def.dev_fields[0].field_def_num, 0);
329 assert_eq!(def.dev_fields[0].developer_data_index, 0);
330 assert_eq!(def.dev_fields[1].field_def_num, 5);
331 assert_eq!(def.dev_fields[1].developer_data_index, 1);
332
333 assert_eq!(def.data_size(), (1 + 2 + 2 + 4 + 4) + (4 + 2));
335 }
336
337 #[test]
338 fn rejects_unknown_base_type() {
339 let bytes = vec![
340 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x1A, ];
343 let mut stream = ByteStream::new(&bytes);
344 let err = MessageDefinition::parse(&mut stream, false).unwrap_err();
345 assert!(matches!(err, FitError::UnknownBaseType(_, _)));
346 }
347
348 #[test]
349 fn local_definitions_set_get_clear() {
350 let mut tbl = LocalDefinitions::new();
351 assert_eq!(tbl.occupied(), 0);
352 assert!(tbl.get(0).is_none());
353
354 let bytes = sample_le_definition_bytes();
355 let mut stream = ByteStream::new(&bytes);
356 let def = MessageDefinition::parse(&mut stream, false).unwrap();
357 tbl.set(3, def.clone());
358 assert_eq!(tbl.occupied(), 1);
359 assert_eq!(tbl.get(3).unwrap().global_mesg_num, 0);
360
361 tbl.set(3, def);
363 assert_eq!(tbl.occupied(), 1);
364
365 tbl.set(
367 99,
368 MessageDefinition {
369 global_mesg_num: 0,
370 endian: Endian::Little,
371 fields: SmallVec::new(),
372 dev_fields: SmallVec::new(),
373 reserved: 0,
374 },
375 );
376 assert_eq!(tbl.occupied(), 1);
377
378 tbl.clear();
379 assert_eq!(tbl.occupied(), 0);
380 }
381
382 #[test]
383 fn require_returns_useful_error() {
384 let tbl = LocalDefinitions::new();
385 let err = tbl.require(7).unwrap_err();
386 assert_eq!(err, FitError::UndefinedLocalMesgNum(7));
387 }
388
389 #[test]
390 fn element_count_handles_arrays_and_misalignment() {
391 let single = FieldDefinition {
392 field_def_num: 0,
393 size: 4,
394 base_type: BaseType::UInt32,
395 base_type_byte: 0x06,
396 };
397 assert_eq!(single.element_count(), 1);
398
399 let array = FieldDefinition {
400 field_def_num: 0,
401 size: 8,
402 base_type: BaseType::UInt16,
403 base_type_byte: 0x04,
404 };
405 assert_eq!(array.element_count(), 4);
406
407 let bad = FieldDefinition {
409 field_def_num: 0,
410 size: 3,
411 base_type: BaseType::UInt32,
412 base_type_byte: 0x06,
413 };
414 assert_eq!(bad.element_count(), 0);
415 }
416}