version_spec/
unresolved_spec.rs#![allow(clippy::from_over_into)]
use crate::spec_error::SpecError;
use crate::unresolved_parser::*;
use crate::version_types::*;
use crate::{clean_version_req_string, clean_version_string, is_alias_name, VersionSpec};
use compact_str::CompactString;
use semver::VersionReq;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display};
use std::str::FromStr;
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
#[serde(untagged, into = "String", try_from = "String")]
pub enum UnresolvedVersionSpec {
Canary,
Alias(CompactString),
Req(VersionReq),
ReqAny(Vec<VersionReq>),
Calendar(CalVer),
Semantic(SemVer),
}
impl UnresolvedVersionSpec {
pub fn parse<T: AsRef<str>>(value: T) -> Result<Self, SpecError> {
Self::from_str(value.as_ref())
}
pub fn is_alias<A: AsRef<str>>(&self, name: A) -> bool {
match self {
Self::Alias(alias) => alias == name.as_ref(),
_ => false,
}
}
pub fn is_canary(&self) -> bool {
match self {
Self::Canary => true,
Self::Alias(alias) => alias == "canary",
_ => false,
}
}
pub fn is_latest(&self) -> bool {
match self {
Self::Alias(alias) => alias == "latest",
_ => false,
}
}
pub fn to_resolved_spec(&self) -> VersionSpec {
match self {
Self::Canary => VersionSpec::Canary,
Self::Alias(alias) => VersionSpec::Alias(CompactString::new(alias)),
Self::Calendar(version) => VersionSpec::Calendar(version.to_owned()),
Self::Semantic(version) => VersionSpec::Semantic(version.to_owned()),
_ => VersionSpec::default(),
}
}
}
#[cfg(feature = "schematic")]
impl schematic::Schematic for UnresolvedVersionSpec {
fn schema_name() -> Option<String> {
Some("UnresolvedVersionSpec".into())
}
fn build_schema(mut schema: schematic::SchemaBuilder) -> schematic::Schema {
schema.set_description("Represents an unresolved version or alias that must be resolved to a fully-qualified version.");
schema.string_default()
}
}
impl Default for UnresolvedVersionSpec {
fn default() -> Self {
Self::Alias("latest".into())
}
}
impl FromStr for UnresolvedVersionSpec {
type Err = SpecError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
if value == "canary" {
return Ok(UnresolvedVersionSpec::Canary);
}
let value = clean_version_string(value);
if is_alias_name(&value) {
return Ok(UnresolvedVersionSpec::Alias(CompactString::new(value)));
}
let value = clean_version_req_string(&value);
if value.contains("||") {
let mut reqs = vec![];
for result in parse_multi(&value)? {
reqs.push(VersionReq::parse(&result)?);
}
return Ok(UnresolvedVersionSpec::ReqAny(reqs));
}
let (result, kind) = parse(value)?;
Ok(match kind {
ParseKind::Req => UnresolvedVersionSpec::Req(VersionReq::parse(&result)?),
ParseKind::Cal => UnresolvedVersionSpec::Calendar(CalVer::parse(&result)?),
_ => UnresolvedVersionSpec::Semantic(SemVer::parse(&result)?),
})
}
}
impl TryFrom<String> for UnresolvedVersionSpec {
type Error = SpecError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::from_str(&value)
}
}
impl Into<String> for UnresolvedVersionSpec {
fn into(self) -> String {
self.to_string()
}
}
impl Display for UnresolvedVersionSpec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Canary => write!(f, "canary"),
Self::Alias(alias) => write!(f, "{}", alias),
Self::Req(req) => write!(f, "{}", req),
Self::ReqAny(reqs) => write!(
f,
"{}",
reqs.iter()
.map(|req| req.to_string())
.collect::<Vec<_>>()
.join(" || ")
),
Self::Calendar(version) => write!(f, "{}", version),
Self::Semantic(version) => write!(f, "{}", version),
}
}
}
impl PartialEq<VersionSpec> for UnresolvedVersionSpec {
fn eq(&self, other: &VersionSpec) -> bool {
match (self, other) {
(Self::Canary, VersionSpec::Alias(a)) => a == "canary",
(Self::Alias(a1), VersionSpec::Alias(a2)) => a1 == a2,
(Self::Calendar(v1), VersionSpec::Calendar(v2)) => v1 == v2,
(Self::Semantic(v1), VersionSpec::Semantic(v2)) => v1 == v2,
_ => false,
}
}
}
impl AsRef<UnresolvedVersionSpec> for UnresolvedVersionSpec {
fn as_ref(&self) -> &UnresolvedVersionSpec {
self
}
}