Skip to main content

pleiades_eclipse/
error.rs

1//! Structured, fail-closed eclipse errors.
2
3use core::fmt;
4
5/// First instant of the supported window (1900-01-01 TT), Julian Day.
6pub const WINDOW_START_JD: f64 = 2_415_020.5;
7/// Last instant of the supported window, Julian Day. This is the end of the
8/// packaged backend's actual Sun/Moon coverage (2100-01-01 TT); the backend has
9/// no segments beyond it, so eclipses in the remainder of 2100 are out of range.
10pub const WINDOW_END_JD: f64 = 2_488_069.5;
11
12/// Errors returned by the eclipse engine; all variants fail closed.
13#[derive(Clone, Debug, PartialEq)]
14pub enum EclipseError {
15    /// A requested instant falls outside the 1900–2100 CE window.
16    OutOfWindow {
17        /// The out-of-window instant, as a Julian Day.
18        julian_day: f64,
19    },
20    /// The backend returned a structured error (message forwarded verbatim).
21    Backend(String),
22    /// The backend produced no ecliptic coordinates for a required body.
23    MissingCoordinates {
24        /// Human-readable label of the body that was missing (e.g. `"Sun"`).
25        body_label: &'static str,
26        /// The Julian Day at which coordinates were requested.
27        julian_day: f64,
28    },
29    /// The supplied observer location was invalid.
30    InvalidObserver {
31        /// Human-readable reason.
32        detail: String,
33    },
34    /// The supplied atmosphere had a non-finite field.
35    InvalidAtmosphere {
36        /// Human-readable reason.
37        detail: String,
38    },
39}
40
41impl fmt::Display for EclipseError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            EclipseError::OutOfWindow { julian_day } => write!(
45                f,
46                "instant JD {julian_day} is outside the supported 1900–2100 CE window \
47                 (JD {WINDOW_START_JD}..={WINDOW_END_JD})"
48            ),
49            EclipseError::Backend(message) => write!(f, "backend error: {message}"),
50            EclipseError::MissingCoordinates {
51                body_label,
52                julian_day,
53            } => write!(
54                f,
55                "backend returned no ecliptic coordinates for {body_label} at JD {julian_day}"
56            ),
57            EclipseError::InvalidObserver { detail } => write!(f, "invalid observer: {detail}"),
58            EclipseError::InvalidAtmosphere { detail } => write!(f, "invalid atmosphere: {detail}"),
59        }
60    }
61}
62
63impl std::error::Error for EclipseError {}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68
69    #[test]
70    fn out_of_window_message_names_the_julian_day() {
71        let err = EclipseError::OutOfWindow {
72            julian_day: 2_400_000.5,
73        };
74        assert!(err.to_string().contains("2400000.5"));
75        assert!(err.to_string().contains("1900"));
76    }
77
78    #[test]
79    fn window_constants_match_1900_2100() {
80        assert_eq!(WINDOW_START_JD, 2_415_020.5);
81        assert_eq!(WINDOW_END_JD, 2_488_069.5);
82    }
83}