use std::collections::HashMap;
use crate::base_type::BaseType;
#[derive(Debug, Clone)]
pub struct DevFieldInfo {
pub name: String,
pub base_type: BaseType,
pub scale: Option<f64>,
pub offset: Option<f64>,
pub units: Option<String>,
}
type DevFieldKey = (u8, u8);
#[derive(Debug, Default, Clone)]
pub struct DevFieldRegistry {
fields: HashMap<DevFieldKey, DevFieldInfo>,
}
impl DevFieldRegistry {
pub fn new() -> Self {
Self::default()
}
#[allow(clippy::too_many_arguments)]
pub fn register_field(
&mut self,
developer_data_index: u8,
field_definition_number: u8,
field_name: String,
fit_base_type_id: u8,
scale: Option<f64>,
offset: Option<f64>,
units: Option<String>,
) {
let base_type = match BaseType::from_byte(fit_base_type_id & BaseType::TYPE_CODE_MASK) {
Ok(bt) => bt,
Err(_) => return, };
let key = (developer_data_index, field_definition_number);
self.fields.insert(
key,
DevFieldInfo {
name: field_name,
base_type,
scale,
offset,
units,
},
);
}
pub fn get(&self, developer_data_index: u8, field_def_num: u8) -> Option<&DevFieldInfo> {
self.fields.get(&(developer_data_index, field_def_num))
}
pub fn len(&self) -> usize {
self.fields.len()
}
pub fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}
pub fn base_type_to_type_name(bt: BaseType) -> &'static str {
match bt {
BaseType::Enum => "enum",
BaseType::SInt8 => "sint8",
BaseType::UInt8 => "uint8",
BaseType::SInt16 => "sint16",
BaseType::UInt16 => "uint16",
BaseType::SInt32 => "sint32",
BaseType::UInt32 => "uint32",
BaseType::String => "string",
BaseType::Float32 => "float32",
BaseType::Float64 => "float64",
BaseType::UInt8z => "uint8z",
BaseType::UInt16z => "uint16z",
BaseType::UInt32z => "uint32z",
BaseType::Byte => "byte",
BaseType::SInt64 => "sint64",
BaseType::UInt64 => "uint64",
BaseType::UInt64z => "uint64z",
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_and_lookup() {
let mut reg = DevFieldRegistry::new();
reg.register_field(
0,
0,
"heart_rate".to_string(),
0x02, None,
None,
Some("bpm".to_string()),
);
let info = reg.get(0, 0).unwrap();
assert_eq!(info.name, "heart_rate");
assert_eq!(info.base_type, BaseType::UInt8);
assert_eq!(info.units.as_deref(), Some("bpm"));
}
#[test]
fn unknown_base_type_is_skipped() {
let mut reg = DevFieldRegistry::new();
reg.register_field(0, 0, "bad".to_string(), 0xFF, None, None, None);
assert!(reg.is_empty());
}
#[test]
fn base_type_to_type_name_round_trip() {
for code in 0x00..=0x10 {
let bt = BaseType::from_byte(code).unwrap();
let name = base_type_to_type_name(bt);
assert!(!name.is_empty());
}
}
}