use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use crate::error::{Error, Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Availability {
Available,
Registered,
Premium,
Reserved,
}
impl Availability {
pub fn is_available(self) -> bool {
self == Availability::Available
}
pub fn is_obtainable(self) -> bool {
matches!(self, Availability::Available | Availability::Premium)
}
pub fn is_registered(self) -> bool {
self == Availability::Registered
}
pub fn as_str(self) -> &'static str {
match self {
Availability::Available => "available",
Availability::Registered => "registered",
Availability::Premium => "premium",
Availability::Reserved => "reserved",
}
}
}
impl fmt::Display for Availability {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl FromStr for Availability {
type Err = Error;
fn from_str(s: &str) -> Result<Self> {
match s.trim().to_ascii_lowercase().as_str() {
"available" | "free" => Ok(Availability::Available),
"registered" | "unavailable" | "taken" => Ok(Availability::Registered),
"premium" => Ok(Availability::Premium),
"reserved" | "restricted" => Ok(Availability::Reserved),
_ => Err(Error::Definitions(format!("{s:?} is not an availability"))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn premium_is_obtainable_but_not_available() {
assert!(!Availability::Premium.is_available());
assert!(Availability::Premium.is_obtainable());
assert!(Availability::Available.is_available());
assert!(!Availability::Reserved.is_obtainable());
}
#[test]
fn parses_sibling_library_wording() {
assert_eq!(
"unavailable".parse::<Availability>().unwrap(),
Availability::Registered
);
assert_eq!(
"AVAILABLE".parse::<Availability>().unwrap(),
Availability::Available
);
assert!("maybe".parse::<Availability>().is_err());
}
#[test]
fn serialises_as_a_lowercase_string() {
let json = serde_json::to_string(&Availability::Registered).unwrap();
assert_eq!(json, "\"registered\"");
assert_eq!(
serde_json::from_str::<Availability>("\"premium\"").unwrap(),
Availability::Premium
);
}
#[test]
fn display_matches_as_str() {
for value in [
Availability::Available,
Availability::Registered,
Availability::Premium,
Availability::Reserved,
] {
assert_eq!(value.to_string(), value.as_str());
assert_eq!(value.as_str().parse::<Availability>().unwrap(), value);
}
}
}