use super::{
Relation,
pest::{DependencyParser, Rule},
};
use crate::{architecture, build_profile, version};
use pest::{Parser, error::Error as PestError, iterators::Pair};
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq, Default)]
pub struct Dependency {
pub relations: Vec<Relation>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Error {
Parse((String, pest::error::InputLocation)),
InvalidPackage,
InvalidVersion(version::Error),
InvalidVersionConstraint,
InvalidArch(architecture::Error),
InvalidBuildProfile(build_profile::Error),
InvalidArchConstraint,
InvalidBuildProfileConstraint,
TooManyVersions,
TooManyArches,
}
impl From<architecture::Error> for Error {
fn from(err: architecture::Error) -> Self {
Error::InvalidArch(err)
}
}
impl From<version::Error> for Error {
fn from(err: version::Error) -> Self {
Error::InvalidVersion(err)
}
}
impl From<build_profile::Error> for Error {
fn from(err: build_profile::Error) -> Self {
Error::InvalidBuildProfile(err)
}
}
impl From<PestError<Rule>> for Error {
fn from(err: PestError<Rule>) -> Self {
Error::Parse((err.variant.message().into(), err.location))
}
}
impl std::fmt::Display for Dependency {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"{}",
self.relations
.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(", ")
)
}
}
impl TryFrom<Pair<'_, Rule>> for Dependency {
type Error = Error;
fn try_from(token: Pair<'_, Rule>) -> Result<Self, Error> {
let mut ret = Dependency { relations: vec![] };
for relation in token.into_inner() {
match relation.as_rule() {
Rule::relation => {}
_ => continue,
};
ret.relations.push(relation.try_into()?);
}
Ok(ret)
}
}
impl FromStr for Dependency {
type Err = Error;
fn from_str(v: &str) -> Result<Self, Error> {
let Some(token) = DependencyParser::parse(Rule::dependency, v)?.next() else {
return Ok(Dependency { relations: vec![] });
};
token.try_into()
}
}
#[cfg(feature = "serde")]
mod serde {
use super::Dependency;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
impl Serialize for Dependency {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
String::serialize(&self.to_string(), serializer)
}
}
impl<'de> Deserialize<'de> for Dependency {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let s = String::deserialize(d)?;
s.parse().map_err(|e| D::Error::custom(format!("{e:?}")))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::control;
use std::io::{BufReader, Cursor};
#[test]
fn serde_dependency() {
#[derive(Clone, Debug, PartialEq, Deserialize)]
struct Test {
#[serde(rename = "Deps")]
deps: Dependency,
}
let test: Test = control::de::from_reader(&mut BufReader::new(Cursor::new(
"\
Deps: foo, bar | baz
",
)))
.unwrap();
assert_eq!(test.deps.relations.len(), 2);
}
}
}