1use std::{error::Error, fmt::Display, num::ParseIntError, str::FromStr};
2
3#[derive(Debug, Clone, Copy, PartialEq)]
5pub enum Region {
6 NorthScotland = 1,
7 SouthScotland = 2,
8 NorthWestEngland = 3,
9 NorthEastEngland = 4,
10 SouthYorkshire = 5,
11 NorthWalesMerseysideAndCheshire = 6,
12 SouthWales = 7,
13 WestMidlands = 8,
14 EastMidlands = 9,
15 EastEngland = 10,
16 SouthWestEngland = 11,
17 SouthEngland = 12,
18 London = 13,
19 SouthEastEngland = 14,
20 England = 15,
21 Scotland = 16,
22 Wales = 17,
23}
24
25impl FromStr for Region {
26 type Err = RegionError;
27
28 fn from_str(s: &str) -> Result<Self, Self::Err> {
29 let region_id = s.parse::<u8>()?;
30
31 let region = match region_id {
32 1 => Self::NorthScotland,
33 2 => Self::SouthScotland,
34 3 => Self::NorthWestEngland,
35 4 => Self::NorthEastEngland,
36 5 => Self::SouthYorkshire,
37 6 => Self::NorthWalesMerseysideAndCheshire,
38 7 => Self::SouthWales,
39 8 => Self::WestMidlands,
40 9 => Self::EastMidlands,
41 10 => Self::EastEngland,
42 11 => Self::SouthWestEngland,
43 12 => Self::SouthEngland,
44 13 => Self::London,
45 14 => Self::SouthEastEngland,
46 15 => Self::England,
47 16 => Self::Scotland,
48 17 => Self::Wales,
49 _ => return Err(RegionError::OutsideRange),
50 };
51
52 Ok(region)
53 }
54}
55
56impl Display for Region {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 let s = match self {
59 Region::NorthScotland => "North Scotland",
60 Region::SouthScotland => "South Scotland",
61 Region::NorthWestEngland => "North West England",
62 Region::NorthEastEngland => "North East England",
63 Region::SouthYorkshire => "South Yorkshire",
64 Region::NorthWalesMerseysideAndCheshire => "North Wales, Merseyside and Cheshire",
65 Region::SouthWales => "South Wales",
66 Region::WestMidlands => "West Midlands",
67 Region::EastMidlands => "East Midlands",
68 Region::EastEngland => "East England",
69 Region::SouthWestEngland => "South West England",
70 Region::SouthEngland => "South England",
71 Region::London => "London",
72 Region::SouthEastEngland => "South East England",
73 Region::England => "England",
74 Region::Scotland => "Scotland",
75 Region::Wales => "Wales",
76 };
77 write!(f, "{}", s)
78 }
79}
80
81#[derive(Debug, PartialEq)]
82pub enum RegionError {
83 ParseError,
84 OutsideRange,
85}
86
87impl Error for RegionError {}
88
89impl Display for RegionError {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 let message = match self {
92 RegionError::ParseError => "Failed to parse region id",
93 RegionError::OutsideRange => {
94 "Region id outside allowed range. Must be between 1 and 17 (inclusive)"
95 }
96 };
97 write!(f, "{}", message)
98 }
99}
100
101impl From<ParseIntError> for RegionError {
106 fn from(_: ParseIntError) -> Self {
107 RegionError::ParseError
108 }
109}
110
111#[cfg(test)]
112mod tests {
113 use super::{Region, RegionError};
114
115 #[test]
116 fn ids_match() {
117 assert_eq!(1_u8, Region::NorthScotland as u8);
118 assert_eq!(2_u8, Region::SouthScotland as u8);
119 assert_eq!(3_u8, Region::NorthWestEngland as u8);
120 assert_eq!(4_u8, Region::NorthEastEngland as u8);
121 assert_eq!(5_u8, Region::SouthYorkshire as u8);
122 assert_eq!(6_u8, Region::NorthWalesMerseysideAndCheshire as u8);
123 assert_eq!(7_u8, Region::SouthWales as u8);
124 assert_eq!(8_u8, Region::WestMidlands as u8);
125 assert_eq!(9_u8, Region::EastMidlands as u8);
126 assert_eq!(10_u8, Region::EastEngland as u8);
127 assert_eq!(11_u8, Region::SouthWestEngland as u8);
128 assert_eq!(12_u8, Region::SouthEngland as u8);
129 assert_eq!(13_u8, Region::London as u8);
130 assert_eq!(14_u8, Region::SouthEastEngland as u8);
131 assert_eq!(15_u8, Region::England as u8);
132 assert_eq!(16_u8, Region::Scotland as u8);
133 assert_eq!(17_u8, Region::Wales as u8);
134 }
135
136 #[test]
137 fn from_str() {
138 assert_eq!("1".parse::<Region>(), Ok(Region::NorthScotland));
139 assert_eq!("2".parse::<Region>(), Ok(Region::SouthScotland));
140 assert_eq!("3".parse::<Region>(), Ok(Region::NorthWestEngland));
141 assert_eq!("4".parse::<Region>(), Ok(Region::NorthEastEngland));
142 assert_eq!("5".parse::<Region>(), Ok(Region::SouthYorkshire));
143 assert_eq!(
144 "6".parse::<Region>(),
145 Ok(Region::NorthWalesMerseysideAndCheshire)
146 );
147 assert_eq!("7".parse::<Region>(), Ok(Region::SouthWales));
148 assert_eq!("8".parse::<Region>(), Ok(Region::WestMidlands));
149 assert_eq!("9".parse::<Region>(), Ok(Region::EastMidlands));
150 assert_eq!("10".parse::<Region>(), Ok(Region::EastEngland));
151 assert_eq!("11".parse::<Region>(), Ok(Region::SouthWestEngland));
152 assert_eq!("12".parse::<Region>(), Ok(Region::SouthEngland));
153 assert_eq!("13".parse::<Region>(), Ok(Region::London));
154 assert_eq!("14".parse::<Region>(), Ok(Region::SouthEastEngland));
155 assert_eq!("15".parse::<Region>(), Ok(Region::England));
156 assert_eq!("16".parse::<Region>(), Ok(Region::Scotland));
157 assert_eq!("17".parse::<Region>(), Ok(Region::Wales));
158 }
159
160 #[test]
161 fn region_display() {
162 assert_eq!(Region::NorthScotland.to_string(), "North Scotland");
163 assert_eq!(Region::SouthScotland.to_string(), "South Scotland");
164 assert_eq!(Region::NorthWestEngland.to_string(), "North West England");
165 assert_eq!(Region::NorthEastEngland.to_string(), "North East England");
166 assert_eq!(Region::SouthYorkshire.to_string(), "South Yorkshire");
167 assert_eq!(
168 Region::NorthWalesMerseysideAndCheshire.to_string(),
169 "North Wales, Merseyside and Cheshire"
170 );
171 assert_eq!(Region::SouthWales.to_string(), "South Wales");
172 assert_eq!(Region::WestMidlands.to_string(), "West Midlands");
173 assert_eq!(Region::EastMidlands.to_string(), "East Midlands");
174 assert_eq!(Region::EastEngland.to_string(), "East England");
175 assert_eq!(Region::SouthWestEngland.to_string(), "South West England");
176 assert_eq!(Region::SouthEngland.to_string(), "South England");
177 assert_eq!(Region::London.to_string(), "London");
178 assert_eq!(Region::SouthEastEngland.to_string(), "South East England");
179 assert_eq!(Region::England.to_string(), "England");
180 assert_eq!(Region::Scotland.to_string(), "Scotland");
181 assert_eq!(Region::Wales.to_string(), "Wales");
182 }
183
184 #[test]
185 fn error_display() {
186 assert_eq!(
187 RegionError::ParseError.to_string(),
188 "Failed to parse region id"
189 );
190 assert_eq!(
191 RegionError::OutsideRange.to_string(),
192 "Region id outside allowed range. Must be between 1 and 17 (inclusive)"
193 );
194 }
195
196 #[test]
197 fn error_parse_int_conversion() {
198 fn foo() -> Result<(), RegionError> {
199 let _: u8 = "foo".parse()?;
201
202 Ok(())
203 }
204
205 assert_eq!(foo(), Err(RegionError::ParseError));
206 }
207}