use std::{
collections::HashMap,
ops::{Add, AddAssign},
str::FromStr,
};
use serde::{Deserialize, Deserializer, de};
use std::path::Path;
use crate::{
error, model::data::DeepData, model::opt::OptionalGroup, model::req::Requirement,
model::stat::StatRange,
};
#[derive(Clone, Debug)]
pub struct Reqfile {
pub general: Vec<Requirement>,
pub post: Vec<Requirement>,
pub final_ranges: Vec<StatRange>,
pub optional: Vec<OptionalGroup>,
pub implicit: HashMap<String, Requirement>,
}
impl Add for Reqfile {
type Output = Reqfile;
fn add(self, rhs: Self) -> Self::Output {
Self {
general: self
.general
.iter()
.chain(rhs.general.iter())
.cloned()
.collect(),
post: self.post.iter().chain(rhs.post.iter()).cloned().collect(),
final_ranges: self
.final_ranges
.iter()
.chain(rhs.final_ranges.iter())
.cloned()
.collect(),
optional: self
.optional
.iter()
.chain(rhs.optional.iter())
.cloned()
.collect(),
implicit: self.implicit.into_iter().chain(rhs.implicit).collect(),
}
}
}
impl AddAssign for Reqfile {
fn add_assign(&mut self, rhs: Self) {
self.general.extend(rhs.general);
self.post.extend(rhs.post);
self.final_ranges.extend(rhs.final_ranges);
self.optional.extend(rhs.optional);
self.implicit.extend(rhs.implicit);
}
}
impl Reqfile {
pub fn parse_str(content: &str) -> error::Result<Self> {
crate::parse::reqfile::parse_reqfile_str(content)
}
pub fn resolve_implicit(&mut self, data: &DeepData) {
self.implicit.extend(data.implicit_requirements());
}
pub fn from_file(path: &Path) -> error::Result<Self> {
crate::parse::reqfile::parse_reqfile(path)
}
#[must_use]
pub fn generate(&self) -> String {
crate::parse::reqfile::gen_reqfile(self)
}
pub fn req_iter(&self) -> impl Iterator<Item = &Requirement> {
self.general.iter().chain(self.post.iter())
}
}
impl FromStr for Reqfile {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::parse::reqfile::parse_reqfile_str(s)
.map_err(|e| format!("Failed to parse requirement: {e}"))
}
}
impl<'de> Deserialize<'de> for Reqfile {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
s.parse().map_err(de::Error::custom)
}
}