extern crate serde;
#[macro_use]
extern crate serde_derive;
use std::fmt;
use std::str;
use std::str::FromStr;
macro_rules! gen_as {
() => {
pub fn as_str(&self) -> &str {
str::from_utf8(&self.0).unwrap()
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
}
macro_rules! gen_display_debug {
($t: ty) => {
impl fmt::Display for $t {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl fmt::Debug for $t {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
pub struct AircraftCode([u8; 3]);
gen_display_debug!(AircraftCode);
impl AircraftCode {
gen_as!();
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
let mut mine = [0; 3];
mine.copy_from_slice(bytes);
AircraftCode(mine)
}
}
#[derive(Debug)]
pub enum AircraftCodeParseError {
InvalidLength(usize),
InvalidCharacter(char)
}
impl std::fmt::Display for AircraftCodeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AircraftCodeParseError::InvalidLength(len) => {
write!(f, "invalid length: {}, expected 3", len)
},
AircraftCodeParseError::InvalidCharacter(c) => {
write!(f, "invalid character: {}, expected A-Z0-9", c)
}
}
}
}
impl std::error::Error for AircraftCodeParseError {
fn description(&self) -> &str {
"aircraft code parsing error"
}
}
impl FromStr for AircraftCode {
type Err = AircraftCodeParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() != 3 {
return Err(AircraftCodeParseError::InvalidLength(value.len()));
}
for c in value.chars() {
if c.is_ascii_uppercase() || c.is_ascii_digit() {
continue;
} else {
return Err(AircraftCodeParseError::InvalidCharacter(c));
}
}
let mut bytes = [0; 3];
bytes.copy_from_slice(value.as_bytes());
Ok(AircraftCode(bytes))
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
pub struct AirlineCode([u8; 2]);
gen_display_debug!(AirlineCode);
impl AirlineCode {
gen_as!();
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
let mut mine = [0; 2];
mine.copy_from_slice(bytes);
AirlineCode(mine)
}
}
#[derive(Debug)]
pub enum AirlineCodeParseError {
InvalidLength(usize),
InvalidCharacter(char)
}
impl std::fmt::Display for AirlineCodeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AirlineCodeParseError::InvalidLength(len) => {
write!(f, "invalid length: {}, expected 2", len)
},
AirlineCodeParseError::InvalidCharacter(c) => {
write!(f, "invalid character: {}, expected A-Z0-9", c)
}
}
}
}
impl std::error::Error for AirlineCodeParseError {
fn description(&self) -> &str {
"airline code parsing error"
}
}
impl FromStr for AirlineCode {
type Err = AirlineCodeParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() != 2 {
return Err(AirlineCodeParseError::InvalidLength(value.len()));
}
for c in value.chars() {
if c.is_ascii_uppercase() || c.is_ascii_digit() {
continue;
} else {
return Err(AirlineCodeParseError::InvalidCharacter(c))
}
}
let mut bytes = [0; 2];
bytes.copy_from_slice(value.as_bytes());
Ok(AirlineCode(bytes))
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
pub struct AirportCode([u8; 3]);
gen_display_debug!(AirportCode);
impl AirportCode {
gen_as!();
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
let mut mine = [0; 3];
mine.copy_from_slice(bytes);
AirportCode(mine)
}
}
#[derive(Debug)]
pub enum AirportCodeParseError {
InvalidLength(usize),
InvalidCharacter(char)
}
impl std::fmt::Display for AirportCodeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AirportCodeParseError::InvalidLength(len) => {
write!(f, "invalid length: {}, expected 3", len)
},
AirportCodeParseError::InvalidCharacter(c) => {
write!(f, "invalid character: {}, expected A-Z0-9", c)
}
}
}
}
impl std::error::Error for AirportCodeParseError {
fn description(&self) -> &str {
"airport code parsing error"
}
}
impl FromStr for AirportCode {
type Err = AirportCodeParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() != 3 {
return Err(AirportCodeParseError::InvalidLength(value.len()));
}
for c in value.chars() {
if c.is_ascii_uppercase() {
continue;
} else {
return Err(AirportCodeParseError::InvalidCharacter(c));
}
}
let mut bytes = [0; 3];
bytes.copy_from_slice(value.as_bytes());
Ok(AirportCode(bytes))
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
pub struct CityCode([u8; 3]);
gen_display_debug!(CityCode);
impl CityCode {
gen_as!();
pub unsafe fn from_bytes_unchecked(bytes: &[u8]) -> Self {
let mut mine = [0; 3];
mine.copy_from_slice(bytes);
CityCode(mine)
}
}
#[derive(Debug)]
pub enum CityCodeParseError {
InvalidLength(usize),
InvalidCharacter(char)
}
impl std::fmt::Display for CityCodeParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CityCodeParseError::InvalidLength(len) => {
write!(f, "invalid length: {}, expected 3", len)
},
CityCodeParseError::InvalidCharacter(c) => {
write!(f, "invalid character: {}, expected A-Z0-9", c)
}
}
}
}
impl std::error::Error for CityCodeParseError {
fn description(&self) -> &str {
"airport code parsing error"
}
}
impl FromStr for CityCode {
type Err = CityCodeParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value.len() != 3 {
return Err(CityCodeParseError::InvalidLength(value.len()));
}
for c in value.chars() {
if c.is_ascii_uppercase() {
continue;
} else {
return Err(CityCodeParseError::InvalidCharacter(c));
}
}
let mut bytes = [0; 3];
bytes.copy_from_slice(value.as_bytes());
Ok(CityCode(bytes))
}
}
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, Hash, Clone, Copy)]
pub struct FlightNumber(u16);
impl FlightNumber {
pub fn to_u16(&self) -> u16 {
self.0
}
pub fn from_u16(num: u16) -> Result<Self, FlightNumberParseError> {
if num >= 1 && num <= 9999 {
return Ok(FlightNumber(num))
}
Err(FlightNumberParseError::InvalidNumber)
}
}
impl fmt::Display for FlightNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:04}", self.0)
}
}
#[derive(Debug)]
pub enum FlightNumberParseError {
NotANumber,
InvalidNumber,
}
impl std::fmt::Display for FlightNumberParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
FlightNumberParseError::NotANumber => {
write!(f, "not a number")
},
FlightNumberParseError::InvalidNumber => {
write!(f, "invalid number, expect 0001 to 9999")
}
}
}
}
impl std::error::Error for FlightNumberParseError {
fn description(&self) -> &str {
"airport code parsing error"
}
}
impl FromStr for FlightNumber {
type Err = FlightNumberParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let num = value.parse()
.map_err(|_| FlightNumberParseError::NotANumber)?;
Self::from_u16(num)
}
}