complish 0.0.1

Core library for project-aware task management with git integration
Documentation
use std::{
  cmp::Ordering,
  fmt::{Display, Formatter, Result as FmtResult},
  str::FromStr,
};

use eyre::{Error, Result, eyre};
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub enum TaskPriority {
  #[serde(rename = "p0")]
  Highest = 0,
  #[serde(rename = "p1")]
  High = 1,
  #[serde(rename = "p2")]
  #[default]
  Medium = 2,
  #[serde(rename = "p3")]
  Low = 3,
  #[serde(rename = "p4")]
  Lowest = 4,
}

impl Display for TaskPriority {
  fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
    match self {
      Self::Highest => write!(f, "p0"),
      Self::High => write!(f, "p1"),
      Self::Medium => write!(f, "p2"),
      Self::Low => write!(f, "p3"),
      Self::Lowest => write!(f, "p4"),
    }
  }
}

impl FromStr for TaskPriority {
  type Err = Error;

  fn from_str(s: &str) -> Result<Self> {
    match s {
      "p0" => Ok(Self::Highest),
      "p1" => Ok(Self::High),
      "p2" => Ok(Self::Medium),
      "p3" => Ok(Self::Low),
      "p4" => Ok(Self::Lowest),
      _ => Err(eyre!("Invalid priority")),
    }
  }
}

impl Ord for TaskPriority {
  fn cmp(&self, other: &Self) -> Ordering {
    (other.clone() as u8).cmp(&(self.clone() as u8))
  }
}

impl PartialOrd for TaskPriority {
  fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
    Some(self.cmp(other))
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  mod display {
    use pretty_assertions::assert_eq;

    use super::*;

    #[test]
    fn it_displays_correctly() {
      assert_eq!(TaskPriority::Highest.to_string(), "p0");
      assert_eq!(TaskPriority::High.to_string(), "p1");
      assert_eq!(TaskPriority::Medium.to_string(), "p2");
      assert_eq!(TaskPriority::Low.to_string(), "p3");
      assert_eq!(TaskPriority::Lowest.to_string(), "p4");
    }
  }

  mod from_str {
    use pretty_assertions::assert_eq;

    use super::*;

    #[test]
    fn it_parses_correctly() {
      assert_eq!(TaskPriority::from_str("p0").unwrap(), TaskPriority::Highest);
      assert_eq!(TaskPriority::from_str("p1").unwrap(), TaskPriority::High);
      assert_eq!(TaskPriority::from_str("p2").unwrap(), TaskPriority::Medium);
      assert_eq!(TaskPriority::from_str("p3").unwrap(), TaskPriority::Low);
      assert_eq!(TaskPriority::from_str("p4").unwrap(), TaskPriority::Lowest);
    }

    #[test]
    fn it_errors_on_invalid_input() {
      assert!(TaskPriority::from_str("p5").is_err());
    }
  }

  mod ordering {
    use super::*;

    #[test]
    fn it_orders_correctly() {
      assert!(TaskPriority::Highest > TaskPriority::High);
      assert!(TaskPriority::High > TaskPriority::Medium);
      assert!(TaskPriority::Medium > TaskPriority::Low);
      assert!(TaskPriority::Low > TaskPriority::Lowest);
    }
  }
}