use std::ops::Deref;
pub(crate) enum Units {
Distance([u8; 4]),
Velocity([u8; 4]),
Acceleration([u8; 4]),
}
impl Units {
#[doc(hidden)]
#[inline]
fn array_from_slice<const N: usize>(slice: &[u8]) -> [u8; N] {
let mut array = [0u8; N];
for (i, &byte) in slice.iter().take(N).enumerate() {
array[i] = byte;
}
array
}
pub(crate) fn distance_from_slice(slice: &[u8]) -> Units {
Units::Distance(Units::array_from_slice(slice))
}
pub(crate) fn velocity_from_slice(slice: &[u8]) -> Units {
Units::Velocity(Units::array_from_slice(slice))
}
pub(crate) fn acceleration_from_slice(slice: &[u8]) -> Units {
Units::Acceleration(Units::array_from_slice(slice))
}
fn encode(value: f64, scale_factor: f64) -> [u8; 4] {
let scaled = value * scale_factor;
let rounded = scaled.round() as i32;
i32::to_le_bytes(rounded)
}
pub(crate) const fn approx(n1: f64, n2: f64) -> bool {
(n1 - n2).abs() < 1E-6
}
}
impl Deref for Units {
type Target = [u8; 4];
fn deref(&self) -> &Self::Target {
match self {
Units::Distance(distance) => distance,
Units::Velocity(velocity) => velocity,
Units::Acceleration(acceleration) => acceleration,
}
}
}
impl IntoIterator for Units {
type IntoIter = std::array::IntoIter<u8, 4>;
type Item = u8;
fn into_iter(self) -> Self::IntoIter {
match self {
Units::Distance(bytes) => IntoIterator::into_iter(bytes),
Units::Velocity(bytes) => IntoIterator::into_iter(bytes),
Units::Acceleration(bytes) => IntoIterator::into_iter(bytes),
}
}
}
pub(crate) trait UnitConversion {
const ACCELERATION_SCALE_FACTOR: f64;
const DISTANCE_ANGLE_SCALE_FACTOR: f64;
const VELOCITY_SCALE_FACTOR: f64;
fn distance_from_f64(distance: f64) -> Units {
let bytes = Units::encode(distance, Self::DISTANCE_ANGLE_SCALE_FACTOR);
Units::Distance(bytes)
}
fn velocity_from_f64(velocity: f64) -> Units {
let bytes = Units::encode(velocity, Self::VELOCITY_SCALE_FACTOR);
Units::Distance(bytes)
}
fn acceleration_from_f64(acceleration: f64) -> Units {
let bytes = Units::encode(acceleration, Self::ACCELERATION_SCALE_FACTOR);
Units::Distance(bytes)
}
fn decode(&self, units: Units) -> f64 {
match units {
Units::Distance(d) => i32::from_le_bytes(d) as f64 / Self::DISTANCE_ANGLE_SCALE_FACTOR,
Units::Velocity(v) => i32::from_le_bytes(v) as f64 / Self::VELOCITY_SCALE_FACTOR,
Units::Acceleration(a) => {
i32::from_le_bytes(a) as f64 / Self::ACCELERATION_SCALE_FACTOR
}
}
}
}