use std::{ fmt::{self, Display}, str::FromStr, }; use anyhow::{anyhow, Result}; use serde::{de::Error, Deserialize, Serialize}; /// A datastructure representing a semantic version number #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] pub struct SemanticVersion { pub major: usize, pub minor: usize, pub patch: usize, } pub fn semver(major: usize, minor: usize, patch: usize) -> SemanticVersion { SemanticVersion { major, minor, patch, } } impl SemanticVersion { pub fn new(major: usize, minor: usize, patch: usize) -> Self { Self { major, minor, patch, } } } impl FromStr for SemanticVersion { type Err = anyhow::Error; fn from_str(s: &str) -> Result { let mut components = s.trim().split('.'); let major = components .next() .ok_or_else(|| anyhow!("missing major version number"))? .parse()?; let minor = components .next() .ok_or_else(|| anyhow!("missing minor version number"))? .parse()?; let patch = components .next() .ok_or_else(|| anyhow!("missing patch version number"))? .parse()?; Ok(Self { major, minor, patch, }) } } impl Display for SemanticVersion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}.{}.{}", self.major, self.minor, self.patch) } } impl Serialize for SemanticVersion { fn serialize(&self, serializer: S) -> std::prelude::v1::Result where S: serde::Serializer, { serializer.serialize_str(&self.to_string()) } } impl<'de> Deserialize<'de> for SemanticVersion { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { let string = String::deserialize(deserializer)?; Self::from_str(&string) .map_err(|_| Error::custom(format!("Invalid version string \"{string}\""))) } }