use crate::{
args::Fraction,
data_tree::{DataTree, DataTreeReflection},
fs_tree_builder::FsTreeBuilder,
json_data::{BinaryVersion, JsonData, SchemaVersion, UnitAndTree},
os_string_display::OsStringDisplay,
reporter::ParallelReporter,
runtime_error::RuntimeError,
size::Size,
status_board::GLOBAL_STATUS_BOARD,
visualizer::{BarAlignment, ColumnWidthDistribution, Direction, Visualizer},
};
use serde::Serialize;
use std::{fs::Metadata, io::stdout, iter::once, num::NonZeroUsize, path::PathBuf};
pub struct Sub<Data, GetData, Report>
where
Data: Size + Into<u64> + Serialize + Send + Sync,
Report: ParallelReporter<Data> + Sync,
GetData: Fn(&Metadata) -> Data + Copy + Sync,
DataTreeReflection<String, Data>: Into<UnitAndTree>,
{
pub files: Vec<PathBuf>,
pub json_output: bool,
pub bytes_format: Data::DisplayFormat,
pub direction: Direction,
pub bar_alignment: BarAlignment,
pub column_width_distribution: ColumnWidthDistribution,
pub max_depth: NonZeroUsize,
pub get_data: GetData,
pub reporter: Report,
pub min_ratio: Fraction,
pub no_sort: bool,
}
impl<Data, GetData, Report> Sub<Data, GetData, Report>
where
Data: Size + Into<u64> + Serialize + Send + Sync,
Report: ParallelReporter<Data> + Sync,
GetData: Fn(&Metadata) -> Data + Copy + Sync,
DataTreeReflection<String, Data>: Into<UnitAndTree>,
{
pub fn run(self) -> Result<(), RuntimeError> {
let Sub {
files,
json_output,
bytes_format,
direction,
bar_alignment,
column_width_distribution,
max_depth,
get_data,
reporter,
min_ratio,
no_sort,
} = self;
let mut iter = files
.into_iter()
.map(|root| -> DataTree<OsStringDisplay, Data> {
FsTreeBuilder {
reporter: &reporter,
root,
get_data,
}
.into()
});
let data_tree = if let Some(data_tree) = iter.next() {
data_tree
} else {
return Sub {
files: vec![".".into()],
reporter,
..self
}
.run();
};
let data_tree = if iter.len() == 0 {
data_tree
} else {
let children: Vec<_> = once(data_tree).chain(iter).collect();
DataTree::dir(
OsStringDisplay::os_string_from("(total)"),
Data::default(),
children,
)
};
if reporter.destroy().is_err() {
eprintln!("[warning] Failed to destroy the thread that reports progress");
}
let min_ratio: f32 = min_ratio.into();
let data_tree = {
let mut data_tree = data_tree;
if min_ratio > 0.0 {
data_tree.par_cull_insignificant_data(min_ratio);
}
if !no_sort {
data_tree.par_sort_by(|left, right| left.data().cmp(&right.data()).reverse());
}
data_tree
};
GLOBAL_STATUS_BOARD.clear_line(0);
if json_output {
let unit_and_tree: UnitAndTree = data_tree
.into_reflection() .par_convert_names_to_utf8() .expect("convert all names from raw string to UTF-8")
.into();
let json_data = JsonData {
schema_version: SchemaVersion,
binary_version: Some(BinaryVersion::current()),
unit_and_tree,
};
return serde_json::to_writer(stdout(), &json_data)
.map_err(RuntimeError::SerializationFailure);
}
let visualizer = Visualizer {
data_tree: &data_tree,
bytes_format,
direction,
bar_alignment,
column_width_distribution,
max_depth,
};
print!("{}", visualizer); Ok(())
}
}