miden_package_registry/
version_requirement.rs1use core::fmt;
2
3use miden_assembly_syntax::debuginfo::Span;
4#[cfg(feature = "serde")]
5use serde::{Deserialize, Serialize};
6
7use super::*;
8use crate::{LexicographicWord, Word};
9
10#[derive(Debug, Clone)]
12pub enum VersionRequirement {
13 Semantic(Span<VersionReq>),
21 Digest(Span<Word>),
30 Exact(Version),
32}
33
34impl VersionRequirement {
35 pub fn is_semantic_version(&self) -> bool {
37 matches!(self, Self::Semantic(_))
38 }
39
40 pub fn is_digest(&self) -> bool {
42 matches!(self, Self::Digest(_))
43 }
44
45 pub fn is_exact(&self) -> bool {
47 matches!(self, Self::Exact(_))
48 }
49}
50
51impl Eq for VersionRequirement {}
52
53impl PartialEq for VersionRequirement {
54 fn eq(&self, other: &Self) -> bool {
55 match (self, other) {
56 (Self::Exact(l), Self::Exact(r)) => l == r,
57 (Self::Digest(l), Self::Digest(r)) => {
58 LexicographicWord::new(l.into_inner()) == LexicographicWord::new(r.into_inner())
59 },
60 (Self::Semantic(l), Self::Semantic(r)) => l == r,
61 (Self::Semantic(_) | Self::Exact(_), Self::Digest(_))
62 | (Self::Semantic(_), Self::Exact(_))
63 | (Self::Digest(_), Self::Semantic(_) | Self::Exact(_))
64 | (Self::Exact(_), Self::Semantic(_)) => false,
65 }
66 }
67}
68
69impl fmt::Display for VersionRequirement {
70 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71 match self {
72 Self::Semantic(v) => fmt::Display::fmt(v, f),
73 Self::Digest(word) => fmt::Display::fmt(word, f),
74 Self::Exact(version) => {
75 assert!(
76 version.digest.is_some(),
77 "exact requirements must include an artifact digest"
78 );
79 write!(f, "{version}")
80 },
81 }
82 }
83}
84
85impl From<VersionReq> for VersionRequirement {
86 fn from(version: VersionReq) -> Self {
87 Self::Semantic(Span::unknown(version))
88 }
89}
90
91impl From<Word> for VersionRequirement {
92 fn from(digest: Word) -> Self {
93 Self::Digest(Span::unknown(digest))
94 }
95}
96
97impl From<Version> for VersionRequirement {
98 fn from(value: Version) -> Self {
99 if value.digest.is_none() {
100 Self::Semantic(Span::unknown(format!("={}", &value.version).parse().unwrap()))
101 } else {
102 Self::Exact(value)
103 }
104 }
105}
106
107#[cfg(feature = "serde")]
108impl Serialize for VersionRequirement {
109 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
110 where
111 S: serde::Serializer,
112 {
113 use alloc::string::ToString;
114 serializer.serialize_str(&self.to_string())
115 }
116}
117
118#[cfg(feature = "serde")]
119impl<'de> Deserialize<'de> for VersionRequirement {
120 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
121 where
122 D: serde::Deserializer<'de>,
123 {
124 use core::str::FromStr;
125
126 let value = <alloc::string::String as Deserialize>::deserialize(deserializer)?;
127
128 if value == "*" {
129 return Ok(Self::from(VersionReq::STAR.clone()));
130 }
131
132 if let Some((version, digest)) = value.split_once('#') {
133 let version = version.parse::<SemVer>().map_err(serde::de::Error::custom)?;
134 let digest = Word::parse(digest).map_err(serde::de::Error::custom)?;
135 return Ok(Self::Exact(Version::new(version, digest)));
136 }
137
138 if let Ok(digest) = Word::parse(&value) {
139 return Ok(Self::from(digest));
140 }
141
142 let requirement = VersionReq::from_str(&value).map_err(serde::de::Error::custom)?;
143 Ok(Self::from(requirement))
144 }
145}