1#![doc = include_str!("../README.md")]
4#![no_std]
5
6#[cfg(feature = "serde")]
7mod serde_;
8
9use core::{
10 fmt::{Display, Formatter, Result as FmtResult},
11 str::FromStr,
12};
13
14iso3166_macros::generate_m49!();
15
16impl Numeric {
17 pub const fn from_str_slice(s: &str) -> Result<Self, Error> {
29 if !s.is_ascii() {
30 return Err(Error::InvalidCharset);
31 }
32
33 let s = s.trim_ascii();
34
35 let s_bytes = s.as_bytes();
36 let s_len = s_bytes.len();
37 if s_len != 2 && s_len != 3 {
38 return Err(Error::InvalidLength);
39 }
40
41 let mut src_bytes = [b' '; 3];
42
43 src_bytes[0] = s_bytes[0];
44 src_bytes[1] = s_bytes[1];
45 if s_len == 3 {
46 src_bytes[2] = s_bytes[2];
47 }
48 src_bytes.make_ascii_uppercase();
49
50 #[allow(unsafe_code)]
51 let src = unsafe { str::from_utf8_unchecked(&src_bytes) };
53
54 if s_len == 2 {
55 Self::from_alpha2(src.trim_ascii())
56 } else {
57 Self::from_alpha3(src)
58 }
59 }
60}
61
62impl Display for Numeric {
63 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
64 write!(f, "{}", self.as_u16())
65 }
66}
67
68impl From<Numeric> for u16 {
69 fn from(value: Numeric) -> Self {
70 value.as_u16()
71 }
72}
73
74impl TryFrom<u16> for Numeric {
75 type Error = Error;
76
77 fn try_from(value: u16) -> Result<Self, Self::Error> {
78 Self::from_u16(value)
79 }
80}
81
82impl TryFrom<&str> for Numeric {
83 type Error = Error;
84
85 fn try_from(value: &str) -> Result<Self, Self::Error> {
86 <Self as FromStr>::from_str(value)
87 }
88}
89
90impl FromStr for Numeric {
91 type Err = Error;
92
93 fn from_str(s: &str) -> Result<Self, Self::Err> {
94 Self::from_str_slice(s)
95 }
96}
97
98impl From<Alpha2> for Numeric {
99 fn from(value: Alpha2) -> Self {
100 value.0
101 }
102}
103
104impl From<Alpha3> for Numeric {
105 fn from(value: Alpha3) -> Self {
106 value.0
107 }
108}
109
110impl PartialEq<Alpha2> for Numeric {
111 fn eq(&self, other: &Alpha2) -> bool {
112 self == &other.0
113 }
114}
115
116impl PartialEq<Alpha3> for Numeric {
117 fn eq(&self, other: &Alpha3) -> bool {
118 self == &other.0
119 }
120}
121
122#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
126pub struct Alpha2(Numeric);
127
128impl Alpha2 {
129 pub const fn from_alpha2(s: &str) -> Result<Self, Error> {
137 match Numeric::from_alpha2(s) {
138 Ok(value) => Ok(Self(value)),
139 Err(err) => Err(err),
140 }
141 }
142
143 pub const fn from_u16(value: u16) -> Result<Self, Error> {
149 match Numeric::from_u16(value) {
150 Ok(value) => Ok(Self(value)),
151 Err(err) => Err(err),
152 }
153 }
154
155 #[must_use]
157 pub const fn from_alpha3(value: Alpha3) -> Self {
158 Self(value.0)
159 }
160
161 #[must_use]
163 pub const fn from_numeric(value: Numeric) -> Self {
164 Self(value)
165 }
166
167 #[must_use]
169 pub const fn as_str(&self) -> &'static str {
170 self.0.as_alpha2_str()
171 }
172}
173
174impl Display for Alpha2 {
175 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
176 f.write_str(self.as_str())
177 }
178}
179
180impl FromStr for Alpha2 {
181 type Err = Error;
182
183 fn from_str(value: &str) -> Result<Self, Self::Err> {
184 Self::from_alpha2(value)
185 }
186}
187
188impl TryFrom<&str> for Alpha2 {
189 type Error = Error;
190
191 fn try_from(value: &str) -> Result<Self, Self::Error> {
192 Self::from_alpha2(value)
193 }
194}
195
196impl TryFrom<u16> for Alpha2 {
197 type Error = Error;
198
199 fn try_from(value: u16) -> Result<Self, Self::Error> {
200 Self::from_u16(value)
201 }
202}
203
204impl From<Alpha3> for Alpha2 {
205 fn from(value: Alpha3) -> Self {
206 Self::from_alpha3(value)
207 }
208}
209
210impl From<Numeric> for Alpha2 {
211 fn from(value: Numeric) -> Self {
212 Self::from_numeric(value)
213 }
214}
215
216impl PartialEq<Alpha3> for Alpha2 {
217 fn eq(&self, other: &Alpha3) -> bool {
218 self.0 == other.0
219 }
220}
221
222impl PartialEq<Numeric> for Alpha2 {
223 fn eq(&self, other: &Numeric) -> bool {
224 self.0 == *other
225 }
226}
227
228#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
243pub struct Alpha3(Numeric);
244
245impl Alpha3 {
246 pub const fn from_alpha3(s: &str) -> Result<Self, Error> {
257 match Numeric::from_alpha3(s) {
258 Ok(value) => Ok(Self(value)),
259 Err(err) => Err(err),
260 }
261 }
262
263 pub const fn from_u16(value: u16) -> Result<Self, Error> {
269 match Numeric::from_u16(value) {
270 Ok(value) => Ok(Self(value)),
271 Err(err) => Err(err),
272 }
273 }
274
275 #[must_use]
277 pub const fn from_alpha2(value: Alpha2) -> Self {
278 Self(value.0)
279 }
280
281 #[must_use]
283 pub const fn from_numeric(value: Numeric) -> Self {
284 Self(value)
285 }
286
287 #[must_use]
289 pub const fn as_str(&self) -> &'static str {
290 self.0.as_alpha3_str()
291 }
292}
293
294impl Display for Alpha3 {
295 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
296 f.write_str(self.as_str())
297 }
298}
299
300impl FromStr for Alpha3 {
301 type Err = Error;
302
303 fn from_str(value: &str) -> Result<Self, Self::Err> {
304 Self::from_alpha3(value)
305 }
306}
307
308impl TryFrom<&str> for Alpha3 {
309 type Error = Error;
310
311 fn try_from(value: &str) -> Result<Self, Self::Error> {
312 Self::from_alpha3(value)
313 }
314}
315
316impl TryFrom<u16> for Alpha3 {
317 type Error = Error;
318
319 fn try_from(value: u16) -> Result<Self, Self::Error> {
320 Self::from_u16(value)
321 }
322}
323
324impl From<Alpha2> for Alpha3 {
325 fn from(value: Alpha2) -> Self {
326 Self::from_alpha2(value)
327 }
328}
329
330impl From<Numeric> for Alpha3 {
331 fn from(value: Numeric) -> Self {
332 Self::from_numeric(value)
333 }
334}
335
336impl PartialEq<Alpha2> for Alpha3 {
337 fn eq(&self, other: &Alpha2) -> bool {
338 self.0 == other.0
339 }
340}
341
342impl PartialEq<Numeric> for Alpha3 {
343 fn eq(&self, other: &Numeric) -> bool {
344 self.0 == *other
345 }
346}
347
348#[cfg(test)]
349mod test {
350 extern crate std;
351
352 use super::*;
353 use std::string::ToString;
354
355 const USA_EXPECTED2: &str = "US";
356 const USA_EXPECTED3: &str = "USA";
357 const USA_EXPECTED_U16: u16 = 840;
358
359 #[test]
360 fn numeric_display() {
361 let src = Numeric::UnitedStatesOfAmerica;
362
363 assert_eq!("840", src.to_string());
364 }
365
366 #[test]
367 fn numeric_u16_roundtrip() {
368 let actual = Numeric::try_from(USA_EXPECTED_U16).expect("valid u16");
369 assert_eq!(USA_EXPECTED_U16, u16::from(actual));
370 }
371
372 #[yare::parameterized(
373 pass = {USA_EXPECTED_U16, Ok(Numeric::UnitedStatesOfAmerica)},
374 unknown = {u16::MAX, Err(Error::UnknownCode)},
375 unknown2 = {123, Err(Error::UnknownCode)},
376 )]
377 fn numeric_from_u16(input: u16, expected: Result<Numeric, Error>) {
378 let actual = Numeric::try_from(input);
379 assert_eq!(expected, actual);
380 }
381
382 #[yare::parameterized(
383 pass = {USA_EXPECTED2, Ok(Numeric::UnitedStatesOfAmerica)},
384 trim_both = {" US ", Err(Error::InvalidLength)},
385 unknown = {"XX", Err(Error::UnknownString)},
386 )]
387 fn numeric_from_alpha2(input: &str, expected: Result<Numeric, Error>) {
388 let actual = Numeric::from_alpha2(input);
389 assert_eq!(expected, actual);
390 }
391
392 #[yare::parameterized(
393 pass = {USA_EXPECTED3, Ok(Numeric::UnitedStatesOfAmerica)},
394 trim_both = {" USA ", Err(Error::InvalidLength)},
395 unknown = {"XXX", Err(Error::UnknownString)},
396 )]
397 fn numeric_from_alpha3(input: &str, expected: Result<Numeric, Error>) {
398 let actual = Numeric::from_alpha3(input);
399 assert_eq!(expected, actual);
400 }
401
402 #[yare::parameterized(
405 pass = {USA_EXPECTED3, Ok(Numeric::UnitedStatesOfAmerica)},
406 trim_both2 = {" US ", Ok(Numeric::UnitedStatesOfAmerica)},
407 trim_start2 = {" US", Ok(Numeric::UnitedStatesOfAmerica)},
408 trim_end2 = {"US ", Ok(Numeric::UnitedStatesOfAmerica)},
409 trim_both3 = {" USA ", Ok(Numeric::UnitedStatesOfAmerica)},
410 trim_start3 = {" USA", Ok(Numeric::UnitedStatesOfAmerica)},
411 trim_end3 = {"USA ", Ok(Numeric::UnitedStatesOfAmerica)},
412 unknown = {"XXX", Err(Error::UnknownString)},
413 poop = {"💩💩💩", Err(Error::InvalidCharset)},
414 length = {"XXXX", Err(Error::InvalidLength)},
415 )]
416 fn numeric_try_from_str(input: &str, expected: Result<Numeric, Error>) {
417 let actual = Numeric::try_from(input);
418 assert_eq!(expected, actual);
419 }
420
421 #[yare::parameterized(
422 pass = {USA_EXPECTED2, Ok(Alpha2::from_numeric(Numeric::UnitedStatesOfAmerica))},
423 )]
424 fn alpha2_from_str(input: &str, expected: Result<Alpha2, Error>) {
425 let actual = Alpha2::from_str(input);
426 assert_eq!(expected, actual);
427 }
428
429 #[yare::parameterized(
430 pass = {USA_EXPECTED3, Ok(Alpha3::from_numeric(Numeric::UnitedStatesOfAmerica))},
431 )]
432 fn alpha3_from_str(input: &str, expected: Result<Alpha3, Error>) {
433 let actual = Alpha3::from_str(input);
434 assert_eq!(expected, actual);
435 }
436}