use std::collections::HashSet;
use crate::lib::logic::{
AnchoredPathsDatum,
PattEnvIndex,
PatternsToApply,
ScannedToApply,
TabColumn,
TabPathStructure,
TabSortBy,
TabSortOrder,
TabSpec,
TableData,
TableOutput,
};
pub trait MatchLabel {
fn label() -> &'static str;
}
#[derive(Debug, Clone)]
pub struct Matched;
#[derive(Debug, Clone)]
pub struct Mismatched;
impl MatchLabel for Matched {
fn label() -> &'static str { "✔" } }
impl MatchLabel for Mismatched {
fn label() -> &'static str { "✖" } }
#[derive(Debug, Clone)]
pub struct Partition<L: MatchLabel> {
pub paths: Vec<String>,
pub label: &'static str,
pub entry: AnchoredPathsDatum,
pub _marker: std::marker::PhantomData<L>,
}
struct EnvIndex<'a> {
pub dirs: HashSet<&'a str>,
pub files: Vec<&'a str>,
}
impl<'a> PattEnvIndex for EnvIndex<'a> {
fn has_dir(&self, dir: &str) -> bool { self.dirs.contains(dir) }
fn has_file_with_prefix(&self, prefix: &str) -> bool {
let start = self.files.partition_point(|&f| f < prefix);
start < self.files.len() && self.files[start].starts_with(prefix)
}
fn any_file_in_dir(&self, dir: &str, check: &mut dyn FnMut(&str) -> bool) -> bool {
let start = self.files.partition_point(|&f| f < dir);
for &f in &self.files[start..] {
if !f.starts_with(dir) {
break;
}
if check(f) {
return true;
}
}
false
}
}
#[derive(Debug, Clone)]
pub struct PartitioningResult {
pub scanner: ScannedToApply,
pub patterns: PatternsToApply,
pub m: Partition<Matched>,
pub x: Partition<Mismatched>,
pub spec: TabSpec,
}
impl PartitioningResult {
pub fn new(scanner: ScannedToApply, patterns: PatternsToApply) -> Self {
let env_index = EnvIndex {
dirs: scanner.dirs.iter().map(|n| n.str.as_str()).collect(),
files: scanner.files.iter().map(|n| n.str.as_str()).collect(),
};
let mut m_vec = Vec::new();
let mut x_vec = Vec::new();
let all_paths = scanner.files.iter().chain(scanner.dirs.iter());
for node in all_paths {
let p = node.str.as_str();
if patterns.is_match(p, &env_index) {
m_vec.push(node.str.clone());
} else {
x_vec.push(node.str.clone());
}
}
let entry = scanner.stat.relation.clone();
Self {
scanner,
patterns,
m: Partition {
paths: m_vec,
label: Matched::label(),
entry: entry.clone(),
_marker: std::marker::PhantomData,
},
x: Partition { paths: x_vec, label: Mismatched::label(), entry, _marker: std::marker::PhantomData },
spec: TabSpec::default(),
}
}
pub fn sort(mut self, by: TabSortBy, order: TabSortOrder, structure: TabPathStructure) -> Self {
self.spec = self.spec.sort(by, order, structure);
self
}
pub fn columns(mut self, cols: &[TabColumn]) -> Self {
self.spec = self.spec.columns(cols);
self
}
pub fn trim(mut self, size: usize, page: Option<usize>) -> Self {
self.spec = self.spec.trim(size, page);
self
}
pub fn build_matched(&self) -> TableOutput {
TableData::gather(&self.m)
.sort(self.spec.sort_by, self.spec.sort_order, self.spec.structure)
.into_output(&self.spec)
}
pub fn build_mismatched(&self) -> TableOutput {
TableData::gather(&self.x)
.sort(self.spec.sort_by, self.spec.sort_order, self.spec.structure)
.into_output(&self.spec)
}
}