Skip to content

Commit 84b2321

Browse files
committed
perf!: do not create copies of dir entries
1 parent d2719ec commit 84b2321

3 files changed

Lines changed: 35 additions & 26 deletions

File tree

src/fs_tree_builder.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use super::{
66
size,
77
tree_builder::{Info, TreeBuilder},
88
};
9+
use pipe_trait::Pipe;
910
use std::{
1011
fs::{read_dir, symlink_metadata},
1112
path::PathBuf,
@@ -65,51 +66,55 @@ where
6566
max_depth,
6667
} = builder;
6768

68-
TreeBuilder::<PathBuf, OsStringDisplay, Size, _, _> {
69+
TreeBuilder::<PathBuf, _, Size, _, _> {
6970
name: OsStringDisplay::os_string_from(&root),
7071

7172
path: root,
7273

7374
get_info: |path| {
75+
let make_info = |size: Size, children: Option<_>| Info {
76+
size,
77+
children: children.into_iter().flatten(),
78+
};
79+
80+
let empty_info = || make_info(Size::default(), None);
81+
7482
let stats = match symlink_metadata(path) {
7583
Err(error) => {
7684
reporter.report(Event::EncounterError(ErrorReport {
7785
operation: SymlinkMetadata,
7886
path,
7987
error,
8088
}));
81-
return Info {
82-
size: Size::default(),
83-
children: Vec::new(),
84-
};
89+
return empty_info();
8590
}
8691
Ok(stats) => stats,
8792
};
8893

89-
let children: Vec<_> = if stats.is_dir() {
94+
let children = if stats.is_dir() {
9095
match read_dir(path) {
9196
Err(error) => {
9297
reporter.report(Event::EncounterError(ErrorReport {
9398
operation: ReadDirectory,
9499
path,
95100
error,
96101
}));
97-
return Info::default();
102+
return empty_info();
98103
}
99104
Ok(entries) => entries,
100105
}
101106
.flatten()
102107
.map(|entry| entry.file_name())
103108
.map(OsStringDisplay::from)
104-
.collect()
109+
.pipe(Some)
105110
} else {
106-
Vec::new()
111+
None
107112
};
108113

109114
let size = size_getter.get_size(&stats);
110115
reporter.report(Event::ReceiveData(size));
111116

112-
Info { size, children }
117+
make_info(size, children)
113118
},
114119

115120
join_path: |prefix, name| prefix.join(&name.0),

src/tree_builder.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,20 @@ use rayon::prelude::*;
77

88
/// Collection of functions and starting points in order to build a [`DataTree`] with [`From`] or [`Into`].
99
#[derive(Debug)]
10-
pub struct TreeBuilder<Path, Name, Size, GetInfo, JoinPath>
10+
pub struct TreeBuilder<Path, NameIter, Size, GetInfo, JoinPath>
1111
where
1212
Path: Send + Sync,
13-
Name: Send + Sync,
14-
GetInfo: Fn(&Path) -> Info<Name, Size> + Copy + Send + Sync,
15-
JoinPath: Fn(&Path, &Name) -> Path + Copy + Send + Sync,
13+
NameIter: IntoIterator,
14+
NameIter::IntoIter: Send,
15+
NameIter::Item: Send,
16+
GetInfo: Fn(&Path) -> Info<NameIter, Size> + Copy + Send + Sync,
17+
JoinPath: Fn(&Path, &NameIter::Item) -> Path + Copy + Send + Sync,
1618
Size: size::Size + Send,
1719
{
1820
/// Path to the root.
1921
pub path: Path,
2022
/// Name of the root.
21-
pub name: Name,
23+
pub name: NameIter::Item,
2224
/// Function to extract necessary information from `path` (`size` and `children`).
2325
pub get_info: GetInfo,
2426
/// Function to join parent's `path` with a child's name to make the child's `name`.
@@ -27,17 +29,19 @@ where
2729
pub max_depth: u64,
2830
}
2931

30-
impl<Path, Name, Size, GetInfo, JoinPath> From<TreeBuilder<Path, Name, Size, GetInfo, JoinPath>>
31-
for DataTree<Name, Size>
32+
impl<Path, NameIter, Size, GetInfo, JoinPath>
33+
From<TreeBuilder<Path, NameIter, Size, GetInfo, JoinPath>> for DataTree<NameIter::Item, Size>
3234
where
3335
Path: Send + Sync,
34-
Name: Send + Sync,
35-
GetInfo: Fn(&Path) -> Info<Name, Size> + Copy + Send + Sync,
36-
JoinPath: Fn(&Path, &Name) -> Path + Copy + Send + Sync,
36+
NameIter: IntoIterator,
37+
NameIter::IntoIter: Send,
38+
NameIter::Item: Send,
39+
GetInfo: Fn(&Path) -> Info<NameIter, Size> + Copy + Send + Sync,
40+
JoinPath: Fn(&Path, &NameIter::Item) -> Path + Copy + Send + Sync,
3741
Size: size::Size + Send,
3842
{
3943
/// Create a [`DataTree`] from a [`TreeBuilder`].
40-
fn from(builder: TreeBuilder<Path, Name, Size, GetInfo, JoinPath>) -> Self {
44+
fn from(builder: TreeBuilder<Path, NameIter, Size, GetInfo, JoinPath>) -> Self {
4145
let TreeBuilder {
4246
path,
4347
name,
@@ -50,7 +54,8 @@ where
5054
let max_depth = max_depth.saturating_sub(1);
5155

5256
let children = children
53-
.into_par_iter()
57+
.into_iter()
58+
.par_bridge()
5459
.map(|name| TreeBuilder {
5560
path: join_path(&path, &name),
5661
name,

src/tree_builder/info.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
use crate::size;
22
use derive_more::From;
3-
use smart_default::SmartDefault;
43

54
/// Information to return from `get_info` of [`super::TreeBuilder`].
6-
#[derive(Debug, SmartDefault, From)]
7-
pub struct Info<Name, Size: size::Size> {
5+
#[derive(Debug, Default, From)]
6+
pub struct Info<NameIter, Size: size::Size> {
87
/// Size associated with given `path`.
98
pub size: Size,
109
/// Direct descendants of given `path`.
11-
pub children: Vec<Name>, // TODO: change this into an iterator
10+
pub children: NameIter,
1211
}

0 commit comments

Comments
 (0)