Skip to content

Commit 6cd0287

Browse files
committed
feat(api): obscure container type
1 parent b58bfd6 commit 6cd0287

5 files changed

Lines changed: 105 additions & 14 deletions

File tree

src/app/sub.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,10 +199,11 @@ where
199199
data_tree: &mut DataTree<OsStringDisplay, Size>,
200200
record: Self::HardlinkRecord,
201201
) -> Result<Self::DeduplicationReport, RuntimeError> {
202-
use std::path::{Path, PathBuf};
203-
let hardlink_info: Box<[(Size, Vec<PathBuf>)]> = record
202+
use crate::hardlink::LinkPathList;
203+
use std::path::Path;
204+
let hardlink_info: Box<[(Size, LinkPathList)]> = record
204205
.iter()
205-
.map(|values| (*values.size(), values.links().to_vec()))
206+
.map(|values| (*values.size(), values.links().clone()))
206207
.collect();
207208
let hardlink_info: Box<[(Size, Vec<&Path>)]> = hardlink_info
208209
.iter()

src/hardlink.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub mod link_path_list;
2+
3+
pub use link_path_list::LinkPathList;

src/hardlink/link_path_list.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use pipe_trait::Pipe;
2+
use std::{iter::FusedIterator, path::PathBuf, slice};
3+
4+
/// List of different hardlinks to the same file.
5+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6+
pub struct LinkPathList(
7+
Vec<PathBuf>, // TODO: benchmark against LinkedList<PathBuf>
8+
);
9+
10+
impl LinkPathList {
11+
/// Create a list of a single path.
12+
pub(crate) fn single(path: PathBuf) -> Self {
13+
LinkPathList(vec![path])
14+
}
15+
16+
/// Add a path to the list.
17+
pub(crate) fn add(&mut self, path: PathBuf) {
18+
self.0.push(path)
19+
}
20+
21+
/// Get the number of paths inside the list.
22+
pub fn len(&self) -> usize {
23+
self.0.len()
24+
}
25+
26+
/// Check whether the list is empty.
27+
pub fn is_empty(&self) -> bool {
28+
self.0.is_empty()
29+
}
30+
31+
/// Iterate over the paths inside the list.
32+
pub fn iter(&self) -> Iter {
33+
self.0.iter().pipe(Iter)
34+
}
35+
}
36+
37+
/// [Iterator] over the paths inside a [`LinkPathList`].
38+
#[derive(Debug, Clone)]
39+
pub struct Iter<'a>(slice::Iter<'a, PathBuf>);
40+
41+
impl<'a> Iterator for Iter<'a> {
42+
type Item = &'a PathBuf;
43+
44+
#[inline]
45+
fn next(&mut self) -> Option<Self::Item> {
46+
self.0.next()
47+
}
48+
49+
#[inline]
50+
fn size_hint(&self) -> (usize, Option<usize>) {
51+
self.0.size_hint()
52+
}
53+
54+
#[inline]
55+
fn count(self) -> usize {
56+
self.0.count()
57+
}
58+
59+
#[inline]
60+
fn nth(&mut self, n: usize) -> Option<Self::Item> {
61+
self.0.nth(n)
62+
}
63+
64+
#[inline]
65+
fn last(self) -> Option<Self::Item> {
66+
self.0.last()
67+
}
68+
}
69+
70+
impl<'a> DoubleEndedIterator for Iter<'a> {
71+
#[inline]
72+
fn next_back(&mut self) -> Option<Self::Item> {
73+
self.0.next_back()
74+
}
75+
76+
#[inline]
77+
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
78+
self.0.nth_back(n)
79+
}
80+
}
81+
82+
impl<'a> ExactSizeIterator for Iter<'a> {
83+
#[inline]
84+
fn len(&self) -> usize {
85+
self.0.len()
86+
}
87+
}
88+
89+
impl FusedIterator for Iter<'_> {}

src/hook/record_hardlink/storage.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
use crate::size;
1+
use crate::{hardlink::LinkPathList, size};
22
use dashmap::{iter::Iter as DashIter, mapref::multiple::RefMulti, DashMap};
33
use derive_more::{Display, Error};
44
use pipe_trait::Pipe;
5-
use std::{
6-
fmt::Debug,
7-
path::{Path, PathBuf},
8-
};
5+
use std::{fmt::Debug, path::Path};
96

107
/// Storage to be used by [`crate::hook::RecordHardLink`].
118
#[derive(Debug, Clone)]
129
pub struct RecordHardLinkStorage<Size>(
1310
/// Map an inode number to its size and detected paths.
14-
DashMap<u64, (Size, Vec<PathBuf>)>, // TODO: benchmark against Mutex<HashMap<u64, (Size, Vec<PathBuf>)>>
11+
DashMap<u64, (Size, LinkPathList)>, // TODO: benchmark against Mutex<HashMap<u64, (Size, LinkPathList)>>
1512
);
1613

1714
impl<Size> RecordHardLinkStorage<Size> {
@@ -62,7 +59,7 @@ where
6259
.and_modify(|(recorded, paths)| {
6360
let (detected, recorded) = (size, *recorded);
6461
if size == recorded {
65-
paths.push(path.to_path_buf());
62+
paths.add(path.to_path_buf());
6663
} else {
6764
size_assertion = Err(SizeConflictError {
6865
ino,
@@ -71,7 +68,7 @@ where
7168
});
7269
}
7370
})
74-
.or_insert_with(|| (size, vec![path.to_path_buf()]));
71+
.or_insert_with(|| (size, path.to_path_buf().pipe(LinkPathList::single)));
7572
size_assertion.map_err(AddError::SizeConflict)
7673
}
7774
}
@@ -80,13 +77,13 @@ where
8077
#[derive(derive_more::Debug)]
8178
#[debug(bound())]
8279
#[debug("Iter(..)")]
83-
pub struct Iter<'a, Size>(DashIter<'a, u64, (Size, Vec<PathBuf>)>);
80+
pub struct Iter<'a, Size>(DashIter<'a, u64, (Size, LinkPathList)>);
8481

8582
/// [Item](Iterator::Item) of [`Iter`].
8683
#[derive(derive_more::Debug)]
8784
#[debug(bound())]
8885
#[debug("IterItem(..)")]
89-
pub struct IterItem<'a, Size>(RefMulti<'a, u64, (Size, Vec<PathBuf>)>);
86+
pub struct IterItem<'a, Size>(RefMulti<'a, u64, (Size, LinkPathList)>);
9087

9188
impl<'a, Size> Iterator for Iter<'a, Size> {
9289
type Item = IterItem<'a, Size>;
@@ -107,7 +104,7 @@ impl<'a, Size> IterItem<'a, Size> {
107104
}
108105

109106
/// Links of the inode.
110-
pub fn links(&self) -> &[PathBuf] {
107+
pub fn links(&self) -> &LinkPathList {
111108
&self.0.value().1
112109
}
113110
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub mod bytes_format;
3333
pub mod data_tree;
3434
pub mod fs_tree_builder;
3535
pub mod get_size;
36+
pub mod hardlink;
3637
pub mod hook;
3738
pub mod json_data;
3839
pub mod os_string_display;

0 commit comments

Comments
 (0)