1use std::fmt;
2use std::path::{Path, PathBuf};
3
4macro_rules! change_impl {
5 (
6 $(($kind:ident, $as_kind:ident, $is_kind:ident)),*
7 $(,)?
8 ) => {
9 impl Change {
10 $(
11 #[inline]
12 pub fn $as_kind(&self) -> Option<&$kind> {
13 match &self {
14 Self::$kind(change) => Some(change),
15 _ => None,
16 }
17 }
18
19 #[inline]
20 pub const fn $is_kind(&self) -> bool {
21 self.kind().$is_kind()
22 }
23 )*
24 }
25 };
26}
27
28macro_rules! change_kind_impl {
29 (
30 $kind:ident =>
31 $($field:ident),*
32 $(,)?
33 ) => {
34 impl $kind {
35 #[inline]
36 pub const fn kind(&self) -> ChangeKind {
37 ChangeKind::$kind
38 }
39
40 $(
41 change_kind_impl!(@expand $field);
42 )*
43 }
44 };
45
46 (@expand path) => {
47 #[inline]
49 pub fn path(&self) -> &Path {
50 &self.path.as_path()
51 }
52
53 #[inline]
55 pub fn into_path(self) -> PathBuf {
56 self.path
57 }
58 };
59
60 (@expand paths) => {
61 #[inline]
63 pub fn old_path(&self) -> &Path {
64 &self.old_path.as_path()
65 }
66
67 #[doc(alias = "path")]
69 #[inline]
70 pub fn new_path(&self) -> &Path {
71 &self.new_path.as_path()
72 }
73
74 #[inline]
76 pub fn paths(&self) -> (&Path, &Path) {
77 (self.old_path.as_path(), self.new_path.as_path())
78 }
79
80 #[inline]
82 pub fn into_paths(self) -> (PathBuf, PathBuf) {
83 (self.old_path, self.new_path)
84 }
85
86 #[doc(alias = "new_path")]
87 #[inline]
88 fn path(&self) -> &Path {
89 &self.new_path.as_path()
90 }
91
92 #[inline]
93 fn into_path(self) -> PathBuf {
94 self.new_path
95 }
96 };
97
98 (@expand size) => {
99 #[inline]
101 pub const fn size(&self) -> usize {
102 self.size
103 }
104 };
105
106 (@expand sizes) => {
107 #[inline]
109 pub const fn old_size(&self) -> usize {
110 self.old_size
111 }
112
113 #[doc(alias = "size")]
115 #[inline]
116 pub const fn new_size(&self) -> usize {
117 self.new_size
118 }
119
120 #[inline]
122 pub fn sizes(&self) -> (usize, usize) {
123 (self.old_size, self.new_size)
124 }
125
126 #[inline]
127 const fn size(&self) -> usize {
128 self.new_size
129 }
130 };
131}
132
133macro_rules! change {
134 (
135 $self:ident,
136 $change:ident => $expr:expr
137 ) => {
138 match $self {
139 Self::Added($change) => $expr,
140 Self::Modified($change) => $expr,
141 Self::Deleted($change) => $expr,
142 Self::Renamed($change) => $expr,
143 }
144 };
145}
146
147#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
148pub enum ChangeKind {
149 Added,
150 Modified,
151 Deleted,
152 Renamed,
153}
154
155impl ChangeKind {
156 #[inline]
163 pub const fn letter(self) -> char {
164 match self {
165 Self::Added => 'A',
166 Self::Modified => 'M',
167 Self::Deleted => 'D',
168 Self::Renamed => 'R',
169 }
170 }
171
172 #[inline]
179 pub const fn symbol(self) -> char {
180 match self {
181 Self::Added => '+',
182 Self::Modified => '~',
183 Self::Deleted => '-',
184 Self::Renamed => '>',
185 }
186 }
187
188 #[inline]
189 pub const fn is_added(self) -> bool {
190 matches!(self, Self::Added)
191 }
192
193 #[inline]
194 pub const fn is_modified(self) -> bool {
195 matches!(self, Self::Modified)
196 }
197
198 #[inline]
199 pub const fn is_deleted(self) -> bool {
200 matches!(self, Self::Deleted)
201 }
202
203 #[inline]
204 pub const fn is_renamed(self) -> bool {
205 matches!(self, Self::Renamed)
206 }
207}
208
209impl fmt::Display for ChangeKind {
210 #[inline]
211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212 self.letter().fmt(f)
213 }
214}
215
216#[derive(PartialEq, Eq, Clone, Debug)]
217pub enum Change {
218 Added(Added),
219 Modified(Modified),
220 Deleted(Deleted),
221 Renamed(Renamed),
222}
223
224impl Change {
225 #[inline]
226 pub const fn kind(&self) -> ChangeKind {
227 match self {
228 Self::Added(_) => ChangeKind::Added,
229 Self::Modified(_) => ChangeKind::Modified,
230 Self::Deleted(_) => ChangeKind::Deleted,
231 Self::Renamed(_) => ChangeKind::Renamed,
232 }
233 }
234
235 #[doc(alias = "new_path")]
237 #[inline]
238 pub fn path(&self) -> &Path {
239 change!(self, change => change.path())
240 }
241
242 #[inline]
244 pub fn into_path(self) -> PathBuf {
245 change!(self, change => change.into_path())
246 }
247
248 #[inline]
253 pub fn old_path(&self) -> Option<&Path> {
254 match self {
255 Self::Renamed(change) => Some(change.old_path()),
256 _ => None,
257 }
258 }
259
260 #[inline]
265 pub fn paths(&self) -> (Option<&Path>, &Path) {
266 match self {
267 Self::Added(change) => (None, change.path()),
268 Self::Modified(change) => (None, change.path()),
269 Self::Deleted(change) => (None, change.path()),
270 Self::Renamed(change) => {
271 let (old_path, new_path) = change.paths();
272 (Some(old_path), new_path)
273 }
274 }
275 }
276
277 #[inline]
282 pub fn into_paths(self) -> (Option<PathBuf>, PathBuf) {
283 match self {
284 Self::Added(change) => (None, change.into_path()),
285 Self::Modified(change) => (None, change.into_path()),
286 Self::Deleted(change) => (None, change.into_path()),
287 Self::Renamed(change) => {
288 let (old_path, new_path) = change.into_paths();
289 (Some(old_path), new_path)
290 }
291 }
292 }
293
294 #[doc(alias = "new_size")]
296 #[inline]
297 pub const fn size(&self) -> usize {
298 change!(self, change => change.size())
299 }
300
301 #[inline]
306 pub const fn old_size(&self) -> Option<usize> {
307 match self {
308 Self::Modified(change) => Some(change.old_size()),
309 _ => None,
310 }
311 }
312
313 #[inline]
318 pub const fn sizes(&self) -> (Option<usize>, usize) {
319 match self {
320 Self::Added(change) => (None, change.size()),
321 Self::Modified(change) => (Some(change.old_size()), change.size()),
322 Self::Deleted(change) => (None, change.size()),
323 Self::Renamed(change) => (None, change.size()),
324 }
325 }
326}
327
328change_impl!(
329 (Added, as_added, is_added),
330 (Modified, as_modified, is_modified),
331 (Deleted, as_deleted, is_deleted),
332 (Renamed, as_renamed, is_renamed),
333);
334
335#[derive(PartialEq, Eq, Clone, Debug)]
336pub struct Added {
337 pub(crate) path: PathBuf,
339 pub(crate) size: usize,
341}
342
343#[derive(PartialEq, Eq, Clone, Debug)]
344pub struct Modified {
345 pub(crate) path: PathBuf,
347 pub(crate) old_size: usize,
349 pub(crate) new_size: usize,
351}
352
353#[derive(PartialEq, Eq, Clone, Debug)]
354pub struct Deleted {
355 pub(crate) path: PathBuf,
357 pub(crate) size: usize,
359}
360
361#[derive(PartialEq, Eq, Clone, Debug)]
362pub struct Renamed {
363 pub(crate) old_path: PathBuf,
365 pub(crate) new_path: PathBuf,
367 pub(crate) size: usize,
369}
370
371change_kind_impl!(Added => path, size);
372change_kind_impl!(Modified => path, sizes);
373change_kind_impl!(Deleted => path, size);
374change_kind_impl!(Renamed => paths, size);
375
376impl fmt::Display for Change {
377 #[inline]
378 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379 match self {
380 Self::Added(change) => change.fmt(f),
381 Self::Modified(change) => change.fmt(f),
382 Self::Deleted(change) => change.fmt(f),
383 Self::Renamed(change) => change.fmt(f),
384 }
385 }
386}
387
388impl fmt::Display for Added {
389 #[inline]
390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391 write!(
392 f,
393 "{} {} ({} bytes)",
394 ChangeKind::Added,
395 self.path.display(),
396 self.size,
397 )
398 }
399}
400
401impl fmt::Display for Modified {
402 #[inline]
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404 write!(
405 f,
406 "{} {} ({} -> {} bytes)",
407 ChangeKind::Modified,
408 self.path.display(),
409 self.old_size,
410 self.new_size,
411 )
412 }
413}
414
415impl fmt::Display for Deleted {
416 #[inline]
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 write!(
419 f,
420 "{} {} ({} bytes)",
421 ChangeKind::Deleted,
422 self.path.display(),
423 self.size,
424 )
425 }
426}
427
428impl fmt::Display for Renamed {
429 #[inline]
430 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
431 write!(
432 f,
433 "{} {} -> {} ({} bytes)",
434 ChangeKind::Added,
435 self.old_path.display(),
436 self.new_path.display(),
437 self.size,
438 )
439 }
440}
441
442impl From<Added> for Change {
443 #[inline]
444 fn from(change: Added) -> Self {
445 Self::Added(change)
446 }
447}
448
449impl From<Modified> for Change {
450 #[inline]
451 fn from(change: Modified) -> Self {
452 Self::Modified(change)
453 }
454}
455
456impl From<Deleted> for Change {
457 #[inline]
458 fn from(change: Deleted) -> Self {
459 Self::Deleted(change)
460 }
461}
462
463impl From<Renamed> for Change {
464 #[inline]
465 fn from(change: Renamed) -> Self {
466 Self::Renamed(change)
467 }
468}