diskr-cli 1.0.0

Save your disk space, without fear of deleting the wrong thing.
Documentation
use crate::scanner::FsNode;
use serde::Serialize;
use std::path::PathBuf;

#[derive(Debug, Clone, Serialize)]
pub struct SizeEntry {
    pub path: PathBuf,
    pub size: u64,
    pub is_dir: bool,
}

pub fn top_files(root: &FsNode, min_size: u64, limit: usize) -> Vec<SizeEntry> {
    let mut files = Vec::new();
    root.flatten_files(&mut files);
    let mut entries: Vec<SizeEntry> = files.into_iter()
        .filter(|f| f.size >= min_size)
        .map(|f| SizeEntry { path: f.path.clone(), size: f.size, is_dir: false })
        .collect();
    entries.sort_by(|a, b| b.size.cmp(&a.size));
    entries.truncate(limit);
    entries
}

pub fn top_dirs(root: &FsNode, limit: usize) -> Vec<SizeEntry> {
    let mut out = Vec::new();
    collect_dirs(root, &mut out);
    out.sort_by(|a, b| b.size.cmp(&a.size));
    out.truncate(limit);
    out
}

fn collect_dirs(node: &FsNode, out: &mut Vec<SizeEntry>) {
    if !node.is_dir { return; }
    out.push(SizeEntry { path: node.path.clone(), size: node.size, is_dir: true });
    for c in &node.children {
        if c.is_dir { collect_dirs(c, out); }
    }
}

pub fn type_breakdown(root: &FsNode) -> Vec<(String, u64, u64)> {
    let mut files = Vec::new();
    root.flatten_files(&mut files);
    use std::collections::HashMap;
    let mut groups: HashMap<&'static str, (u64, u64)> = HashMap::new();
    for f in files {
        let ext = f.path.extension().and_then(|e| e.to_str()).unwrap_or("").to_lowercase();
        let cat = categorize_ext(&ext);
        let entry = groups.entry(cat).or_insert((0, 0));
        entry.0 += f.size;
        entry.1 += 1;
    }
    let mut result: Vec<(String, u64, u64)> = groups.into_iter().map(|(k, (s, c))| (k.to_string(), s, c)).collect();
    result.sort_by(|a, b| b.1.cmp(&a.1));
    result
}

fn categorize_ext(ext: &str) -> &'static str {
    match ext {
        "mp4" | "mkv" | "avi" | "mov" | "webm" | "flv" => "video",
        "jpg" | "jpeg" | "png" | "gif" | "webp" | "bmp" | "svg" | "raw" => "image",
        "mp3" | "wav" | "flac" | "ogg" | "m4a" => "audio",
        "zip" | "tar" | "gz" | "xz" | "7z" | "rar" | "bz2" | "zst" => "archive",
        "iso" | "img" | "appimage" | "deb" | "rpm" => "package",
        "pdf" | "doc" | "docx" | "xls" | "xlsx" | "ppt" | "pptx" | "odt" => "document",
        "log" => "log",
        "so" | "dll" | "bin" | "exe" | "o" | "a" => "binary",
        "" => "no-extension",
        _ => "other",
    }
}