1#[derive(Debug, Clone, thiserror::Error)]
6#[non_exhaustive]
7pub enum SphereQlError {
8 #[error("invalid radius {0}: must be >= 0")]
9 InvalidRadius(f64),
10 #[error("invalid theta {0}: must be in [0, 2π)")]
11 InvalidTheta(f64),
12 #[error("invalid phi {0}: must be in [0, π]")]
13 InvalidPhi(f64),
14 #[error("invalid latitude {0}: must be in [-90, 90]")]
15 InvalidLatitude(f64),
16 #[error("invalid longitude {0}: must be in [-180, 180]")]
17 InvalidLongitude(f64),
18 #[error("invalid altitude {0}: must be >= 0")]
19 InvalidAltitude(f64),
20 #[error("invalid shell bounds: inner {inner} must be < outer {outer}")]
21 InvalidShellBounds { inner: f64, outer: f64 },
22 #[error("invalid band bounds: phi_min {phi_min} must be < phi_max {phi_max}")]
23 InvalidBandBounds { phi_min: f64, phi_max: f64 },
24 #[error("invalid cone: half_angle {0} must be in (0, π]")]
25 InvalidConeAngle(f64),
26 #[error("invalid cap: half_angle {0} must be in (0, π]")]
27 InvalidCapAngle(f64),
28 #[error(
29 "invalid wedge bounds: theta_min {theta_min} and theta_max {theta_max} must be in [0, 2π)"
30 )]
31 InvalidWedgeBounds { theta_min: f64, theta_max: f64 },
32 #[error("zero vector cannot be normalized")]
33 ZeroVector,
34 #[error("vector length mismatch: expected {expected}, got {actual}")]
35 DimensionMismatch { expected: usize, actual: usize },
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41
42 #[test]
43 fn error_messages_are_human_readable() {
44 assert!(
45 SphereQlError::InvalidRadius(-1.0)
46 .to_string()
47 .contains("-1")
48 );
49 assert!(
50 SphereQlError::DimensionMismatch {
51 expected: 3,
52 actual: 2
53 }
54 .to_string()
55 .contains("3")
56 );
57 assert!(
58 SphereQlError::InvalidShellBounds {
59 inner: 5.0,
60 outer: 1.0
61 }
62 .to_string()
63 .contains("5")
64 );
65 }
66
67 #[test]
68 fn zero_vector_error_formats() {
69 let msg = SphereQlError::ZeroVector.to_string();
70 assert!(!msg.is_empty());
71 }
72}