1extern crate serde;
2#[macro_use]
3extern crate serde_derive;
4
5use std::fmt;
6use std::str;
7use std::str::FromStr;
8
9macro_rules! gen_as {
10 () => {
11 pub fn as_str(&self) -> &str {
12 str::from_utf8(&self.0).unwrap()
13 }
14
15 pub fn as_bytes(&self) -> &[u8] {
16 &self.0
17 }
18 }
19}
20
21macro_rules! gen_display_debug {
22 ($t: ty) => {
23 impl fmt::Display for $t {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 write!(f, "{}", self.as_str())
26 }
27 }
28
29 impl fmt::Debug for $t {
30 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31 write!(f, "{}", self.as_str())
32 }
33 }
34 }
35}
36
37#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
39pub struct AircraftCode([u8; 3]);
40
41gen_display_debug!(AircraftCode);
42
43impl AircraftCode {
44 gen_as!();
45
46 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
48 let mut mine = [0; 3];
49
50 mine.copy_from_slice(bytes);
51 AircraftCode(mine)
52 }
53}
54
55#[derive(Debug)]
56pub enum AircraftCodeParseError {
57 InvalidLength(usize),
58 InvalidCharacter(char)
59}
60
61impl std::fmt::Display for AircraftCodeParseError {
62 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63 match *self {
64 AircraftCodeParseError::InvalidLength(len) => {
65 write!(f, "invalid length: {}, expected 3", len)
66 },
67 AircraftCodeParseError::InvalidCharacter(c) => {
68 write!(f, "invalid character: {}, expected A-Z0-9", c)
69 }
70 }
71 }
72}
73
74impl std::error::Error for AircraftCodeParseError {
75 fn description(&self) -> &str {
76 "aircraft code parsing error"
77 }
78}
79
80impl FromStr for AircraftCode {
81 type Err = AircraftCodeParseError;
82
83 fn from_str(value: &str) -> Result<Self, Self::Err> {
84 if value.len() != 3 {
85 return Err(AircraftCodeParseError::InvalidLength(value.len()));
86 }
87
88 for c in value.chars() {
89 if c.is_ascii_uppercase() || c.is_ascii_digit() {
90 continue;
91 } else {
92 return Err(AircraftCodeParseError::InvalidCharacter(c));
93 }
94 }
95 let mut bytes = [0; 3];
96 bytes.copy_from_slice(value.as_bytes());
97 Ok(AircraftCode(bytes))
98 }
99}
100
101#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
111pub struct AirlineCode([u8; 2]);
112
113gen_display_debug!(AirlineCode);
114
115impl AirlineCode {
116 gen_as!();
117
118
119 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
121 let mut mine = [0; 2];
122
123 mine.copy_from_slice(bytes);
124 AirlineCode(mine)
125 }
126}
127
128#[derive(Debug)]
129pub enum AirlineCodeParseError {
130 InvalidLength(usize),
131 InvalidCharacter(char)
132}
133
134impl std::fmt::Display for AirlineCodeParseError {
135 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136 match *self {
137 AirlineCodeParseError::InvalidLength(len) => {
138 write!(f, "invalid length: {}, expected 2", len)
139 },
140 AirlineCodeParseError::InvalidCharacter(c) => {
141 write!(f, "invalid character: {}, expected A-Z0-9", c)
142 }
143 }
144 }
145}
146
147impl std::error::Error for AirlineCodeParseError {
148 fn description(&self) -> &str {
149 "airline code parsing error"
150 }
151}
152
153impl FromStr for AirlineCode {
154 type Err = AirlineCodeParseError;
155
156 fn from_str(value: &str) -> Result<Self, Self::Err> {
157 if value.len() != 2 {
158 return Err(AirlineCodeParseError::InvalidLength(value.len()));
159 }
160
161 for c in value.chars() {
162 if c.is_ascii_uppercase() || c.is_ascii_digit() {
163 continue;
164 } else {
165 return Err(AirlineCodeParseError::InvalidCharacter(c))
166 }
167 }
168 let mut bytes = [0; 2];
169 bytes.copy_from_slice(value.as_bytes());
170 Ok(AirlineCode(bytes))
171 }
172}
173
174#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
176pub struct AirportCode([u8; 3]);
177
178gen_display_debug!(AirportCode);
179
180impl AirportCode {
181 gen_as!();
182
183
184 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
186 let mut mine = [0; 3];
187
188 mine.copy_from_slice(bytes);
189 AirportCode(mine)
190 }
191}
192
193#[derive(Debug)]
194pub enum AirportCodeParseError {
195 InvalidLength(usize),
196 InvalidCharacter(char)
197}
198
199impl std::fmt::Display for AirportCodeParseError {
200 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
201 match *self {
202 AirportCodeParseError::InvalidLength(len) => {
203 write!(f, "invalid length: {}, expected 3", len)
204 },
205 AirportCodeParseError::InvalidCharacter(c) => {
206 write!(f, "invalid character: {}, expected A-Z0-9", c)
207 }
208 }
209 }
210}
211
212impl std::error::Error for AirportCodeParseError {
213 fn description(&self) -> &str {
214 "airport code parsing error"
215 }
216}
217
218impl FromStr for AirportCode {
219 type Err = AirportCodeParseError;
220
221 fn from_str(value: &str) -> Result<Self, Self::Err> {
222 if value.len() != 3 {
223 return Err(AirportCodeParseError::InvalidLength(value.len()));
224 }
225 for c in value.chars() {
226 if c.is_ascii_uppercase() {
227 continue;
228 } else {
229 return Err(AirportCodeParseError::InvalidCharacter(c));
230 }
231 }
232 let mut bytes = [0; 3];
233 bytes.copy_from_slice(value.as_bytes());
234 Ok(AirportCode(bytes))
235 }
236}
237
238#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
240pub struct CityCode([u8; 3]);
241
242gen_display_debug!(CityCode);
243
244impl CityCode {
245 gen_as!();
246
247 pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
249 let mut mine = [0; 3];
250
251 mine.copy_from_slice(bytes);
252 CityCode(mine)
253 }
254}
255
256#[derive(Debug)]
257pub enum CityCodeParseError {
258 InvalidLength(usize),
259 InvalidCharacter(char)
260}
261
262impl std::fmt::Display for CityCodeParseError {
263 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264 match *self {
265 CityCodeParseError::InvalidLength(len) => {
266 write!(f, "invalid length: {}, expected 3", len)
267 },
268 CityCodeParseError::InvalidCharacter(c) => {
269 write!(f, "invalid character: {}, expected A-Z0-9", c)
270 }
271 }
272 }
273}
274
275impl std::error::Error for CityCodeParseError {
276 fn description(&self) -> &str {
277 "airport code parsing error"
278 }
279}
280
281impl FromStr for CityCode {
282 type Err = CityCodeParseError;
283
284 fn from_str(value: &str) -> Result<Self, Self::Err> {
285 if value.len() != 3 {
286 return Err(CityCodeParseError::InvalidLength(value.len()));
287 }
288 for c in value.chars() {
289 if c.is_ascii_uppercase() {
290 continue;
291 } else {
292 return Err(CityCodeParseError::InvalidCharacter(c));
293 }
294 }
295 let mut bytes = [0; 3];
296 bytes.copy_from_slice(value.as_bytes());
297 Ok(CityCode(bytes))
298 }
299}
300
301#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
303pub struct FlightNumber(u16);
304
305impl FlightNumber {
306 pub fn to_u16(&self) -> u16 {
307 self.0
308 }
309
310 pub fn from_u16(num: u16) -> Result<Self, FlightNumberParseError> {
311 if num >= 1 && num <= 9999 {
312 return Ok(FlightNumber(num))
313 }
314 Err(FlightNumberParseError::InvalidNumber)
315 }
316}
317
318impl fmt::Display for FlightNumber {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 write!(f, "{:04}", self.0)
321 }
322}
323
324#[derive(Debug)]
325pub enum FlightNumberParseError {
326 NotANumber,
327 InvalidNumber,
328}
329
330impl std::fmt::Display for FlightNumberParseError {
331 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
332 match *self {
333 FlightNumberParseError::NotANumber => {
334 write!(f, "not a number")
335 },
336 FlightNumberParseError::InvalidNumber => {
337 write!(f, "invalid number, expect 0001 to 9999")
338 }
339 }
340 }
341}
342
343impl std::error::Error for FlightNumberParseError {
344 fn description(&self) -> &str {
345 "airport code parsing error"
346 }
347}
348
349impl FromStr for FlightNumber {
350 type Err = FlightNumberParseError;
351
352 fn from_str(value: &str) -> Result<Self, Self::Err> {
353 let num = value.parse()
354 .map_err(|_| FlightNumberParseError::NotANumber)?;
355 Self::from_u16(num)
356 }
357}