use std::hash::{Hash, Hasher}; use std::ops::Deref; use std::str::FromStr; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use ts_rs::TS; #[derive(Debug, Clone, TS)] #[ts(type = "string", rename = "Version")] pub struct VersionString { version: exver::ExtendedVersion, string: String, } impl VersionString { pub fn as_str(&self) -> &str { self.string.as_str() } pub fn into_version(self) -> exver::ExtendedVersion { self.version } } impl std::fmt::Display for VersionString { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.string) } } impl std::str::FromStr for VersionString { type Err = ::Err; fn from_str(s: &str) -> Result { Ok(VersionString { string: s.to_owned(), version: s.parse()?, }) } } impl From for VersionString { fn from(v: exver::ExtendedVersion) -> Self { VersionString { string: v.to_string(), version: v, } } } impl From for exver::ExtendedVersion { fn from(v: VersionString) -> Self { v.version } } impl Default for VersionString { fn default() -> Self { Self::from(exver::ExtendedVersion::default()) } } impl Deref for VersionString { type Target = exver::ExtendedVersion; fn deref(&self) -> &Self::Target { &self.version } } impl AsRef for VersionString { fn as_ref(&self) -> &exver::ExtendedVersion { &self.version } } impl AsRef for VersionString { fn as_ref(&self) -> &str { self.as_str() } } impl PartialEq for VersionString { fn eq(&self, other: &VersionString) -> bool { self.version.eq(&other.version) } } impl Eq for VersionString {} impl PartialOrd for VersionString { fn partial_cmp(&self, other: &Self) -> Option { self.version.partial_cmp(&other.version) } } impl Ord for VersionString { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.version.partial_cmp(&other.version).unwrap_or_else(|| { match (self.version.flavor(), other.version.flavor()) { (None, Some(_)) => std::cmp::Ordering::Greater, (Some(_), None) => std::cmp::Ordering::Less, (a, b) => a.cmp(&b), } }) } } impl Hash for VersionString { fn hash(&self, state: &mut H) { self.version.hash(state) } } impl<'de> Deserialize<'de> for VersionString { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { let string = String::deserialize(deserializer)?; let version = exver::ExtendedVersion::from_str(&string).map_err(::serde::de::Error::custom)?; Ok(Self { string, version }) } } impl Serialize for VersionString { fn serialize(&self, serializer: S) -> Result where S: Serializer, { self.string.serialize(serializer) } }