use std::{path::Path, sync::Arc};
use crate::{
Change, ChangeType, PackageName,
change::{LoadingError, UniqueId},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ChangeSet {
releases: Vec<Release>,
}
impl ChangeSet {
pub fn from_directory<P: AsRef<Path>>(path: P) -> Result<Self, LoadingError> {
path.as_ref()
.read_dir()?
.filter_map(|entry| {
entry
.map_err(LoadingError::from)
.and_then(|entry| {
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "md") && path.is_file() {
Change::from_file(path).map(Some)
} else {
Ok(None)
}
})
.transpose()
})
.collect()
}
}
impl FromIterator<Change> for ChangeSet {
fn from_iter<T: IntoIterator<Item = Change>>(iter: T) -> Self {
let mut releases = iter
.into_iter()
.flat_map(|change| {
let unique_id = Arc::new(change.unique_id);
let summary: Arc<str> = change.summary.into();
change
.versioning
.into_iter()
.map(move |(package_name, change_type)| {
(
package_name,
PackageChange {
change_type,
unique_id: unique_id.clone(),
summary: summary.clone(),
},
)
})
})
.fold(
Vec::<Release>::new(),
|mut releases, (package_name, change)| {
if let Some(release) = releases
.iter_mut()
.find(|release| release.package_name == package_name)
{
release.changes.push(change);
} else {
releases.push(Release {
package_name,
changes: vec![change],
});
}
releases
},
);
for release in &mut releases {
release
.changes
.sort_by(|first, second| first.unique_id.cmp(&second.unique_id));
}
Self { releases }
}
}
impl IntoIterator for ChangeSet {
type Item = Release;
type IntoIter = std::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.releases.into_iter()
}
}
impl From<ChangeSet> for Vec<Release> {
fn from(value: ChangeSet) -> Vec<Release> {
value.releases
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Release {
pub package_name: PackageName,
pub changes: Vec<PackageChange>,
}
impl Release {
#[must_use]
pub fn change_type(&self) -> Option<&ChangeType> {
self.changes.iter().map(|change| &change.change_type).max()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PackageChange {
pub unique_id: Arc<UniqueId>,
pub change_type: ChangeType,
pub summary: Arc<str>,
}