#[cfg_attr(feature = "c", repr(C))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct NmeaNumber {
pub value: i64,
pub scale: u8,
}
impl NmeaNumber {
#[must_use]
pub fn new(value: i64, scale: u8) -> Self {
Self { value, scale }
}
#[must_use]
pub fn parse(raw: &str) -> Option<Self> {
let (int_part, frac_part) = match raw.find('.') {
Some(i) => (&raw[..i], &raw[i + 1..]),
None => (raw, ""),
};
let scale: u8 = frac_part.len().try_into().ok()?;
let int_val: i64 = int_part.parse().ok()?;
let frac_val: i64 = frac_part.parse().ok()?;
let negative = int_part.starts_with('-');
let value =
int_val * 10i64.pow(u32::from(scale)) + if negative { -frac_val } else { frac_val };
Some(Self { value, scale })
}
}
#[cfg(feature = "float")]
impl From<NmeaNumber> for f32 {
#[allow(
clippy::cast_precision_loss,
reason = "f32 precision loss is intentional"
)]
fn from(num: NmeaNumber) -> Self {
let scale = 10i64.checked_pow(u32::from(num.scale)).unwrap_or(i64::MAX);
num.value as f32 / scale as f32
}
}
#[cfg(feature = "float")]
impl From<NmeaNumber> for f64 {
#[allow(
clippy::cast_precision_loss,
reason = "f64 precision loss is intentional"
)]
fn from(num: NmeaNumber) -> Self {
let scale = 10i64.checked_pow(u32::from(num.scale)).unwrap_or(i64::MAX);
num.value as f64 / scale as f64
}
}