Skip to main content

rapidgeo_polyline/
error.rs

1//! Error types for polyline operations.
2
3use std::fmt;
4
5/// Errors that can occur during polyline encoding or decoding operations.
6///
7/// These errors provide detailed information about what went wrong during
8/// polyline processing, including specific locations for parsing errors
9/// and descriptive messages for coordinate validation failures.
10#[derive(Debug, Clone, PartialEq)]
11pub enum PolylineError {
12    /// Invalid character found in polyline string.
13    ///
14    /// Polyline strings must contain only ASCII characters in the range 63-126 ('?' to '~').
15    /// This error includes the invalid character and its position in the string.
16    InvalidCharacter { character: char, position: usize },
17
18    /// Truncated or malformed polyline data.
19    ///
20    /// Occurs when the polyline string ends unexpectedly, such as having a latitude
21    /// delta without a corresponding longitude delta, or when the variable-length
22    /// encoding is incomplete.
23    TruncatedData,
24
25    /// Coordinate value overflow during encoding or decoding.
26    ///
27    /// Happens when coordinate calculations exceed the range of 64-bit integers,
28    /// typically with very high precision values or extreme coordinate differences.
29    CoordinateOverflow,
30
31    /// Invalid precision value.
32    ///
33    /// Precision must be between 1 and 11 inclusive. Higher precision values
34    /// provide more accuracy but may cause overflow with large coordinate values.
35    InvalidPrecision(u8),
36
37    /// Empty input where coordinates were expected.
38    ///
39    /// Currently unused - empty inputs are handled gracefully by returning
40    /// empty results rather than errors.
41    EmptyInput,
42
43    /// Invalid coordinate value.
44    ///
45    /// Occurs when coordinates are NaN, infinite, or outside reasonable
46    /// geographic bounds (±180° longitude, ±90° latitude).
47    InvalidCoordinate(String),
48}
49
50impl fmt::Display for PolylineError {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        match self {
53            PolylineError::InvalidCharacter {
54                character,
55                position,
56            } => {
57                write!(
58                    f,
59                    "Invalid character '{}' at position {}",
60                    character, position
61                )
62            }
63            PolylineError::TruncatedData => {
64                write!(f, "Polyline data is truncated or malformed")
65            }
66            PolylineError::CoordinateOverflow => {
67                write!(f, "Coordinate value overflow during encoding or decoding")
68            }
69            PolylineError::InvalidPrecision(precision) => {
70                write!(
71                    f,
72                    "Invalid precision {}, must be between 1 and 11",
73                    precision
74                )
75            }
76            PolylineError::EmptyInput => {
77                write!(f, "Empty input provided")
78            }
79            PolylineError::InvalidCoordinate(message) => {
80                write!(f, "Invalid coordinate: {}", message)
81            }
82        }
83    }
84}
85
86impl std::error::Error for PolylineError {}
87
88/// Result type for polyline operations.
89///
90/// This is a convenience type alias for `Result<T, PolylineError>` used
91/// throughout the crate. All public functions return this type to provide
92/// consistent error handling.
93///
94/// # Example
95///
96/// ```rust
97/// use rapidgeo_polyline::{encode, PolylineResult};
98/// use rapidgeo_distance::LngLat;
99///
100/// fn encode_route(coords: &[LngLat]) -> PolylineResult<String> {
101///     encode(coords, 5)
102/// }
103/// ```
104pub type PolylineResult<T> = Result<T, PolylineError>;
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn test_invalid_character_display() {
112        let err = PolylineError::InvalidCharacter {
113            character: '!',
114            position: 5,
115        };
116        assert_eq!(err.to_string(), "Invalid character '!' at position 5");
117    }
118
119    #[test]
120    fn test_truncated_data_display() {
121        let err = PolylineError::TruncatedData;
122        assert_eq!(err.to_string(), "Polyline data is truncated or malformed");
123    }
124
125    #[test]
126    fn test_coordinate_overflow_display() {
127        let err = PolylineError::CoordinateOverflow;
128        assert_eq!(
129            err.to_string(),
130            "Coordinate value overflow during encoding or decoding"
131        );
132    }
133
134    #[test]
135    fn test_invalid_precision_display() {
136        let err = PolylineError::InvalidPrecision(15);
137        assert_eq!(
138            err.to_string(),
139            "Invalid precision 15, must be between 1 and 11"
140        );
141    }
142
143    #[test]
144    fn test_empty_input_display() {
145        let err = PolylineError::EmptyInput;
146        assert_eq!(err.to_string(), "Empty input provided");
147    }
148
149    #[test]
150    fn test_invalid_coordinate_display() {
151        let err = PolylineError::InvalidCoordinate("NaN value".to_string());
152        assert_eq!(err.to_string(), "Invalid coordinate: NaN value");
153    }
154
155    #[test]
156    fn test_error_trait_implementation() {
157        let err = PolylineError::TruncatedData;
158        let _: &dyn std::error::Error = &err;
159    }
160}