Skip to main content

elevator_core/components/
position.rs

1//! Position and velocity components along the shaft axis.
2
3use serde::{Deserialize, Serialize};
4use std::fmt;
5
6/// Position along the shaft axis.
7///
8/// # Display
9///
10/// Formats as a bare numeric value to two decimals; hosts suffix
11/// their own unit label (the engine doesn't pin a distance unit).
12///
13/// ```
14/// # use elevator_core::components::Position;
15/// let pos = Position::from(4.5);
16/// assert_eq!(format!("{pos}"), "4.50");
17/// ```
18#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
19pub struct Position {
20    /// Absolute position value.
21    pub(crate) value: f64,
22}
23
24impl Position {
25    /// Zero position (shaft origin).
26    pub const ZERO: Self = Self { value: 0.0 };
27
28    /// Absolute position value.
29    #[must_use]
30    pub const fn value(&self) -> f64 {
31        self.value
32    }
33
34    /// Absolute distance between two positions.
35    #[must_use]
36    pub fn distance_to(self, other: Self) -> f64 {
37        (self.value - other.value).abs()
38    }
39}
40
41impl fmt::Display for Position {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        write!(f, "{:.2}", self.value)
44    }
45}
46
47impl From<f64> for Position {
48    fn from(value: f64) -> Self {
49        debug_assert!(
50            value.is_finite(),
51            "Position value must be finite, got {value}"
52        );
53        Self { value }
54    }
55}
56
57/// Velocity along the shaft axis (signed: +up, -down).
58///
59/// # Display
60///
61/// Formats as a bare numeric value to two decimals; hosts suffix
62/// their own unit label (the engine doesn't pin a distance unit).
63///
64/// ```
65/// # use elevator_core::components::Velocity;
66/// let vel = Velocity::from(1.2);
67/// assert_eq!(format!("{vel}"), "1.20");
68/// let stopped = Velocity::from(0.0);
69/// assert_eq!(format!("{stopped}"), "0.00");
70/// ```
71#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
72pub struct Velocity {
73    /// Signed velocity value.
74    pub(crate) value: f64,
75}
76
77impl Velocity {
78    /// Zero velocity (stationary).
79    pub const ZERO: Self = Self { value: 0.0 };
80
81    /// Signed velocity value.
82    #[must_use]
83    pub const fn value(&self) -> f64 {
84        self.value
85    }
86
87    /// Absolute speed (magnitude of velocity).
88    #[must_use]
89    pub const fn speed(self) -> f64 {
90        self.value.abs()
91    }
92}
93
94impl fmt::Display for Velocity {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        write!(f, "{:.2}", self.value)
97    }
98}
99
100impl From<f64> for Velocity {
101    fn from(value: f64) -> Self {
102        debug_assert!(
103            value.is_finite(),
104            "Velocity value must be finite, got {value}"
105        );
106        Self { value }
107    }
108}