use std::fs;
use std::path::PathBuf;
use crate::cache::caches::{get_cache_name, RegistrySubCache, RegistrySuperCache};
use rayon::iter::*;
use walkdir::WalkDir;
pub(crate) struct RegistryIndex {
name: String,
path: PathBuf,
size: Option<u64>,
number_of_files: Option<usize>,
files_calculated: bool, files: Vec<PathBuf>,
}
impl RegistrySubCache for RegistryIndex {
fn new(path: PathBuf) -> Self {
Self {
name: get_cache_name(&path),
path,
size: None,
number_of_files: None,
files_calculated: false,
files: vec![],
}
}
fn name(&self) -> &str {
&self.name
}
#[inline]
fn path_exists(&self) -> bool {
self.path().exists()
}
fn path(&self) -> &PathBuf {
&self.path
}
#[inline]
fn invalidate(&mut self) {
self.size = None;
self.files_calculated = false;
self.number_of_files = None;
self.files = vec![];
}
fn known_to_be_empty(&mut self) {
self.size = Some(0);
self.files_calculated = true;
self.number_of_files = Some(0);
self.files = Vec::new();
}
fn total_size(&mut self) -> u64 {
match self.size {
Some(size) => size,
None => {
if self.path.is_dir() {
let total_size = self
.files()
.par_iter()
.filter(|f| f.is_file())
.map(|f| {
fs::metadata(f)
.unwrap_or_else(|_| panic!("Failed to get size of file: '{:?}'", f))
.len()
})
.sum();
self.size = Some(total_size);
total_size
} else {
self.known_to_be_empty();
0
}
}
}
}
fn files(&mut self) -> &[PathBuf] {
if self.files_calculated {
} else if self.path_exists() {
let walkdir = WalkDir::new(self.path.display().to_string());
let vec = walkdir
.into_iter()
.map(|direntry| direntry.unwrap().into_path())
.collect::<Vec<PathBuf>>();
self.number_of_files = Some(vec.len());
self.files = vec;
self.files_calculated = true;
} else {
self.known_to_be_empty();
}
&self.files
}
fn number_of_files(&mut self) -> usize {
if let Some(number) = self.number_of_files {
number
} else {
let _ = self.files();
if let Some(n) = self.number_of_files {
n
} else {
unreachable!();
}
}
}
fn files_sorted(&mut self) -> &[PathBuf] {
let _ = self.files(); self.files.sort();
self.files()
}
fn items(&mut self) -> &[PathBuf] {
&[]
}
fn number_of_items(&mut self) -> usize {
0
}
}
pub(crate) struct RegistryIndicesCache {
#[allow(unused)]
path: PathBuf,
indices: Vec<RegistryIndex>,
#[allow(unused)]
number_of_indices: usize,
total_size: Option<u64>,
total_number_of_files: Option<usize>,
indices_paths: Vec<PathBuf>,
}
impl RegistrySuperCache for RegistryIndicesCache {
type SubCache = RegistryIndex;
fn new(path: PathBuf) -> Self {
if !path.exists() {
return Self {
path,
number_of_indices: 0,
indices: vec![],
total_number_of_files: None,
total_size: None,
indices_paths: Vec::new(),
};
}
let indices_dirs = std::fs::read_dir(&path)
.unwrap_or_else(|_| panic!("failed to read directory {}", path.display()));
#[allow(clippy::manual_filter_map)]
let indices = indices_dirs
.map(|direntry| direntry.unwrap().path())
.filter(|p| p.is_dir() && p.file_name().unwrap().to_str().unwrap().contains('-'))
.map(RegistryIndex::new)
.collect::<Vec<RegistryIndex>>();
Self {
path,
number_of_indices: indices.len(),
indices,
total_number_of_files: None,
total_size: None,
indices_paths: Vec::new(),
}
}
fn caches(&mut self) -> &mut Vec<Self::SubCache> {
&mut self.indices
}
fn invalidate(&mut self) {
self.number_of_indices = 0;
self.total_size = None;
self.total_number_of_files = None;
self.indices
.iter_mut()
.for_each(RegistrySubCache::invalidate);
}
fn files(&mut self) -> Vec<PathBuf> {
let mut all_files = Vec::new();
for index in &mut self.indices {
all_files.extend(index.files().to_vec());
}
all_files
}
fn files_sorted(&mut self) -> Vec<PathBuf> {
let mut files_sorted = self.files();
files_sorted.sort();
files_sorted
}
fn total_size(&mut self) -> u64 {
if let Some(size) = self.total_size {
size
} else {
let total_size = self
.indices
.iter_mut()
.map(RegistrySubCache::total_size)
.sum();
self.total_size = Some(total_size);
total_size
}
}
fn number_of_subcaches(&mut self) -> usize {
self.indices.len()
}
fn total_number_of_files(&mut self) -> usize {
match self.total_number_of_files {
Some(number) => number,
None => {
#[allow(clippy::cast_possible_truncation)]
self.indices
.iter_mut()
.map(|index| index.total_size() as usize)
.sum()
}
}
}
fn items(&mut self) -> &[PathBuf] {
let v: Vec<PathBuf> = self
.caches()
.iter()
.map(|index| index.path().clone())
.collect();
self.indices_paths = v;
&self.indices_paths
}
fn number_of_items(&mut self) -> usize {
self.caches().len()
}
}