Skip to main content

rustyfit/
proto.rs

1#![warn(missing_docs)]
2
3use std::{error, fmt};
4
5use crate::profile::{
6    ProfileType,
7    typedef::{FitBaseType, MesgNum},
8};
9
10/// Mask for determining if the message type is a message definition.
11pub(crate) const MESG_DEFINITION_MASK: u8 = 0b01000000;
12
13/// Mask for determining if the message type is a normal message data .
14pub(crate) const MESG_NORMAL_HEADER_MASK: u8 = 0b00000000;
15
16/// Mask for determining if the message type is a compressed timestamp message data.
17pub(crate) const MESG_COMPRESSED_HEADER_MASK: u8 = 0b10000000;
18
19/// Mask for determining if the message's header is a message definition or is it
20/// actually a message data with compressed timestamp and multiple local message type.
21///
22/// For compressed timestamp, message data's header bit 5-6 is the local message type.
23/// Bit 6 overlap with MESG_DEFINITION_MASK, it's a message definition only if Bit 7 is zero.
24pub(crate) const MESG_HEADER_MASK: u8 = MESG_COMPRESSED_HEADER_MASK | MESG_DEFINITION_MASK;
25
26/// Mask for mapping normal message data to the message definition.
27pub(crate) const LOCAL_MESG_NUM_MASK: u8 = 0b00001111;
28
29/// Mask for mapping compressed timestamp message data to the message definition. Used with CompressedBitShift.
30pub(crate) const COMPRESSED_LOCAL_MESG_NUM_MASK: u8 = 0b01100000;
31
32/// Mask for measuring time offset value from header. Compressed timestamp is using 5 least significant bits (lsb) of header
33pub(crate) const COMPRESSED_TIME_MASK: u8 = 0b00011111;
34
35/// Mask for determining if a message contains developer fields.
36pub(crate) const DEV_DATA_MASK: u8 = 0b00100000;
37
38/// Used for right-shifting the 5 least significant bits (lsb) of compressed time.
39pub(crate) const COMPRESSED_BIT_SHIFT: u8 = 5;
40
41/// Field's number for timestamp across all defined messages in the profile.
42/// Exception: Course Point and Set message.
43pub(crate) const FIELD_NUM_TIMESTAMP: u8 = 253;
44
45/// FileHeader's data_type.
46pub(crate) static DATA_TYPE: &str = ".FIT";
47
48/// Defined errors returned from proto module.
49#[derive(Debug, Clone, Copy)]
50pub enum Error {
51    /// Protocol Validator's error when Protocol Version 1.0 constains developer data.
52    ProtocolViolationDeveloperData,
53    /// Protocol Validator's error when Protocol Version 1.0 has base_type number more than byte number.
54    ProtocolViolationUnsupportedBaseType(FitBaseType),
55    /// Marshal error when Value is invalid.
56    InvalidValue,
57}
58
59impl fmt::Display for Error {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match *self {
62            Error::ProtocolViolationDeveloperData => {
63                write!(f, "protocol version 1.0 do not support developer data")
64            }
65            Error::ProtocolViolationUnsupportedBaseType(base_type) => {
66                write!(f, "protocol version 1.0 do not support type {}", base_type)
67            }
68            Error::InvalidValue => write!(f, "invalid proto::Value"),
69        }
70    }
71}
72
73impl error::Error for Error {}
74
75/// FIT is FIT protocol data representative.
76#[derive(Default, Debug)]
77pub struct FIT {
78    /// File Header contains either 12 or 14 bytes
79    pub file_header: FileHeader,
80    /// Messages
81    pub messages: Vec<Message>,
82    /// Cyclic Redundancy Check 16-bit value to ensure the integrity of the messages.
83    pub crc: u16,
84}
85
86/// FileHeader is a FIT's FileHeader with either 12 bytes size without CRC or a 14 bytes size with CRC,
87/// while 14 bytes size is the preferred size.
88#[derive(Debug, Default, Clone, Copy)]
89pub struct FileHeader {
90    /// File header size either 12 (legacy) or 14.
91    pub size: u8,
92    /// The FIT Protocol version which is being used to encode the FIT file.
93    pub protocol_version: ProtocolVersion,
94    /// The FIT Profile Version (associated with data defined in Global FIT Profile).
95    pub profile_version: u16,
96    /// The size of the messages in bytes (this field will be automatically updated by the encoder)
97    pub data_size: u32,
98    /// ".FIT" (an immutable string constant)
99    pub data_type: &'static str,
100    /// Cyclic Redundancy Check 16-bit value to ensure the integrity of the file header.
101    /// (this field will be automatically updated by the encoder)
102    pub crc: u16,
103}
104
105impl FileHeader {
106    pub(crate) fn marshal_append(&self, vec: &mut Vec<u8>) {
107        vec.push(self.size);
108        vec.push(self.protocol_version.0);
109        vec.extend_from_slice(&self.profile_version.to_le_bytes());
110        vec.extend_from_slice(&self.data_size.to_le_bytes());
111        vec.extend_from_slice(DATA_TYPE.as_bytes());
112        if self.size >= 14 {
113            vec.extend_from_slice(&self.crc.to_le_bytes());
114        }
115    }
116}
117
118/// MessageDefinition is the definition of the upcoming data messages.
119#[derive(Debug, Default, Clone)]
120pub struct MessageDefinition {
121    /// The message definition header with mask 0b01000000.
122    pub header: u8,
123    /// Currently undetermined; the default value is 0.
124    pub reserved: u8,
125    /// The Byte Order to be used to decode the values of both this message definition and the upcoming message. (0: Little-Endian, 1: Big-Endian)
126    pub arch: u8,
127    /// Global Message Number defined by factory (retrieved from Profile.xslx). (endianness of this 2 Byte value is defined in the Architecture byte)
128    pub mesg_num: MesgNum,
129    /// List of the field definition
130    pub field_definitions: Vec<FieldDefinition>,
131    /// List of the developer field definition (only if Developer Data Flag is set in Header)
132    pub developer_field_definitions: Vec<DeveloperFieldDefinition>,
133}
134
135/// FieldDefinition is the definition of the upcoming field within the message's structure.
136#[derive(Debug, Default, Clone, Copy)]
137pub struct FieldDefinition {
138    /// The field definition number
139    pub num: u8,
140    /// The size of the upcoming value
141    pub size: u8,
142    /// The type of the upcoming value to be represented
143    pub base_type: FitBaseType,
144}
145
146/// FieldDefinition is the definition of the upcoming developer field within the message's structure.
147#[derive(Debug, Default, Clone, Copy)]
148pub struct DeveloperFieldDefinition {
149    /// Maps to `field_definition_number` of a `field_description` message.
150    pub num: u8,
151    /// Size (in bytes) of the specified FIT message’s field
152    pub size: u8,
153    /// Maps to `developer_data_index` of a `developer_data_id` and a `field_description` messages.
154    pub developer_data_index: u8,
155}
156
157/// Message is a FIT protocol message containing the data defined in the Message Definition
158#[derive(Default, Debug, Clone)]
159pub struct Message {
160    /// Message Header serves to distinguish whether the message is a Normal Data or a Compressed Timestamp Data.
161    /// Unlike MessageDefinition, Message's Header should not contain Developer Data Flag.
162    pub header: u8,
163    /// Global Message Number defined in Global FIT Profile, except number within range 0xFF00 - 0xFFFE are manufacturer specific number.
164    pub num: MesgNum,
165    /// List of Field
166    pub fields: Vec<Field>,
167    /// List of DeveloperField
168    pub developer_fields: Vec<DeveloperField>,
169}
170
171impl Message {
172    /// SubFieldSubstitution returns any sub-field that can substitute
173    /// the properties interpretation of the parent Field (Dynamic Field).
174    pub fn sub_field_substitution<'a>(
175        &self,
176        field_ref: &FieldReference<'a>,
177    ) -> Option<&'a SubField<'a>> {
178        for sub_field in field_ref.sub_fields {
179            for sub_field_map in sub_field.maps {
180                for field in &self.fields {
181                    if field.num != sub_field_map.ref_field_num {
182                        continue;
183                    }
184                    if field.value.cast_i64() == sub_field_map.ref_field_value {
185                        return Some(sub_field);
186                    }
187                }
188            }
189        }
190        None
191    }
192
193    pub(crate) fn marshal_append(&self, vec: &mut Vec<u8>, arch: u8) -> Result<(), Error> {
194        vec.push(self.header);
195        for field in &self.fields {
196            field.value.marshal_append(vec, arch)?;
197        }
198        for dev_field in &self.developer_fields {
199            dev_field.value.marshal_append(vec, arch)?;
200        }
201        Ok(())
202    }
203}
204
205/// Field represents the full representation of a field, as specified in the Global FIT Profile.
206#[derive(Default, Debug, Clone)]
207pub struct Field {
208    /// Defined in the Global FIT profile for the specified FIT message, otherwise
209    /// its a manufaturer specific number (defined by manufacturer). (255 == invalid)
210    pub num: u8,
211    /// BaseType is the base of the ProfileType. E.g. ProfileType::DateTime -> FitBaseType::Uint32.
212    pub profile_type: ProfileType,
213    /// Value
214    pub value: Value,
215    /// A flag to detect whether this field is generated through component expansion.
216    pub is_expanded: bool,
217}
218
219/// FieldReference acts as a representation of a field as defined in the Global FIT Profile.
220#[derive(Debug, Clone, Copy)]
221pub struct FieldReference<'a> {
222    /// Defined in the Global FIT profile for the specified FIT message, otherwise
223    /// its a manufaturer specific number (defined by manufacturer). (255 == invalid)
224    pub num: u8,
225    /// Defined in the Global FIT profile for the specified FIT message, otherwise
226    /// its a manufaturer specific name (defined by manufacturer).
227    pub name: &'a str,
228    /// Type is defined type that serves as an abstraction layer above base types (primitive-types),
229    /// e.g. DateTime is a time representation in uint32.
230    pub base_type: FitBaseType,
231    /// ProfileType represents more than just a type of Value. E.g. ProfileType::DateTime -> FitBaseType::Uint32.
232    /// When an u32 value having ProfileType::DateTime as type, the value represents time.
233    pub profile_type: ProfileType,
234    /// Flag whether the value of this field is an array
235    pub array: bool,
236    /// Flag to indicate if the value of the field is accumulable.
237    pub accumulate: bool,
238    /// A scale or offset specified in the FIT profile for binary fields (sint/uint etc.) only.
239    /// The binary quantity is divided by the scale factor and then the offset is subtracted. (default: 1)
240    pub scale: f64,
241    /// A scale or offset specified in the FIT profile for binary fields (sint/uint etc.) only.
242    /// The binary quantity is divided by the scale factor and then the offset is subtracted. (default: 0)
243    pub offset: f64,
244    /// Units of the value, such as m (meter), m/s (meter per second), s (second), etc.
245    pub units: &'a str,
246    /// List of component
247    pub components: &'a [Component],
248    /// List of sub-field
249    pub sub_fields: &'a [SubField<'a>],
250}
251
252/// DeveloperField is a way to add custom data fields to existing messages. Developer Data Fields can be added
253/// to any message at runtime by providing a self-describing FieldDefinition messages prior to that message.
254/// The combination of the DeveloperDataIndex and FieldDefinitionNumber create a unique id for each FieldDescription.
255/// Developer Data Fields are also used by the Connect IQ FIT Contributor library, allowing Connect IQ apps
256/// and data fields to include custom data in FIT Activity files during the recording of activities.
257///
258/// NOTE: If DeveloperField contains a valid NativeMesgNum and NativeFieldNum, the value should be treated as
259/// native value (scale, offset, etc shall apply). [Added since protocol version 2.0]
260#[derive(Debug, Clone)]
261pub struct DeveloperField {
262    /// Maps to `field_definition_number` of a `field_description` message.
263    pub num: u8,
264    /// Maps to `developer_data_index` of a `developer_data_id` and a `field_description` messages.
265    pub developer_data_index: u8,
266    /// Value
267    pub value: Value,
268}
269
270/// Component is a way of compressing one or more fields into a bit field expressed in a single containing field.
271/// The component can be expanded as a main Field in a Message or to update the value of the destination main Field.
272#[derive(Debug)]
273pub struct Component {
274    /// Refer to Field's Number.
275    pub field_num: u8,
276    /// A flag whether this component should be accumulated.
277    pub accumulate: bool,
278    /// The size of data of this component in bits  
279    pub bits: u8,
280    /// Similar to FieldReference's scale, but for this component.
281    pub scale: f64,
282    /// Similar to FieldReference's offset, but for this component.
283    pub offset: f64,
284}
285
286/// SubField is a dynamic interpretation of the main Field in a Message when the SubFieldMap mapping match. See SubFieldMap's docs.
287#[derive(Debug)]
288pub struct SubField<'a> {
289    /// Name
290    pub name: &'a str,
291    /// ProfileType
292    pub profile_type: ProfileType,
293    /// Scale
294    pub scale: f64,
295    /// Offset
296    pub offset: f64,
297    /// Units
298    pub units: &'a str,
299    /// List of SubFieldMap
300    pub maps: &'a [SubFieldMap],
301    /// List of Component
302    pub components: &'a [Component],
303}
304
305/// SubFieldMap is the mapping between SubField and the corresponding main Field in a Message.
306/// When any Field in a Message has Field.Num == RefFieldNum and Field.Value == RefFieldValue, then the SubField containing
307/// this mapping can be interpreted as the main Field's properties (name, scale, type etc.)
308#[derive(Debug)]
309pub struct SubFieldMap {
310    /// Mapping reference to targeted Field's Number.
311    pub ref_field_num: u8,
312    /// Mapping reference to targeted Field's Value.
313    pub ref_field_value: i64,
314}
315
316/// Value representation of Message's Field.
317#[allow(missing_docs)]
318#[derive(Debug, Clone, Default)]
319pub enum Value {
320    #[default]
321    Invalid,
322    Int8(i8),
323    Uint8(u8),
324    Int16(i16),
325    Uint16(u16),
326    Int32(i32),
327    Uint32(u32),
328    String(String),
329    Float32(f32),
330    Float64(f64),
331    Int64(i64),
332    Uint64(u64),
333    VecInt8(Vec<i8>),
334    VecUint8(Vec<u8>),
335    VecInt16(Vec<i16>),
336    VecUint16(Vec<u16>),
337    VecInt32(Vec<i32>),
338    VecUint32(Vec<u32>),
339    VecString(Vec<String>),
340    VecFloat32(Vec<f32>),
341    VecFloat64(Vec<f64>),
342    VecInt64(Vec<i64>),
343    VecUint64(Vec<u64>),
344}
345
346/// Value that can hold FIT's value.
347impl Value {
348    /// Unmarshal bytes into Value.
349    //
350    // This is hotpath. We intentionally avoid using chunks_exact() iterator, as
351    // it introduces a slight performance overhead compared to using a standard loop.
352    pub(crate) fn unmarshal(buf: &[u8], array: bool, base_type: FitBaseType, arch: u8) -> Value {
353        match base_type {
354            FitBaseType::SINT8 => match array {
355                true => Value::VecInt8({
356                    let mut vals: Vec<i8> = Vec::with_capacity(buf.len());
357                    for &v in buf {
358                        vals.push(v as i8);
359                    }
360                    vals
361                }),
362                false => Value::Int8(buf[0] as i8),
363            },
364            FitBaseType::ENUM | FitBaseType::BYTE | FitBaseType::UINT8 | FitBaseType::UINT8Z => {
365                match array {
366                    true => Value::VecUint8(buf.to_vec()),
367                    false => Value::Uint8(buf[0]),
368                }
369            }
370            FitBaseType::SINT16 => match array {
371                true => Value::VecInt16({
372                    let mut vals: Vec<i16> = Vec::with_capacity(buf.len() / 2);
373                    let mut buf = buf;
374                    while buf.len() >= 2 {
375                        vals.push(match arch {
376                            0 => i16::from_le_bytes(buf[..2].try_into().unwrap()),
377                            _ => i16::from_be_bytes(buf[..2].try_into().unwrap()),
378                        });
379                        buf = &buf[2..];
380                    }
381                    vals
382                }),
383                false => match arch {
384                    0 => Value::Int16(i16::from_le_bytes(buf[..2].try_into().unwrap())),
385                    _ => Value::Int16(i16::from_be_bytes(buf[..2].try_into().unwrap())),
386                },
387            },
388            FitBaseType::UINT16 | FitBaseType::UINT16Z => match array {
389                true => Value::VecUint16({
390                    let mut vals: Vec<u16> = Vec::with_capacity(buf.len() / 2);
391                    let mut buf = buf;
392                    while buf.len() >= 2 {
393                        vals.push(match arch {
394                            0 => u16::from_le_bytes(buf[..2].try_into().unwrap()),
395                            _ => u16::from_be_bytes(buf[..2].try_into().unwrap()),
396                        });
397                        buf = &buf[2..];
398                    }
399                    vals
400                }),
401                false => match arch {
402                    0 => Value::Uint16(u16::from_le_bytes(buf[..2].try_into().unwrap())),
403                    _ => Value::Uint16(u16::from_be_bytes(buf[..2].try_into().unwrap())),
404                },
405            },
406            FitBaseType::SINT32 => match array {
407                true => Value::VecInt32({
408                    let mut vals: Vec<i32> = Vec::with_capacity(buf.len() / 4);
409                    let mut buf = buf;
410                    while buf.len() >= 4 {
411                        vals.push(match arch {
412                            0 => i32::from_le_bytes(buf[..4].try_into().unwrap()),
413                            _ => i32::from_be_bytes(buf[..4].try_into().unwrap()),
414                        });
415                        buf = &buf[4..];
416                    }
417                    vals
418                }),
419                false => match arch {
420                    0 => Value::Int32(i32::from_le_bytes(buf[..4].try_into().unwrap())),
421                    _ => Value::Int32(i32::from_be_bytes(buf[..4].try_into().unwrap())),
422                },
423            },
424            FitBaseType::UINT32 | FitBaseType::UINT32Z => match array {
425                true => Value::VecUint32({
426                    let mut vals: Vec<u32> = Vec::with_capacity(buf.len() / 4);
427                    let mut buf = buf;
428                    while buf.len() >= 4 {
429                        vals.push(match arch {
430                            0 => u32::from_le_bytes(buf[..4].try_into().unwrap()),
431                            _ => u32::from_be_bytes(buf[..4].try_into().unwrap()),
432                        });
433                        buf = &buf[4..];
434                    }
435                    vals
436                }),
437                false => match arch {
438                    0 => Value::Uint32(u32::from_le_bytes(buf[..4].try_into().unwrap())),
439                    _ => Value::Uint32(u32::from_be_bytes(buf[..4].try_into().unwrap())),
440                },
441            },
442            FitBaseType::STRING => match array {
443                true => Value::String(String::from_utf8_lossy(buf).to_string()),
444                false => Value::VecString({
445                    let mut vals = Vec::with_capacity(strcount(buf) as usize);
446                    let mut last = 0usize;
447                    for (i, &v) in buf.iter().enumerate() {
448                        if v != 0 {
449                            continue;
450                        }
451                        if last != i {
452                            vals.push(String::from_utf8_lossy(&buf[last..i]).into_owned());
453                        }
454                        last = i + 1
455                    }
456                    vals
457                }),
458            },
459            FitBaseType::FLOAT32 => match array {
460                true => Value::VecFloat32({
461                    let mut vals: Vec<f32> = Vec::with_capacity(buf.len() / 4);
462                    let mut buf = buf;
463                    while buf.len() >= 4 {
464                        vals.push(match arch {
465                            0 => f32::from_le_bytes(buf[..4].try_into().unwrap()),
466                            _ => f32::from_be_bytes(buf[..4].try_into().unwrap()),
467                        });
468                        buf = &buf[4..];
469                    }
470                    vals
471                }),
472                false => match arch {
473                    0 => Value::Float32(f32::from_le_bytes(buf[..4].try_into().unwrap())),
474                    _ => Value::Float32(f32::from_be_bytes(buf[..4].try_into().unwrap())),
475                },
476            },
477            FitBaseType::FLOAT64 => match array {
478                true => Value::VecFloat64({
479                    let mut vals: Vec<f64> = Vec::with_capacity(buf.len() / 8);
480                    let mut buf = buf;
481                    while buf.len() >= 2 {
482                        vals.push(match arch {
483                            0 => f64::from_le_bytes(buf[..8].try_into().unwrap()),
484                            _ => f64::from_be_bytes(buf[..8].try_into().unwrap()),
485                        });
486                        buf = &buf[8..];
487                    }
488                    vals
489                }),
490                false => match arch {
491                    0 => Value::Float64(f64::from_le_bytes(buf[..8].try_into().unwrap())),
492                    _ => Value::Float64(f64::from_be_bytes(buf[..8].try_into().unwrap())),
493                },
494            },
495            FitBaseType::SINT64 => match array {
496                true => Value::VecInt64({
497                    let mut vals: Vec<i64> = Vec::with_capacity(buf.len() / 8);
498                    let mut buf = buf;
499                    while buf.len() >= 8 {
500                        vals.push(match arch {
501                            0 => i64::from_le_bytes(buf[..8].try_into().unwrap()),
502                            _ => i64::from_be_bytes(buf[..8].try_into().unwrap()),
503                        });
504                        buf = &buf[8..];
505                    }
506                    vals
507                }),
508                false => match arch {
509                    0 => Value::Int64(i64::from_le_bytes(buf[..8].try_into().unwrap())),
510                    _ => Value::Int64(i64::from_be_bytes(buf[..8].try_into().unwrap())),
511                },
512            },
513            FitBaseType::UINT64 | FitBaseType::UINT64Z => match array {
514                true => Value::VecUint64({
515                    let mut vals: Vec<u64> = Vec::with_capacity(buf.len() / 8);
516                    let mut buf = buf;
517                    while buf.len() >= 8 {
518                        vals.push(match arch {
519                            0 => u64::from_le_bytes(buf[..8].try_into().unwrap()),
520                            _ => u64::from_be_bytes(buf[..8].try_into().unwrap()),
521                        });
522                        buf = &buf[8..];
523                    }
524                    vals
525                }),
526                false => match arch {
527                    0 => Value::Uint64(u64::from_le_bytes(buf[..8].try_into().unwrap())),
528                    _ => Value::Uint64(u64::from_be_bytes(buf[..8].try_into().unwrap())),
529                },
530            },
531            _ => Value::Invalid,
532        }
533    }
534
535    pub(crate) fn marshal_append(&self, vec: &mut Vec<u8>, arch: u8) -> Result<(), Error> {
536        match self {
537            Value::Int8(v) => vec.push(*v as u8),
538            Value::Uint8(v) => vec.push(*v),
539            Value::Int16(v) => vec.extend_from_slice(&match arch {
540                0 => v.to_le_bytes(),
541                _ => v.to_be_bytes(),
542            }),
543            Value::Uint16(v) => vec.extend_from_slice(&match arch {
544                0 => v.to_le_bytes(),
545                _ => v.to_be_bytes(),
546            }),
547            Value::Int32(v) => vec.extend_from_slice(&match arch {
548                0 => v.to_le_bytes(),
549                _ => v.to_be_bytes(),
550            }),
551            Value::Uint32(v) => vec.extend_from_slice(&match arch {
552                0 => v.to_le_bytes(),
553                _ => v.to_be_bytes(),
554            }),
555            Value::String(v) => {
556                let b = v.as_bytes();
557                vec.extend_from_slice(b);
558                if v.is_empty() || b[b.len() - 1] != 0 {
559                    vec.push(0);
560                }
561            }
562            Value::Float32(v) => vec.extend_from_slice(&match arch {
563                0 => v.to_le_bytes(),
564                _ => v.to_be_bytes(),
565            }),
566            Value::Float64(v) => vec.extend_from_slice(&match arch {
567                0 => v.to_le_bytes(),
568                _ => v.to_be_bytes(),
569            }),
570            Value::Int64(v) => vec.extend_from_slice(&match arch {
571                0 => v.to_le_bytes(),
572                _ => v.to_be_bytes(),
573            }),
574            Value::Uint64(v) => vec.extend_from_slice(&match arch {
575                0 => v.to_le_bytes(),
576                _ => v.to_be_bytes(),
577            }),
578            Value::VecInt8(v) => {
579                for &x in v {
580                    vec.push(x as u8);
581                }
582            }
583            Value::VecUint8(v) => {
584                for &x in v {
585                    vec.push(x);
586                }
587            }
588            Value::VecInt16(v) => match arch {
589                0 => {
590                    for x in v {
591                        vec.extend_from_slice(&x.to_le_bytes());
592                    }
593                }
594                _ => {
595                    for x in v {
596                        vec.extend_from_slice(&x.to_be_bytes());
597                    }
598                }
599            },
600            Value::VecUint16(v) => match arch {
601                0 => {
602                    for x in v {
603                        vec.extend_from_slice(&x.to_le_bytes());
604                    }
605                }
606                _ => {
607                    for x in v {
608                        vec.extend_from_slice(&x.to_be_bytes());
609                    }
610                }
611            },
612            Value::VecInt32(v) => match arch {
613                0 => {
614                    for x in v {
615                        vec.extend_from_slice(&x.to_le_bytes());
616                    }
617                }
618                _ => {
619                    for x in v {
620                        vec.extend_from_slice(&x.to_be_bytes());
621                    }
622                }
623            },
624            Value::VecUint32(v) => match arch {
625                0 => {
626                    for x in v {
627                        vec.extend_from_slice(&x.to_le_bytes());
628                    }
629                }
630                _ => {
631                    for x in v {
632                        vec.extend_from_slice(&x.to_be_bytes());
633                    }
634                }
635            },
636            Value::VecString(v) => {
637                for x in v {
638                    let b = x.as_bytes();
639                    vec.extend_from_slice(b);
640                    if v.is_empty() || b[b.len() - 1] != 0 {
641                        vec.push(0);
642                    }
643                }
644            }
645            Value::VecFloat32(v) => match arch {
646                0 => {
647                    for x in v {
648                        vec.extend_from_slice(&x.to_le_bytes());
649                    }
650                }
651                _ => {
652                    for x in v {
653                        vec.extend_from_slice(&x.to_be_bytes());
654                    }
655                }
656            },
657            Value::VecFloat64(v) => match arch {
658                0 => {
659                    for x in v {
660                        vec.extend_from_slice(&x.to_le_bytes());
661                    }
662                }
663                _ => {
664                    for x in v {
665                        vec.extend_from_slice(&x.to_be_bytes());
666                    }
667                }
668            },
669            Value::VecInt64(v) => match arch {
670                0 => {
671                    for x in v {
672                        vec.extend_from_slice(&x.to_le_bytes());
673                    }
674                }
675                _ => {
676                    for x in v {
677                        vec.extend_from_slice(&x.to_be_bytes());
678                    }
679                }
680            },
681            Value::VecUint64(v) => match arch {
682                0 => {
683                    for x in v {
684                        vec.extend_from_slice(&x.to_le_bytes());
685                    }
686                }
687                _ => {
688                    for x in v {
689                        vec.extend_from_slice(&x.to_be_bytes());
690                    }
691                }
692            },
693            Value::Invalid => return Err(Error::InvalidValue),
694        };
695        Ok(())
696    }
697
698    /// cast_i64 converts any integer value into i64. If the value is not an integer, this returns i64::MAX.
699    pub(crate) fn cast_i64(&self) -> i64 {
700        match self {
701            Value::Uint8(v) => *v as i64,
702            Value::Int8(v) => *v as i64,
703            Value::Int16(v) => *v as i64,
704            Value::Uint16(v) => *v as i64,
705            Value::Int32(v) => *v as i64,
706            Value::Uint32(v) => *v as i64,
707            Value::Int64(v) => *v,
708            Value::Uint64(v) => *v as i64,
709            _ => i64::MAX,
710        }
711    }
712
713    /// Returns i8 or its invalid value when it's not an i8 value.
714    pub fn as_i8(&self) -> i8 {
715        if let Value::Int8(v) = self {
716            return *v;
717        }
718        i8::MAX
719    }
720
721    /// Returns u8 or its invalid value when it's not an u8 value.
722    pub fn as_u8(&self) -> u8 {
723        if let Value::Uint8(v) = self {
724            return *v;
725        }
726        u8::MAX
727    }
728
729    /// Returns u8z or its invalid value when it's not an u8z value.
730    pub fn as_u8z(&self) -> u8 {
731        if let Value::Uint8(v) = self {
732            return *v;
733        }
734        0
735    }
736
737    /// Returns i16 or its invalid value when it's not an i16 value.
738    pub fn as_i16(&self) -> i16 {
739        if let Value::Int16(v) = self {
740            return *v;
741        }
742        i16::MAX
743    }
744
745    /// Returns u16 or its invalid value when it's not an u16 value.
746    pub fn as_u16(&self) -> u16 {
747        if let Value::Uint16(v) = self {
748            return *v;
749        }
750        u16::MAX
751    }
752
753    /// Returns u16z or its invalid value when it's not an u16z value.
754    pub fn as_u16z(&self) -> u16 {
755        if let Value::Uint16(v) = self {
756            return *v;
757        }
758        0
759    }
760
761    /// Returns i32 or its invalid value when it's not an i32 value.
762    pub fn as_i32(&self) -> i32 {
763        if let Value::Int32(v) = self {
764            return *v;
765        }
766        i32::MAX
767    }
768
769    /// Returns u32 or its invalid value when it's not an u32 value.
770    pub fn as_u32(&self) -> u32 {
771        if let Value::Uint32(v) = self {
772            return *v;
773        }
774        u32::MAX
775    }
776
777    /// Returns u32z or its invalid value when it's not an u32z value.
778    pub fn as_u32z(&self) -> u32 {
779        if let Value::Uint32(v) = self {
780            return *v;
781        }
782        0
783    }
784
785    /// Returns string (clone) or empty string when it's not a string.
786    pub fn as_string(&self) -> String {
787        if let Value::String(v) = self {
788            return v.clone();
789        }
790        String::new()
791    }
792
793    /// Returns f32 or its invalid value when it's not a f32 value.
794    pub fn as_f32(&self) -> f32 {
795        if let Value::Float32(v) = self {
796            return *v;
797        }
798        f32::MAX
799    }
800
801    /// Returns f64 or its invalid value when it's not a f64 value.
802    pub fn as_f64(&self) -> f64 {
803        if let Value::Float64(v) = self {
804            return *v;
805        }
806        f64::MAX
807    }
808
809    /// Returns i64 or its invalid value when it's not an i64 value.
810    pub fn as_i64(&self) -> i64 {
811        if let Value::Int64(v) = self {
812            return *v;
813        }
814        i64::MAX
815    }
816
817    /// Returns u64 or its invalid value when it's not an u64 value.
818    pub fn as_u64(&self) -> u64 {
819        if let Value::Uint64(v) = self {
820            return *v;
821        }
822        u64::MAX
823    }
824
825    /// Returns u64z or its invalid value when it's not an u64z value.
826    pub fn as_u64z(&self) -> u64 {
827        if let Value::Uint64(v) = self {
828            return *v;
829        }
830        0
831    }
832
833    /// Returns Vec<i8> (clone) or empty vector when it's not a Vec<i8> value.
834    pub fn as_vec_i8(&self) -> Vec<i8> {
835        if let Value::VecInt8(v) = self {
836            return v.clone();
837        }
838        Vec::new()
839    }
840
841    /// Returns Vec<u8> (clone) or empty vector when it's not a Vec<u8> value.
842    pub fn as_vec_u8(&self) -> Vec<u8> {
843        if let Value::VecUint8(v) = self {
844            return v.clone();
845        }
846        Vec::new()
847    }
848
849    /// Returns Vec<i16> (clone) or empty vector when it's not a Vec<i16> value.
850    pub fn as_vec_i16(&self) -> Vec<i16> {
851        if let Value::VecInt16(v) = self {
852            return v.clone();
853        }
854        Vec::new()
855    }
856
857    /// Returns Vec<u16> (clone) or empty vector when it's not a Vec<u16> value.
858    pub fn as_vec_u16(&self) -> Vec<u16> {
859        if let Value::VecUint16(v) = self {
860            return v.clone();
861        }
862        Vec::new()
863    }
864
865    /// Returns Vec<i32> (clone) or empty vector when it's not a Vec<i32> value.
866    pub fn as_vec_i32(&self) -> Vec<i32> {
867        if let Value::VecInt32(v) = self {
868            return v.clone();
869        }
870        Vec::new()
871    }
872
873    /// Returns Vec<u32> (clone) or empty vector when it's not a Vec<u32> value.
874    pub fn as_vec_u32(&self) -> Vec<u32> {
875        if let Value::VecUint32(v) = self {
876            return v.clone();
877        }
878        Vec::new()
879    }
880
881    /// Returns Vec<String> (clone) or empty vector when it's not a Vec<String> value.
882    pub fn as_vec_string(&self) -> Vec<String> {
883        if let Value::VecString(v) = self {
884            return v.clone();
885        }
886        Vec::new()
887    }
888
889    /// Returns Vec<f32> (clone) or empty vector when it's not a Vec<f32> value.
890    pub fn as_vec_f32(&self) -> Vec<f32> {
891        if let Value::VecFloat32(v) = self {
892            return v.clone();
893        }
894        Vec::new()
895    }
896
897    /// Returns Vec<f64> (clone) or empty vector when it's not a Vec<f64> value.
898    pub fn as_vec_f64(&self) -> Vec<f64> {
899        if let Value::VecFloat64(v) = self {
900            return v.clone();
901        }
902        Vec::new()
903    }
904
905    /// Returns Vec<i64> (clone) or empty vector when it's not a Vec<i64> value.
906    pub fn as_vec_i64(&self) -> Vec<i64> {
907        if let Value::VecInt64(v) = self {
908            return v.clone();
909        }
910        Vec::new()
911    }
912
913    /// Returns Vec<u64> (clone) or empty vector when it's not a Vec<u64> value.
914    pub fn as_vec_u64(&self) -> Vec<u64> {
915        if let Value::VecUint64(v) = self {
916            return v.clone();
917        }
918        Vec::new()
919    }
920
921    /// Checks whether Value holds any representation of invalid value based on base_type.
922    /// An array is invalid when all elements represent invalid value.
923    pub(crate) fn is_valid(&self, base_type: FitBaseType) -> bool {
924        match self {
925            Value::Int8(v) => *v != i8::MAX,
926            Value::Uint8(v) => match base_type {
927                FitBaseType::UINT8 | FitBaseType::ENUM | FitBaseType::BYTE => *v != u8::MAX,
928                FitBaseType::UINT8Z => *v != 0,
929                _ => false,
930            },
931            Value::Int16(v) => *v != i16::MAX,
932            Value::Uint16(v) => match base_type {
933                FitBaseType::UINT16 => *v != u16::MAX,
934                FitBaseType::UINT16Z => *v != 0,
935                _ => false,
936            },
937            Value::Int32(v) => *v != i32::MAX,
938            Value::Uint32(v) => match base_type {
939                FitBaseType::UINT32 => *v != u32::MAX,
940                FitBaseType::UINT32Z => *v != 0,
941                _ => false,
942            },
943            Value::String(v) => !v.is_empty() && v.as_str() != "\x00",
944            Value::Float32(v) => f32::to_bits(*v) != u32::MAX,
945            Value::Float64(v) => f64::to_bits(*v) != u64::MAX,
946            Value::Int64(v) => *v != i64::MAX,
947            Value::Uint64(v) => match base_type {
948                FitBaseType::UINT64 => *v != u64::MAX,
949                FitBaseType::UINT64Z => *v != 0,
950                _ => false,
951            },
952            Value::VecInt8(v) => {
953                for &x in v {
954                    if x != i8::MAX {
955                        return true;
956                    }
957                }
958                false
959            }
960            Value::VecUint8(v) => match base_type {
961                FitBaseType::UINT8 => {
962                    for &x in v {
963                        if x != u8::MAX {
964                            return true;
965                        }
966                    }
967                    false
968                }
969                FitBaseType::UINT8Z => {
970                    for &x in v {
971                        if x != u8::MIN {
972                            return true;
973                        }
974                    }
975                    false
976                }
977                _ => false,
978            },
979            Value::VecInt16(v) => {
980                for &x in v {
981                    if x != i16::MAX {
982                        return true;
983                    }
984                }
985                false
986            }
987            Value::VecUint16(v) => match base_type {
988                FitBaseType::UINT16 => {
989                    for &x in v {
990                        if x != u16::MAX {
991                            return true;
992                        }
993                    }
994                    false
995                }
996                FitBaseType::UINT16Z => {
997                    for &x in v {
998                        if x != u16::MIN {
999                            return true;
1000                        }
1001                    }
1002                    false
1003                }
1004                _ => false,
1005            },
1006            Value::VecInt32(v) => {
1007                for &x in v {
1008                    if x != i32::MAX {
1009                        return true;
1010                    }
1011                }
1012                false
1013            }
1014            Value::VecUint32(v) => match base_type {
1015                FitBaseType::UINT32 => {
1016                    for &x in v {
1017                        if x != u32::MAX {
1018                            return true;
1019                        }
1020                    }
1021                    false
1022                }
1023                FitBaseType::UINT32Z => {
1024                    for &x in v {
1025                        if x != u32::MIN {
1026                            return true;
1027                        }
1028                    }
1029                    false
1030                }
1031                _ => false,
1032            },
1033            Value::VecString(v) => {
1034                for x in v {
1035                    if !x.is_empty() && x.as_str() != "\x00" {
1036                        return true;
1037                    }
1038                }
1039                false
1040            }
1041            Value::VecFloat32(v) => {
1042                for &x in v {
1043                    if x.to_bits() != u32::MAX {
1044                        return true;
1045                    }
1046                }
1047                false
1048            }
1049            Value::VecFloat64(v) => {
1050                for &x in v {
1051                    if x.to_bits() != u64::MAX {
1052                        return true;
1053                    }
1054                }
1055                false
1056            }
1057            Value::VecInt64(v) => {
1058                for &x in v {
1059                    if x != i64::MAX {
1060                        return true;
1061                    }
1062                }
1063                false
1064            }
1065            Value::VecUint64(v) => match base_type {
1066                FitBaseType::UINT64 => {
1067                    for &x in v {
1068                        if x != u64::MAX {
1069                            return true;
1070                        }
1071                    }
1072                    false
1073                }
1074                FitBaseType::UINT64Z => {
1075                    for &x in v {
1076                        if x != u64::MIN {
1077                            return true;
1078                        }
1079                    }
1080                    false
1081                }
1082                _ => false,
1083            },
1084            Value::Invalid => false,
1085        }
1086    }
1087
1088    /// Checks whether Value's type is align with given basetype.
1089    pub(crate) fn is_align(&self, base_type: FitBaseType) -> bool {
1090        match self {
1091            Value::Int8(_) => base_type == FitBaseType::SINT8,
1092            Value::Uint8(_) => {
1093                base_type == FitBaseType::ENUM
1094                    || base_type == FitBaseType::UINT8
1095                    || base_type == FitBaseType::UINT8Z
1096                    || base_type == FitBaseType::BYTE
1097            }
1098            Value::Int16(_) => base_type == FitBaseType::SINT16,
1099            Value::Uint16(_) => {
1100                base_type == FitBaseType::UINT16 || base_type == FitBaseType::UINT16Z
1101            }
1102            Value::Int32(_) => base_type == FitBaseType::SINT32,
1103            Value::Uint32(_) => {
1104                base_type == FitBaseType::UINT32 || base_type == FitBaseType::UINT32Z
1105            }
1106            Value::String(_) => base_type == FitBaseType::STRING,
1107            Value::Float32(_) => base_type == FitBaseType::FLOAT32,
1108            Value::Float64(_) => base_type == FitBaseType::FLOAT64,
1109            Value::Int64(_) => base_type == FitBaseType::SINT64,
1110            Value::Uint64(_) => {
1111                base_type == FitBaseType::UINT64 || base_type == FitBaseType::UINT64Z
1112            }
1113            Value::VecInt8(_) => base_type == FitBaseType::SINT8,
1114            Value::VecUint8(_) => {
1115                base_type == FitBaseType::ENUM
1116                    || base_type == FitBaseType::UINT8
1117                    || base_type == FitBaseType::UINT8Z
1118                    || base_type == FitBaseType::BYTE
1119            }
1120            Value::VecInt16(_) => base_type == FitBaseType::SINT16,
1121            Value::VecUint16(_) => {
1122                base_type == FitBaseType::UINT16 || base_type == FitBaseType::UINT16Z
1123            }
1124            Value::VecInt32(_) => base_type == FitBaseType::SINT32,
1125            Value::VecUint32(_) => {
1126                base_type == FitBaseType::UINT32 || base_type == FitBaseType::UINT32Z
1127            }
1128            Value::VecString(_) => base_type == FitBaseType::STRING,
1129            Value::VecFloat32(_) => base_type == FitBaseType::FLOAT32,
1130            Value::VecFloat64(_) => base_type == FitBaseType::FLOAT64,
1131            Value::VecInt64(_) => base_type == FitBaseType::SINT64,
1132            Value::VecUint64(_) => {
1133                base_type == FitBaseType::UINT64 || base_type == FitBaseType::UINT64Z
1134            }
1135            _ => false,
1136        }
1137    }
1138
1139    /// Returns the size of Value in binary from. For every string in Value,
1140    /// if the last index of the string is not '\x00', size += 1.
1141    pub(crate) fn size(&self) -> usize {
1142        match self {
1143            Value::Int8(_) | Value::Uint8(_) => 1,
1144            Value::Int16(_) | Value::Uint16(_) => 2,
1145            Value::Int32(_) | Value::Uint32(_) | Value::Float32(_) => 4,
1146            Value::Int64(_) | Value::Uint64(_) | Value::Float64(_) => 8,
1147            Value::String(v) => {
1148                let n = v.len();
1149                if n == 0 || v.as_bytes()[n - 1] != 0 {
1150                    return n + 1;
1151                }
1152                n
1153            }
1154            Value::VecInt8(v) => v.len(),
1155            Value::VecUint8(v) => v.len(),
1156            Value::VecInt16(v) => v.len() * 2,
1157            Value::VecUint16(v) => v.len() * 2,
1158            Value::VecInt32(v) => v.len() * 4,
1159            Value::VecUint32(v) => v.len() * 4,
1160            Value::VecFloat32(v) => v.len() * 4,
1161            Value::VecFloat64(v) => v.len() * 8,
1162            Value::VecInt64(v) => v.len() * 8,
1163            Value::VecUint64(v) => v.len() * 8,
1164            Value::VecString(v) => {
1165                let mut size = 0usize;
1166                for x in v {
1167                    let mut n = x.len();
1168                    if n == 0 || x.as_bytes()[n - 1] != 0 {
1169                        n += 1;
1170                    }
1171                    size += n;
1172                }
1173                size
1174            }
1175            Value::Invalid => 0,
1176        }
1177    }
1178}
1179
1180/// Protocol Version representation.
1181#[derive(Default, Debug, Clone, Copy, PartialEq)]
1182pub struct ProtocolVersion(pub u8);
1183
1184#[allow(missing_docs)]
1185impl ProtocolVersion {
1186    pub const V1: ProtocolVersion = ProtocolVersion(1 << 4);
1187    pub const V2: ProtocolVersion = ProtocolVersion(2 << 4);
1188
1189    /// Returns major version.
1190    pub fn major(self) -> u8 {
1191        self.0 >> 4
1192    }
1193
1194    /// Returns minor version.
1195    pub fn minor(self) -> u8 {
1196        self.0 | ((1 << 4) - 1)
1197    }
1198}
1199
1200/// Validates whether the message contains unsupported data for the targeted protocol version.
1201pub(crate) fn validate_message(
1202    mesg: &Message,
1203    protocol_version: ProtocolVersion,
1204) -> Result<(), Error> {
1205    if protocol_version == ProtocolVersion::V1 {
1206        if !mesg.developer_fields.is_empty() {
1207            return Err(Error::ProtocolViolationDeveloperData);
1208        }
1209        for field in &mesg.fields {
1210            if field.profile_type.base_type().0 & FitBaseType::NUM_MASK
1211                > FitBaseType::BYTE.0 & FitBaseType::NUM_MASK
1212            {
1213                return Err(Error::ProtocolViolationUnsupportedBaseType(
1214                    field.profile_type.base_type(),
1215                ));
1216            }
1217        }
1218    }
1219    Ok(())
1220}
1221
1222/// Counts how many valid utf-8 string in s.
1223pub(crate) fn strcount(s: &[u8]) -> u8 {
1224    let mut last = 0usize;
1225    let mut size = 0u8;
1226    for (i, &v) in s.iter().enumerate() {
1227        if v != 0 {
1228            continue;
1229        }
1230        if last != i {
1231            size += 1
1232        }
1233        last = i + 1
1234    }
1235    if size == 0 && !s.is_empty() {
1236        return 1; // Allow string without utf-8 null termination.
1237    }
1238    size
1239}
1240
1241#[cfg(test)]
1242mod tests {
1243    use crate::{
1244        profile::typedef::FitBaseType,
1245        proto::{Value, strcount},
1246    };
1247
1248    #[test]
1249    fn test_strcount() {
1250        #[derive(Default, Clone, Copy)]
1251        struct Case {
1252            input: &'static str,
1253            expected: u8,
1254        }
1255
1256        let tt = [
1257            Case {
1258                input: "Open Water",
1259                expected: 1,
1260            },
1261            Case {
1262                input: "Open Water\x00",
1263                expected: 1,
1264            },
1265            Case {
1266                input: "Open Water\x00\x00",
1267                expected: 1,
1268            },
1269            Case {
1270                input: "Open\x00Water\x00",
1271                expected: 2,
1272            },
1273        ];
1274
1275        for (i, tc) in tt.iter().enumerate() {
1276            let v = strcount(tc.input.as_bytes());
1277            assert_eq!(v, tc.expected, "index {} input \"{}\"", i, tc.input);
1278        }
1279    }
1280
1281    #[test]
1282    fn test_value_is_valid() {
1283        struct Case {
1284            value: Value,
1285            base_type: FitBaseType,
1286            is_valid: bool,
1287        }
1288
1289        let tt = [
1290            Case {
1291                value: Value::Int8(i8::MIN),
1292                base_type: FitBaseType::SINT8,
1293                is_valid: true,
1294            },
1295            Case {
1296                value: Value::Int8(i8::MAX),
1297                base_type: FitBaseType::SINT8,
1298                is_valid: false,
1299            },
1300            Case {
1301                value: Value::Uint8(u8::MIN),
1302                base_type: FitBaseType::UINT8,
1303                is_valid: true,
1304            },
1305            Case {
1306                value: Value::Uint8(u8::MAX),
1307                base_type: FitBaseType::UINT8,
1308                is_valid: false,
1309            },
1310            Case {
1311                value: Value::Uint8(u8::MIN),
1312                base_type: FitBaseType::UINT8Z,
1313                is_valid: false,
1314            },
1315            Case {
1316                value: Value::Uint8(u8::MAX),
1317                base_type: FitBaseType::UINT8Z,
1318                is_valid: true,
1319            },
1320            Case {
1321                value: Value::Int16(i16::MIN),
1322                base_type: FitBaseType::SINT16,
1323                is_valid: true,
1324            },
1325            Case {
1326                value: Value::Int16(i16::MAX),
1327                base_type: FitBaseType::SINT16,
1328                is_valid: false,
1329            },
1330            Case {
1331                value: Value::Uint16(u16::MIN),
1332                base_type: FitBaseType::UINT16,
1333                is_valid: true,
1334            },
1335            Case {
1336                value: Value::Uint16(u16::MAX),
1337                base_type: FitBaseType::UINT16,
1338                is_valid: false,
1339            },
1340            Case {
1341                value: Value::Uint16(u16::MIN),
1342                base_type: FitBaseType::UINT16Z,
1343                is_valid: false,
1344            },
1345            Case {
1346                value: Value::Uint16(u16::MAX),
1347                base_type: FitBaseType::UINT16Z,
1348                is_valid: true,
1349            },
1350            Case {
1351                value: Value::Int32(i32::MIN),
1352                base_type: FitBaseType::SINT32,
1353                is_valid: true,
1354            },
1355            Case {
1356                value: Value::Int32(i32::MAX),
1357                base_type: FitBaseType::SINT32,
1358                is_valid: false,
1359            },
1360            Case {
1361                value: Value::Uint32(u32::MIN),
1362                base_type: FitBaseType::UINT32,
1363                is_valid: true,
1364            },
1365            Case {
1366                value: Value::Uint32(u32::MAX),
1367                base_type: FitBaseType::UINT32,
1368                is_valid: false,
1369            },
1370            Case {
1371                value: Value::Uint32(u32::MIN),
1372                base_type: FitBaseType::UINT32Z,
1373                is_valid: false,
1374            },
1375            Case {
1376                value: Value::Uint32(u32::MAX),
1377                base_type: FitBaseType::UINT32Z,
1378                is_valid: true,
1379            },
1380            Case {
1381                value: Value::Float32(f32::MIN),
1382                base_type: FitBaseType::FLOAT32,
1383                is_valid: true,
1384            },
1385            Case {
1386                value: Value::Float32(f32::from_bits(u32::MAX)),
1387                base_type: FitBaseType::FLOAT32,
1388                is_valid: false,
1389            },
1390            Case {
1391                value: Value::Float64(f64::MIN),
1392                base_type: FitBaseType::FLOAT64,
1393                is_valid: true,
1394            },
1395            Case {
1396                value: Value::Float64(f64::from_bits(u64::MAX)),
1397                base_type: FitBaseType::FLOAT64,
1398                is_valid: false,
1399            },
1400            Case {
1401                value: Value::Int64(i64::MIN),
1402                base_type: FitBaseType::SINT64,
1403                is_valid: true,
1404            },
1405            Case {
1406                value: Value::Int64(i64::MAX),
1407                base_type: FitBaseType::SINT64,
1408                is_valid: false,
1409            },
1410            Case {
1411                value: Value::Uint64(u64::MIN),
1412                base_type: FitBaseType::UINT64,
1413                is_valid: true,
1414            },
1415            Case {
1416                value: Value::Uint64(u64::MAX),
1417                base_type: FitBaseType::UINT64,
1418                is_valid: false,
1419            },
1420            Case {
1421                value: Value::Uint64(u64::MIN),
1422                base_type: FitBaseType::UINT64Z,
1423                is_valid: false,
1424            },
1425            Case {
1426                value: Value::Uint64(u64::MAX),
1427                base_type: FitBaseType::UINT64Z,
1428                is_valid: true,
1429            },
1430            Case {
1431                value: Value::String("rustyfit".to_string()),
1432                base_type: FitBaseType::STRING,
1433                is_valid: true,
1434            },
1435            Case {
1436                value: Value::String("".to_string()),
1437                base_type: FitBaseType::STRING,
1438                is_valid: false,
1439            },
1440            Case {
1441                value: Value::String("\x00".to_string()),
1442                base_type: FitBaseType::STRING,
1443                is_valid: false,
1444            },
1445            Case {
1446                value: Value::VecInt8(vec![0i8, 1i8]),
1447                base_type: FitBaseType::SINT8,
1448                is_valid: true,
1449            },
1450            Case {
1451                value: Value::VecInt8(vec![i8::MAX, i8::MAX]),
1452                base_type: FitBaseType::SINT8,
1453                is_valid: false,
1454            },
1455            Case {
1456                value: Value::VecUint8(vec![0u8, 1u8]),
1457                base_type: FitBaseType::UINT8,
1458                is_valid: true,
1459            },
1460            Case {
1461                value: Value::VecUint8(vec![0u8, 1u8]),
1462                base_type: FitBaseType::UINT8Z,
1463                is_valid: true,
1464            },
1465            Case {
1466                value: Value::VecUint8(vec![u8::MAX, u8::MAX]),
1467                base_type: FitBaseType::UINT8,
1468                is_valid: false,
1469            },
1470            Case {
1471                value: Value::VecUint8(vec![u8::MIN, u8::MIN]),
1472                base_type: FitBaseType::UINT8Z,
1473                is_valid: false,
1474            },
1475            Case {
1476                value: Value::VecInt16(vec![0i16, 1i16]),
1477                base_type: FitBaseType::SINT16,
1478                is_valid: true,
1479            },
1480            Case {
1481                value: Value::VecInt16(vec![i16::MAX, i16::MAX]),
1482                base_type: FitBaseType::SINT16,
1483                is_valid: false,
1484            },
1485            Case {
1486                value: Value::VecUint16(vec![0u16, 1u16]),
1487                base_type: FitBaseType::UINT16,
1488                is_valid: true,
1489            },
1490            Case {
1491                value: Value::VecUint16(vec![0u16, 1u16]),
1492                base_type: FitBaseType::UINT16Z,
1493                is_valid: true,
1494            },
1495            Case {
1496                value: Value::VecUint16(vec![u16::MAX, u16::MAX]),
1497                base_type: FitBaseType::UINT16,
1498                is_valid: false,
1499            },
1500            Case {
1501                value: Value::VecUint16(vec![u16::MIN, u16::MIN]),
1502                base_type: FitBaseType::UINT16Z,
1503                is_valid: false,
1504            },
1505            Case {
1506                value: Value::VecInt32(vec![0i32, 1i32]),
1507                base_type: FitBaseType::SINT32,
1508                is_valid: true,
1509            },
1510            Case {
1511                value: Value::VecInt32(vec![i32::MAX, i32::MAX]),
1512                base_type: FitBaseType::SINT32,
1513                is_valid: false,
1514            },
1515            Case {
1516                value: Value::VecUint32(vec![0u32, 1u32]),
1517                base_type: FitBaseType::UINT32,
1518                is_valid: true,
1519            },
1520            Case {
1521                value: Value::VecUint32(vec![0u32, 1u32]),
1522                base_type: FitBaseType::UINT32Z,
1523                is_valid: true,
1524            },
1525            Case {
1526                value: Value::VecUint32(vec![u32::MAX, u32::MAX]),
1527                base_type: FitBaseType::UINT32,
1528                is_valid: false,
1529            },
1530            Case {
1531                value: Value::VecUint32(vec![u32::MIN, u32::MIN]),
1532                base_type: FitBaseType::UINT32Z,
1533                is_valid: false,
1534            },
1535            Case {
1536                value: Value::VecFloat32(vec![0f32, 1f32]),
1537                base_type: FitBaseType::FLOAT32,
1538                is_valid: true,
1539            },
1540            Case {
1541                value: Value::VecFloat32(vec![f32::from_bits(u32::MAX), f32::from_bits(u32::MAX)]),
1542                base_type: FitBaseType::FLOAT32,
1543                is_valid: false,
1544            },
1545            Case {
1546                value: Value::VecFloat64(vec![0f64, 1f64]),
1547                base_type: FitBaseType::FLOAT64,
1548                is_valid: true,
1549            },
1550            Case {
1551                value: Value::VecFloat64(vec![f64::from_bits(u64::MAX), f64::from_bits(u64::MAX)]),
1552                base_type: FitBaseType::FLOAT64,
1553                is_valid: false,
1554            },
1555            Case {
1556                value: Value::VecInt64(vec![0i64, 1i64]),
1557                base_type: FitBaseType::SINT64,
1558                is_valid: true,
1559            },
1560            Case {
1561                value: Value::VecInt64(vec![i64::MAX, i64::MAX]),
1562                base_type: FitBaseType::SINT64,
1563                is_valid: false,
1564            },
1565            Case {
1566                value: Value::VecUint64(vec![0u64, 1u64]),
1567                base_type: FitBaseType::UINT64,
1568                is_valid: true,
1569            },
1570            Case {
1571                value: Value::VecUint64(vec![0u64, 1u64]),
1572                base_type: FitBaseType::UINT64Z,
1573                is_valid: true,
1574            },
1575            Case {
1576                value: Value::VecUint64(vec![u64::MAX, u64::MAX]),
1577                base_type: FitBaseType::UINT64,
1578                is_valid: false,
1579            },
1580            Case {
1581                value: Value::VecUint64(vec![u64::MIN, u64::MIN]),
1582                base_type: FitBaseType::UINT64Z,
1583                is_valid: false,
1584            },
1585            Case {
1586                value: Value::VecString(vec!["rustyfit".to_string(), "rustyfit".to_string()]),
1587                base_type: FitBaseType::STRING,
1588                is_valid: true,
1589            },
1590            Case {
1591                value: Value::VecString(vec!["\x00".to_string(), "\x00".to_string()]),
1592                base_type: FitBaseType::STRING,
1593                is_valid: false,
1594            },
1595        ];
1596
1597        for (i, tc) in tt.iter().enumerate() {
1598            let is_valid = tc.value.is_valid(tc.base_type);
1599            assert_eq!(
1600                tc.is_valid, is_valid,
1601                "{}: {:?} | {}",
1602                i, tc.value, tc.base_type,
1603            );
1604        }
1605    }
1606}