use crate::primitives::Either; /// A type representing units of length /// /// It can be any of the following /// - Centimeters /// - Meters /// - Kilometers /// - Inches /// - Feet /// - A custom value #[derive( Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize, )] #[serde(transparent)] pub struct Unit(Either); impl Unit { /// Create a new unit measuring Centimeters /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::centimeters(); /// ``` pub fn centimeters() -> Self { Unit(Either::Left(Length::Centimeters)) } /// Check if the unit is Centimeters /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::centimeters().is_centimeters()); /// ``` pub fn is_centimeters(&self) -> bool { self.0 .as_ref() .left() .map(|l| l.is_centimeters()) .unwrap_or(false) } /// Create a new unit measuring Meters /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::meters(); /// ``` pub fn meters() -> Self { Unit(Either::Left(Length::Meters)) } /// Check if the unit is Meters /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::meters().is_meters()); /// ``` pub fn is_meters(&self) -> bool { self.0 .as_ref() .left() .map(|l| l.is_meters()) .unwrap_or(false) } /// Create a new unit measuring Kilometers /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::kilometers(); /// ``` pub fn kilometers() -> Self { Unit(Either::Left(Length::Kilometers)) } /// Check if the unit is Kilometers /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::kilometers().is_kilometers()); /// ``` pub fn is_kilometers(&self) -> bool { self.0 .as_ref() .left() .map(|l| l.is_kilometers()) .unwrap_or(false) } /// Create a new unit measuring Feet /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::feet(); /// ``` pub fn feet() -> Self { Unit(Either::Left(Length::Feet)) } /// Check if the unit is Feet /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::feet().is_feet()); /// ``` pub fn is_feet(&self) -> bool { self.0.as_ref().left().map(|l| l.is_feet()).unwrap_or(false) } /// Create a new unit measuring Inches /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::inches(); /// ``` pub fn inches() -> Self { Unit(Either::Left(Length::Inches)) } /// Check if the unit is Inches /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::inches().is_inches()); /// ``` pub fn is_inches(&self) -> bool { self.0 .as_ref() .left() .map(|l| l.is_inches()) .unwrap_or(false) } /// Create a new custom unit /// /// ```rust /// use activitystreams::primitives::Unit; /// /// Unit::custom("Yards"); /// ``` pub fn custom(string: T) -> Self where T: Into, { Unit(Either::Right(string.into())) } /// Check if a unit is custom /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::custom("Yards").is_custom()); /// ``` pub fn is_custom(&self) -> bool { self.as_custom().is_some() } /// Fetch a custom unit /// /// ```rust /// use activitystreams::primitives::Unit; /// /// assert!(Unit::custom("Yards").as_custom() == Some("Yards")); /// ``` pub fn as_custom(&self) -> Option<&str> { self.0.as_ref().right().map(|r| r.as_str()) } } impl Default for Unit { fn default() -> Self { Self::meters() } } impl std::str::FromStr for Unit { type Err = std::convert::Infallible; fn from_str(s: &str) -> Result { let unit = match s { "cm" => Self::centimeters(), "m" => Self::meters(), "km" => Self::kilometers(), "inches" => Self::inches(), "feet" => Self::feet(), other => Self::custom(other), }; Ok(unit) } } impl From for Unit { fn from(s: String) -> Self { match s.parse() { Ok(u) => u, Err(e) => match e {}, } } } impl From<&str> for Unit { fn from(s: &str) -> Self { match s.parse() { Ok(u) => u, Err(e) => match e {}, } } } /// A list of units of length that represent valid units for certain ActivityStreams objects #[derive( Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Deserialize, serde::Serialize, )] #[serde(untagged)] enum Length { #[serde(rename = "cm")] Centimeters, #[serde(rename = "feet")] Feet, #[serde(rename = "inches")] Inches, #[serde(rename = "km")] Kilometers, #[default] #[serde(rename = "m")] Meters, } #[derive(Clone, Debug)] /// The error type produced when a Length cannot be parsed struct LengthError; impl std::fmt::Display for LengthError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Could not parse units") } } impl std::error::Error for LengthError {} impl Length { fn is_centimeters(&self) -> bool { matches!(self, Length::Centimeters) } fn is_feet(&self) -> bool { matches!(self, Length::Feet) } fn is_inches(&self) -> bool { matches!(self, Length::Inches) } fn is_kilometers(&self) -> bool { matches!(self, Length::Kilometers) } fn is_meters(&self) -> bool { matches!(self, Length::Meters) } } impl std::str::FromStr for Length { type Err = LengthError; fn from_str(s: &str) -> Result { match s { "cm" => Ok(Length::Centimeters), "feet" => Ok(Length::Feet), "inches" => Ok(Length::Inches), "km" => Ok(Length::Kilometers), "m" => Ok(Length::Meters), _ => Err(LengthError), } } } impl std::convert::TryFrom<&str> for Length { type Error = LengthError; fn try_from(s: &str) -> Result { s.parse() } } impl std::convert::TryFrom<&mut str> for Length { type Error = LengthError; fn try_from(s: &mut str) -> Result { s.parse() } } impl std::convert::TryFrom for Length { type Error = LengthError; fn try_from(s: String) -> Result { s.parse() } } impl std::fmt::Display for Length { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { Length::Centimeters => write!(f, "cm"), Length::Feet => write!(f, "feet"), Length::Inches => write!(f, "inches"), Length::Kilometers => write!(f, "km"), Length::Meters => write!(f, "meters"), } } }