1use rez_next_version::Version;
4use serde::{Deserialize, Serialize};
5use std::fmt;
6use std::str::FromStr;
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct Requirement {
11 pub name: String,
13
14 pub version_constraint: Option<VersionConstraint>,
16
17 pub weak: bool,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
23pub enum VersionConstraint {
24 Exact(Version),
26
27 GreaterThan(Version),
29
30 GreaterThanOrEqual(Version),
32
33 LessThan(Version),
35
36 LessThanOrEqual(Version),
38
39 Compatible(Version),
41
42 Range(Version, Version),
44
45 Any,
47}
48
49impl Requirement {
50 pub fn new(name: String) -> Self {
52 Self {
53 name,
54 version_constraint: None,
55 weak: false,
56 }
57 }
58
59 pub fn is_satisfied_by(&self, version: &Version) -> bool {
61 match &self.version_constraint {
62 None => true, Some(constraint) => constraint.is_satisfied_by(version),
64 }
65 }
66
67 pub fn package_name(&self) -> &str {
69 &self.name
70 }
71}
72
73impl VersionConstraint {
74 pub fn is_satisfied_by(&self, version: &Version) -> bool {
76 match self {
77 VersionConstraint::Exact(v) => version == v,
78 VersionConstraint::GreaterThan(v) => version > v,
79 VersionConstraint::GreaterThanOrEqual(v) => version >= v,
80 VersionConstraint::LessThan(v) => version < v,
81 VersionConstraint::LessThanOrEqual(v) => version <= v,
82 VersionConstraint::Compatible(v) => {
83 version >= v && version.as_str().split('.').next() == v.as_str().split('.').next()
85 }
86 VersionConstraint::Range(min, max) => version >= min && version < max,
87 VersionConstraint::Any => true,
88 }
89 }
90}
91
92impl FromStr for Requirement {
93 type Err = String;
94
95 fn from_str(s: &str) -> Result<Self, Self::Err> {
96 let s = s.trim();
97
98 let (s, weak) = if s.starts_with("~") {
100 (&s[1..], true)
101 } else {
102 (s, false)
103 };
104
105 if s.ends_with("+") {
107 let without_plus = &s[..s.len() - 1];
109 if let Some(dash_pos) = without_plus.rfind("-") {
110 let name = without_plus[..dash_pos].to_string();
111 let version_str = &without_plus[dash_pos + 1..];
112 let version = Version::parse(version_str)
113 .map_err(|e| format!("Invalid version {}: {}", version_str, e))?;
114 Ok(Requirement {
115 name,
116 version_constraint: Some(VersionConstraint::GreaterThanOrEqual(version)),
117 weak,
118 })
119 } else {
120 Ok(Requirement {
121 name: s.to_string(),
122 version_constraint: None,
123 weak,
124 })
125 }
126 } else {
127 Ok(Requirement {
129 name: s.to_string(),
130 version_constraint: None,
131 weak,
132 })
133 }
134 }
135}
136
137impl fmt::Display for Requirement {
138 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139 if self.weak {
140 write!(f, "~")?;
141 }
142
143 write!(f, "{}", self.name)?;
144
145 if let Some(ref constraint) = self.version_constraint {
146 write!(f, "{}", constraint)?;
147 }
148
149 Ok(())
150 }
151}
152
153impl fmt::Display for VersionConstraint {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 match self {
156 VersionConstraint::Exact(v) => write!(f, "=={}", v.as_str()),
157 VersionConstraint::GreaterThan(v) => write!(f, ">{}", v.as_str()),
158 VersionConstraint::GreaterThanOrEqual(v) => write!(f, ">={}", v.as_str()),
159 VersionConstraint::LessThan(v) => write!(f, "<{}", v.as_str()),
160 VersionConstraint::LessThanOrEqual(v) => write!(f, "<={}", v.as_str()),
161 VersionConstraint::Compatible(v) => write!(f, "~={}", v.as_str()),
162 VersionConstraint::Range(min, max) => write!(f, ">={},<{}", min.as_str(), max.as_str()),
163 VersionConstraint::Any => write!(f, ""),
164 }
165 }
166}