Skip to main content

celestial_coords/
errors.rs

1use celestial_core::AstroError;
2use thiserror::Error;
3
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7pub type CoordResult<T> = Result<T, CoordError>;
8
9#[derive(Debug, Error)]
10#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11pub enum CoordError {
12    #[error("Invalid coordinate: {message}")]
13    InvalidCoordinate { message: String },
14
15    #[error("Epoch conversion failed: {source}")]
16    EpochError {
17        #[from]
18        source: celestial_time::TimeError,
19    },
20
21    #[error("Core astronomical calculation failed: {message}")]
22    CoreError { message: String },
23
24    #[error("Invalid distance: {message}")]
25    InvalidDistance { message: String },
26
27    #[error("Observer location required for topocentric coordinates")]
28    MissingObserver,
29
30    #[error("Coordinate operation not supported: {message}")]
31    UnsupportedOperation { message: String },
32
33    #[error("Data parsing failed: {message}")]
34    ParsingError { message: String },
35
36    #[error("Data not available: {message}")]
37    DataUnavailable { message: String },
38
39    /// Errors from external libraries (filesystem, network, etc.)
40    ///
41    /// This is deliberately unstructured (just a string) since external error types vary widely.
42    /// If richer context is needed for specific external errors, add dedicated variants.
43    #[error("External error: {message}")]
44    ExternalError { message: String },
45}
46
47impl CoordError {
48    pub fn invalid_coordinate(message: impl Into<String>) -> Self {
49        Self::InvalidCoordinate {
50            message: message.into(),
51        }
52    }
53
54    pub fn invalid_distance(message: impl Into<String>) -> Self {
55        Self::InvalidDistance {
56            message: message.into(),
57        }
58    }
59
60    pub fn unsupported_operation(message: impl Into<String>) -> Self {
61        Self::UnsupportedOperation {
62            message: message.into(),
63        }
64    }
65
66    pub fn parsing_error(message: impl Into<String>) -> Self {
67        Self::ParsingError {
68            message: message.into(),
69        }
70    }
71
72    pub fn data_unavailable(message: impl Into<String>) -> Self {
73        Self::DataUnavailable {
74            message: message.into(),
75        }
76    }
77
78    pub fn external_library(operation: &str, error: &str) -> Self {
79        Self::ExternalError {
80            message: format!("{}: {}", operation, error),
81        }
82    }
83
84    pub fn from_core(error: AstroError) -> Self {
85        Self::CoreError {
86            message: error.to_string(),
87        }
88    }
89}
90
91impl From<AstroError> for CoordError {
92    fn from(error: AstroError) -> Self {
93        Self::from_core(error)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_unsupported_operation() {
103        let err = CoordError::unsupported_operation("test op");
104        assert!(err.to_string().contains("test op"));
105    }
106
107    #[test]
108    fn test_parsing_error() {
109        let err = CoordError::parsing_error("parse fail");
110        assert!(err.to_string().contains("parse fail"));
111    }
112}