1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! The error enum and the parse-failure kinds.
use core::fmt;
/// The reasons a conversion or a parse can fail.
///
/// Every variant is reachable and has a test that reaches it.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
/// Latitude is NaN, infinite, or outside [-90, 90].
LatOutOfRange {
/// The rejected latitude.
found: f64,
},
/// Longitude is NaN or infinite.
LonOutOfRange {
/// The rejected longitude.
found: f64,
},
/// UTM zone outside 1 to 60, or 0 passed to [`UtmUps::utm`](crate::UtmUps::utm).
ZoneOutOfRange {
/// The rejected zone number.
found: u8,
},
/// Easting outside the wide transfer range for the stated grid.
EastingOutOfRange {
/// The rejected easting in metres.
found: f64,
},
/// Northing outside the wide transfer range for the stated grid.
NorthingOutOfRange {
/// The rejected northing in metres.
found: f64,
},
/// Precision outside 0 to 11.
PrecisionOutOfRange {
/// The rejected digit-pair count.
found: u8,
},
/// The coordinate is valid UTM or UPS but outside the MGRS grid coverage.
OutsideMgrsExtent {
/// The easting of the rejected coordinate in metres.
easting: f64,
/// The northing of the rejected coordinate in metres.
northing: f64,
},
/// The string is not an MGRS reference. The kind names the first rule it broke.
Parse(ParseErrorKind),
}
/// The first parse rule an invalid MGRS string broke.
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ParseErrorKind {
/// The string is empty after trimming ASCII whitespace.
Empty,
/// A zone-only reference such as "18T". Deliberately unsupported: a cell six
/// degrees wide has no useful center.
GridZoneOnly,
/// The leading digits are not a zone number in 1 to 60.
BadZoneNumber,
/// The letter after the zone is not a band letter C to X (`I` and `O` excluded).
BadBandLetter,
/// A 100 km square letter is not in the MGRS alphabets.
BadSquareLetters,
/// Square letters valid in the alphabet but not for this zone.
SquareZoneMismatch,
/// The implied northing is inconsistent with the band letter.
SquareBandMismatch,
/// The digit block has an odd number of digits.
OddDigitCount,
/// The digit block has more than 22 digits.
TooManyDigits,
/// The string contains a non-ASCII byte or internal whitespace.
NonAsciiOrWhitespace,
/// A character that is neither a letter nor a digit where digits were expected.
TrailingInput,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::LatOutOfRange { found } => {
write!(f, "latitude {found} is not a finite value in [-90, 90]")
}
Error::LonOutOfRange { found } => {
write!(f, "longitude {found} is not finite")
}
Error::ZoneOutOfRange { found } => {
write!(f, "zone {found} is outside 1 to 60")
}
Error::EastingOutOfRange { found } => {
write!(f, "easting {found} m is outside the transfer range")
}
Error::NorthingOutOfRange { found } => {
write!(f, "northing {found} m is outside the transfer range")
}
Error::PrecisionOutOfRange { found } => {
write!(f, "precision {found} is outside 0 to 11")
}
Error::OutsideMgrsExtent { easting, northing } => {
write!(
f,
"easting {easting} m, northing {northing} m is outside the MGRS grid coverage"
)
}
Error::Parse(kind) => write!(f, "invalid MGRS string: {kind}"),
}
}
}
impl fmt::Display for ParseErrorKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msg = match self {
ParseErrorKind::Empty => "empty string",
ParseErrorKind::GridZoneOnly => "grid-zone-only reference is not supported",
ParseErrorKind::BadZoneNumber => "zone number is not in 1 to 60",
ParseErrorKind::BadBandLetter => "band letter is not C to X (I and O excluded)",
ParseErrorKind::BadSquareLetters => "100 km square letters are not in the alphabets",
ParseErrorKind::SquareZoneMismatch => "square letters do not belong to this zone",
ParseErrorKind::SquareBandMismatch => {
"square letters imply a northing outside this band"
}
ParseErrorKind::OddDigitCount => "digit block has an odd number of digits",
ParseErrorKind::TooManyDigits => "digit block has more than 22 digits",
ParseErrorKind::NonAsciiOrWhitespace => "non-ASCII byte or internal whitespace",
ParseErrorKind::TrailingInput => "unexpected character after the square letters",
};
f.write_str(msg)
}
}
impl std::error::Error for Error {}