#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
pub struct Version(VersionPart, Vec<VersionPart>);
impl<'de> Deserialize<'de> for Version
{
#[inline(always)]
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>
{
struct SupportVisitor;
impl<'de> Visitor<'de> for SupportVisitor
{
type Value = Version;
#[inline(always)]
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result
{
formatter.write_str("a string which contains a period-delimited version")
}
#[inline(always)]
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E>
{
Ok(Version::parse(v))
}
}
deserializer.deserialize_str(SupportVisitor)
}
}
impl<'a, I: Into<&'a str>> From<I> for Version
{
#[inline(always)]
fn from(value: I) -> Self
{
Version::parse(value.into())
}
}
impl FromStr for Version
{
type Err = ();
#[inline(always)]
fn from_str(s: &str) -> Result<Self, Self::Err>
{
Ok(Version::parse(s))
}
}
impl Version
{
#[inline(always)]
pub fn opera_mini_all() -> Self
{
Version(VersionPart::All, vec![])
}
#[inline(always)]
pub fn safari_technology_preview() -> Self
{
Version(VersionPart::TechnologyPreview, vec![])
}
#[inline(always)]
pub fn major(major_version: u64) -> Self
{
Version(VersionPart::Number(major_version), vec![])
}
#[inline(always)]
pub fn major_minor(major_version: u64, minor_version: u64) -> Self
{
Version(VersionPart::Number(major_version), vec![VersionPart::Number(minor_version)])
}
#[inline(always)]
pub fn major_minor_revision(major_version: u64, minor_version: u64, revision_version: u64) -> Self
{
Version(VersionPart::Number(major_version), vec![VersionPart::Number(minor_version), VersionPart::Number(revision_version)])
}
#[inline(always)]
pub fn is_safari_technology_preview(&self) -> bool
{
match self.0
{
VersionPart::TechnologyPreview => true,
_ => false,
}
}
#[inline(always)]
pub fn is_invalid_or_unknown(&self) -> bool
{
match self.0
{
VersionPart::Number(0) => true,
VersionPart::Unknown(_) => true,
_ => false,
}
}
#[inline(always)]
fn parse(v: &str) -> Self
{
use self::VersionPart::*;
if let Some(index) = v.find('-')
{
return Self::parse(&v[..index]);
}
match v
{
"TP" => return Self::safari_technology_preview(),
"all" => return Self::opera_mini_all(),
_ => (),
}
let parts = v.split('.');
let (lower, upper) = parts.size_hint();
let mut capacity = if let Some(upper) = upper
{
upper
}
else
{
lower
};
if capacity != 0
{
capacity -= 1;
}
let mut first = None;
let mut subsequent = Vec::with_capacity(capacity);
for part in parts
{
let versionPart = match part.parse::<u64>()
{
Ok(value) => Number(value),
Err(_) => Unknown(part.to_owned())
};
if first.is_none()
{
first = Some(versionPart);
}
else
{
subsequent.push(versionPart);
}
}
subsequent.shrink_to_fit();
Version(first.unwrap(), subsequent)
}
}