this repo has no description
1use humansize::{format_size, DECIMAL};
2use std::{cmp::Ordering, fmt::Display};
3
4use super::{
5 parser::DiffPackage,
6 versioning::{Version, VersionComponent, VersionList},
7};
8
9#[derive(Default, Debug, PartialEq, Eq)]
10pub enum DiffType {
11 Added,
12 Removed,
13 Changed,
14
15 #[default]
16 Unknown,
17}
18
19#[derive(Debug)]
20pub struct Package {
21 pub size_delta: SizeDelta,
22 pub diff_type: DiffType,
23
24 pub versions_before: VersionList,
25 pub versions_after: VersionList,
26}
27
28#[derive(Debug)]
29pub struct SizeDelta(pub i64);
30
31impl DiffType {
32 pub fn from_versions(before: &[String], after: &[String]) -> DiffType {
33 match (before.is_empty(), after.is_empty()) {
34 (true, false) => DiffType::Added,
35 (false, true) => DiffType::Removed,
36 (false, false) => DiffType::Changed,
37 (true, true) => DiffType::Unknown, // should be unreachable but I'm not sure
38 }
39 }
40}
41
42impl Display for Package {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 match self.diff_type {
45 DiffType::Added => {
46 write!(f, "{}", self.versions_after)?;
47 }
48 DiffType::Removed => {
49 write!(f, "{}", self.versions_before)?;
50 }
51 DiffType::Changed => {
52 write!(f, "{} -> {}", self.versions_before, self.versions_after)?;
53 }
54 DiffType::Unknown => unreachable!(),
55 }
56
57 Ok(())
58 }
59}
60
61impl From<DiffPackage> for Package {
62 fn from(diff: DiffPackage) -> Self {
63 let diff_type = DiffType::from_versions(&diff.versions_before, &diff.versions_after);
64
65 let (parsed_before, parsed_after) = match diff_type {
66 DiffType::Added => handle_diff_added(&diff.versions_after),
67 DiffType::Removed => handle_diff_removed(&diff.versions_before),
68 DiffType::Changed => handle_diff_changed(&diff.versions_before, &diff.versions_after),
69 DiffType::Unknown => unreachable!(),
70 };
71
72 Package {
73 size_delta: diff.size_delta.into(),
74 versions_before: parsed_before,
75 versions_after: parsed_after,
76 diff_type,
77 }
78 }
79}
80
81fn handle_diff_added(versions_after: &[String]) -> (VersionList, VersionList) {
82 let after = to_version_list(versions_after, Ordering::Greater);
83 (VersionList::new(), after)
84}
85
86fn handle_diff_removed(versions_before: &[String]) -> (VersionList, VersionList) {
87 let before = to_version_list(versions_before, Ordering::Less);
88 (before, VersionList::new())
89}
90
91fn to_version_list(versions: &[String], order: Ordering) -> VersionList {
92 let mut version_list = VersionList::new();
93
94 for before in versions {
95 let parts_before = before.split('.').map(String::from);
96 let mut version = Version::new();
97 for part in parts_before {
98 version.push(VersionComponent::new(part, order));
99 }
100 version_list.push(version);
101 }
102
103 version_list
104}
105
106fn handle_diff_changed(
107 versions_before: &[String],
108 versions_after: &[String],
109) -> (VersionList, VersionList) {
110 let mut parsed_before = VersionList::new();
111 let mut parsed_after = VersionList::new();
112
113 for (before, after) in versions_before.iter().zip(versions_after.iter()) {
114 let mut parts_before = before.split('.').map(String::from).collect::<Vec<_>>();
115 let mut parts_after = after.split('.').map(String::from).collect::<Vec<_>>();
116
117 let max_len = parts_before.len().max(parts_after.len());
118 parts_before.resize(max_len, String::new());
119 parts_after.resize(max_len, String::new());
120
121 let mut ordering = Ordering::Equal;
122
123 let mut line_before = Version::new();
124 let mut line_after = Version::new();
125
126 for (b, a) in parts_before.into_iter().zip(parts_after.into_iter()) {
127 if ordering == Ordering::Equal {
128 ordering = b.cmp(&a);
129 }
130 line_before.push(VersionComponent::new(b, ordering));
131 line_after.push(VersionComponent::new(a, ordering.reverse()));
132 }
133
134 parsed_before.push(line_before);
135 parsed_after.push(line_after);
136 }
137
138 (parsed_before, parsed_after)
139}
140
141impl std::fmt::Display for SizeDelta {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 let sign = if self.0 >= 0 { "+" } else { "-" };
144 let size: u64 = self.0.abs().try_into().unwrap_or(0);
145 write!(f, "{sign}{}", format_size(size, DECIMAL))
146 }
147}
148
149impl From<i64> for SizeDelta {
150 fn from(size: i64) -> Self {
151 SizeDelta(size)
152 }
153}