apt_edsp/scenario/
relations.rs

1use std::fmt::Display;
2use std::str::FromStr;
3
4use serde::{Deserialize, Serialize};
5
6use super::super::util::TryFromStringVisitor;
7use super::Version;
8
9/// Specifies the comparator used to compare two [`Version`]s.
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11pub enum Relation {
12    /// The first version must be strictly earlier than the second (`a < b`).
13    Earlier,
14    /// The first version must be earlier than or equal to the second (`a <= b`).
15    EarlierEqual,
16    /// The first version must be equal to the second (`a == b`).
17    Equal,
18    /// The first version must be later than or equal to the second (`a >= b`).
19    LaterEqual,
20    /// The first version must be strictly later than the second (`a > b`).
21    Later,
22}
23
24impl Relation {
25    fn parse<'a, E: nom::error::ParseError<&'a str>>(
26        input: &'a str,
27    ) -> nom::IResult<&str, Self, E> {
28        use nom::branch::alt;
29        use nom::bytes::complete::tag;
30        use nom::combinator::value;
31        alt((
32            value(Relation::Earlier, tag("<<")),
33            value(Relation::EarlierEqual, tag("<=")),
34            value(Relation::Equal, tag("=")),
35            value(Relation::LaterEqual, tag(">=")),
36            value(Relation::Later, tag(">>")),
37        ))(input)
38    }
39}
40
41impl Display for Relation {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            Relation::Earlier => write!(f, "<<"),
45            Relation::EarlierEqual => write!(f, "<="),
46            Relation::Equal => write!(f, "="),
47            Relation::LaterEqual => write!(f, ">="),
48            Relation::Later => write!(f, ">>"),
49        }
50    }
51}
52
53/// Describes a set of versions of a package.
54#[derive(Debug, Eq, PartialEq)]
55pub struct VersionSet {
56    /// The name of the package.
57    pub package: String,
58    /// The constraint fulfilled by the versions in the version set. If [`None`], the version set
59    /// contains _all_ the versions of the given package.
60    pub constraint: Option<(Relation, Version)>,
61}
62
63impl Display for VersionSet {
64    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65        write!(f, "{}", self.package)?;
66
67        if let Some((relation, version)) = &self.constraint {
68            write!(f, " ({} {})", relation, version.as_str())?;
69        }
70
71        Ok(())
72    }
73}
74
75/// The error returned when failing to parse a [`VersionSet`].
76#[derive(Debug)]
77pub enum VersionSetParseError {
78    /// The package name was empty. Contains the trace information for where the error was found.
79    EmptyPackageName(String),
80
81    /// There was an error parsing the constraint. Contains the trace information for where
82    /// the error was found.
83    BadConstraintSpec(String),
84
85    /// There was an error parsing the [`Version`].
86    BadVersion(<Version as TryFrom<&'static str>>::Error),
87}
88
89impl Display for VersionSetParseError {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        match self {
92            VersionSetParseError::EmptyPackageName(e) => {
93                write!(f, "Error parsing package name:\n{e}")
94            }
95            VersionSetParseError::BadConstraintSpec(e) => {
96                write!(f, "Error parsing constraint spec:\n{e}")
97            }
98            VersionSetParseError::BadVersion(e) => write!(f, "Error parsing version:\n{e}"),
99        }
100    }
101}
102
103impl FromStr for VersionSet {
104    type Err = VersionSetParseError;
105
106    fn from_str(input: &str) -> Result<Self, Self::Err> {
107        use nom::bytes::complete::*;
108        use nom::character::complete::*;
109        use nom::combinator::*;
110        use nom::error::{context, convert_error};
111        use nom::sequence::*;
112        use nom::Finish;
113
114        let (remaining, package) = terminated(
115            context(
116                "package name",
117                take_while1(|c: char| !c.is_whitespace() && c != '('),
118            ),
119            space0,
120        )(input)
121        .finish()
122        .map_err(|e| VersionSetParseError::EmptyPackageName(convert_error(input, e)))?;
123
124        // Parse constraint
125        let constraint = if remaining.is_empty() {
126            None
127        } else {
128            let (_, (relation, version)) = all_consuming(context(
129                "spec",
130                preceded(
131                    char('('),
132                    terminated(
133                        separated_pair(
134                            context("relation", Relation::parse),
135                            space0,
136                            context("version", take_until1(")")),
137                        ),
138                        tuple((char(')'), space0)),
139                    ),
140                ),
141            ))(remaining)
142            .finish()
143            .map_err(|e| VersionSetParseError::BadConstraintSpec(convert_error(input, e)))?;
144            let version = Version::try_from(version).map_err(VersionSetParseError::BadVersion)?;
145            Some((relation, version))
146        };
147
148        Ok(Self {
149            package: package.to_string(),
150            constraint,
151        })
152    }
153}
154
155impl TryFrom<String> for VersionSet {
156    type Error = <Self as FromStr>::Err;
157
158    fn try_from(value: String) -> Result<Self, Self::Error> {
159        Self::from_str(&value)
160    }
161}
162
163impl TryFrom<&str> for VersionSet {
164    type Error = <Self as FromStr>::Err;
165
166    fn try_from(value: &str) -> Result<Self, Self::Error> {
167        Self::from_str(value)
168    }
169}
170
171impl Serialize for VersionSet {
172    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
173        serializer.collect_str(self)
174    }
175}
176
177impl<'de> Deserialize<'de> for VersionSet {
178    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
179        deserializer.deserialize_str(TryFromStringVisitor::new())
180    }
181}
182
183/// Specifies a dependency of a package that can be fulfilled by one or more [`VersionSet`]s.
184#[derive(Debug, Eq, PartialEq)]
185pub struct Dependency {
186    /// The first [`VersionSet`] that can fulfill this [`Dependency`].
187    pub first: VersionSet,
188    /// The other [`VersionSet`]s that can fulfill this [`Dependency`].
189    pub alternates: Vec<VersionSet>,
190}
191
192impl Display for Dependency {
193    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194        write!(f, "{}", self.first)?;
195
196        for alt in &self.alternates {
197            write!(f, " | {}", alt)?;
198        }
199
200        Ok(())
201    }
202}
203
204/// The error returned when failing to parse a [`Dependency`].
205#[derive(Debug)]
206pub enum DependencyParseError {
207    /// There was an error parsing the [`VersionSet`] with the given index.
208    Alternate(usize, VersionSetParseError),
209}
210
211impl Display for DependencyParseError {
212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213        match self {
214            DependencyParseError::Alternate(i, e) => write!(f, "Error parsing alternate {i}: {e}"),
215        }
216    }
217}
218
219impl FromStr for Dependency {
220    type Err = DependencyParseError;
221
222    fn from_str(input: &str) -> Result<Self, Self::Err> {
223        let (first, rest) = input.split_once('|').unwrap_or((input, ""));
224
225        let first = first
226            .trim()
227            .parse()
228            .map_err(|e| DependencyParseError::Alternate(0, e))?;
229        let alternates = if !rest.is_empty() {
230            rest.split('|')
231                .map(|s| s.trim())
232                .enumerate()
233                .map(|(i, s)| {
234                    s.parse()
235                        .map_err(|e| DependencyParseError::Alternate(i + 1, e))
236                })
237                .collect::<Result<_, _>>()?
238        } else {
239            vec![]
240        };
241
242        Ok(Self { first, alternates })
243    }
244}
245
246impl TryFrom<String> for Dependency {
247    type Error = <Self as FromStr>::Err;
248
249    fn try_from(value: String) -> Result<Self, Self::Error> {
250        Self::from_str(&value)
251    }
252}
253
254impl TryFrom<&str> for Dependency {
255    type Error = <Self as FromStr>::Err;
256
257    fn try_from(value: &str) -> Result<Self, Self::Error> {
258        Self::from_str(value)
259    }
260}
261
262impl Serialize for Dependency {
263    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
264        serializer.collect_str(self)
265    }
266}
267
268impl<'de> Deserialize<'de> for Dependency {
269    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
270        deserializer.deserialize_str(TryFromStringVisitor::new())
271    }
272}