use std::{error::Error, fmt, str::FromStr, string::ToString};
pub trait Order {
fn with_order(self, order: Direction) -> Self;
fn order(&self) -> Option<Direction>;
}
macro_rules! impl_order {
($name:path) => {
impl Order for $name {
fn with_order(mut self, order: Direction) -> $name {
self.order = Some(order);
self
}
fn order(&self) -> Option<Direction> {
self.order
}
}
};
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Direction {
Asc,
Desc,
}
impl ToString for Direction {
fn to_string(&self) -> String {
match *self {
Direction::Asc => "asc".to_string(),
Direction::Desc => "desc".to_string(),
}
}
}
#[derive(Debug)]
pub struct ParseDirectionError {
kind: ErrorKind,
}
#[derive(Debug)]
enum ErrorKind {
InvalidToken,
}
impl Error for ParseDirectionError {
fn description(&self) -> &str {
match self.kind {
ErrorKind::InvalidToken => "Invalid token specified",
}
}
}
impl fmt::Display for ParseDirectionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.description())
}
}
impl FromStr for Direction {
type Err = ParseDirectionError;
fn from_str(s: &str) -> Result<Direction, Self::Err> {
match s.to_lowercase().as_ref() {
"asc" => Ok(Direction::Asc),
"desc" => Ok(Direction::Desc),
_ => Err(ParseDirectionError {
kind: ErrorKind::InvalidToken,
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_can_become_a_string() {
assert_eq!(Direction::Asc.to_string(), "asc");
assert_eq!(Direction::Desc.to_string(), "desc");
}
#[test]
fn it_can_be_derived() {
struct Foo {
order: Option<Direction>,
}
impl_order!(Foo);
let foo = Foo { order: None }.with_order(Direction::Asc);
assert_eq!(foo.order, Some(Direction::Asc));
assert_eq!(foo.order(), Some(Direction::Asc));
}
#[test]
fn it_can_be_parsed() {
assert_eq!("asc".parse::<Direction>().unwrap(), Direction::Asc);
assert_eq!("aSc".parse::<Direction>().unwrap(), Direction::Asc);
assert_eq!("desc".parse::<Direction>().unwrap(), Direction::Desc);
assert_eq!("DESC".parse::<Direction>().unwrap(), Direction::Desc);
assert!("no".parse::<Direction>().is_err());
}
}