Skip to main content

pleiades_backend/
capabilities.rs

1use core::fmt;
2
3/// Capability flags for a backend.
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Clone, Debug, PartialEq, Eq, Hash)]
6pub struct BackendCapabilities {
7    /// Whether geocentric calculations are supported.
8    pub geocentric: bool,
9    /// Whether topocentric calculations are supported.
10    pub topocentric: bool,
11    /// Whether apparent values are supported.
12    pub apparent: bool,
13    /// Whether mean values are supported.
14    pub mean: bool,
15    /// Whether the backend can serve batch requests.
16    pub batch: bool,
17    /// Whether sidereal outputs are computed natively rather than derived above the backend.
18    pub native_sidereal: bool,
19}
20
21impl Default for BackendCapabilities {
22    fn default() -> Self {
23        Self {
24            geocentric: true,
25            topocentric: false,
26            apparent: true,
27            mean: true,
28            batch: true,
29            native_sidereal: false,
30        }
31    }
32}
33
34impl BackendCapabilities {
35    /// Returns a compact one-line rendering of the declared capability flags.
36    pub fn summary_line(&self) -> String {
37        format!(
38            "geocentric={}; topocentric={}; apparent={}; mean={}; batch={}; native_sidereal={}",
39            self.geocentric,
40            self.topocentric,
41            self.apparent,
42            self.mean,
43            self.batch,
44            self.native_sidereal
45        )
46    }
47
48    /// Returns the compact capability summary after validating the flag set.
49    pub fn validated_summary_line(&self) -> Result<String, BackendCapabilitiesValidationError> {
50        self.validate()?;
51        Ok(self.summary_line())
52    }
53
54    /// Returns `Ok(())` when the capability flags describe at least one usable
55    /// position mode and one usable value mode.
56    pub fn validate(&self) -> Result<(), BackendCapabilitiesValidationError> {
57        if !self.geocentric && !self.topocentric {
58            return Err(BackendCapabilitiesValidationError::MissingPositionMode);
59        }
60
61        if !self.apparent && !self.mean {
62            return Err(BackendCapabilitiesValidationError::MissingValueMode);
63        }
64
65        Ok(())
66    }
67}
68
69/// Errors returned when the declared backend capabilities cannot describe a usable request shape.
70#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
71#[non_exhaustive]
72pub enum BackendCapabilitiesValidationError {
73    /// Neither geocentric nor topocentric position support was declared.
74    MissingPositionMode,
75    /// Neither apparent nor mean output support was declared.
76    MissingValueMode,
77}
78
79impl BackendCapabilitiesValidationError {
80    /// Returns a compact validation summary string.
81    pub fn summary_line(&self) -> &'static str {
82        match self {
83            Self::MissingPositionMode => {
84                "backend capabilities must support geocentric or topocentric positions"
85            }
86            Self::MissingValueMode => "backend capabilities must support mean or apparent output",
87        }
88    }
89}
90
91impl fmt::Display for BackendCapabilitiesValidationError {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        f.write_str(self.summary_line())
94    }
95}
96
97impl std::error::Error for BackendCapabilitiesValidationError {}
98
99impl fmt::Display for BackendCapabilities {
100    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101        f.write_str(&self.summary_line())
102    }
103}
104
105#[cfg(test)]
106#[path = "capabilities_tests.rs"]
107mod tests;