parallel_disk_usage/
fs_tree_builder.rs1use super::{
2 data_tree::DataTree,
3 get_size::GetSize,
4 os_string_display::OsStringDisplay,
5 reporter::{error_report::Operation::*, ErrorReport, Event, Reporter},
6 size,
7 tree_builder::{Info, TreeBuilder},
8};
9use pipe_trait::Pipe;
10use std::{
11 fs::{read_dir, symlink_metadata},
12 path::PathBuf,
13};
14
15#[derive(Debug)]
37pub struct FsTreeBuilder<Size, SizeGetter, Report>
38where
39 Report: Reporter<Size> + Sync,
40 Size: size::Size + Send + Sync,
41 SizeGetter: GetSize<Size = Size> + Sync,
42{
43 pub root: PathBuf,
45 pub size_getter: SizeGetter,
47 pub reporter: Report,
49 pub max_depth: u64,
51}
52
53impl<Size, SizeGetter, Report> From<FsTreeBuilder<Size, SizeGetter, Report>>
54 for DataTree<OsStringDisplay, Size>
55where
56 Report: Reporter<Size> + Sync,
57 Size: size::Size + Send + Sync,
58 SizeGetter: GetSize<Size = Size> + Sync,
59{
60 fn from(builder: FsTreeBuilder<Size, SizeGetter, Report>) -> Self {
62 let FsTreeBuilder {
63 root,
64 size_getter,
65 reporter,
66 max_depth,
67 } = builder;
68
69 TreeBuilder::<PathBuf, OsStringDisplay, Size, _, _> {
70 name: OsStringDisplay::os_string_from(&root),
71
72 path: root,
73
74 get_info: |path| {
75 let stats = match symlink_metadata(path) {
76 Err(error) => {
77 reporter.report(Event::EncounterError(ErrorReport {
78 operation: SymlinkMetadata,
79 path,
80 error,
81 }));
82 return Info {
83 size: Size::default(),
84 children: Vec::new(),
85 };
86 }
87 Ok(stats) => stats,
88 };
89
90 let children: Vec<_> = if stats.file_type().is_dir() {
91 match read_dir(path) {
92 Err(error) => {
93 reporter.report(Event::EncounterError(ErrorReport {
94 operation: ReadDirectory,
95 path,
96 error,
97 }));
98 return Info::default();
99 }
100 Ok(entries) => entries,
101 }
102 .filter_map(|entry| match entry {
103 Err(error) => {
104 reporter.report(Event::EncounterError(ErrorReport {
105 operation: AccessEntry,
106 path,
107 error,
108 }));
109 None
110 }
111 Ok(entry) => entry.file_name().pipe(OsStringDisplay::from).pipe(Some),
112 })
113 .collect()
114 } else {
115 Vec::new()
116 };
117
118 let size = size_getter.get_size(&stats);
119 reporter.report(Event::ReceiveData(size));
120
121 Info { size, children }
122 },
123
124 join_path: |prefix, name| prefix.join(&name.0),
125
126 max_depth,
127 }
128 .into()
129 }
130}