Skip to main content

diskard_core/
finding.rs

1use serde::Serialize;
2use std::fmt;
3use std::path::PathBuf;
4use std::time::SystemTime;
5
6/// Risk level for a finding — how safe it is to delete.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
8pub enum RiskLevel {
9    /// Safe to delete — caches, build artifacts that regenerate automatically.
10    Safe,
11    /// Moderate — can be regenerated but may take time or bandwidth.
12    Moderate,
13    /// Risky — may contain user data or require manual reconfiguration.
14    Risky,
15}
16
17impl fmt::Display for RiskLevel {
18    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19        match self {
20            Self::Safe => write!(f, "safe"),
21            Self::Moderate => write!(f, "moderate"),
22            Self::Risky => write!(f, "risky"),
23        }
24    }
25}
26
27impl RiskLevel {
28    pub fn emoji(&self) -> &'static str {
29        match self {
30            Self::Safe => "🟢",
31            Self::Moderate => "🟡",
32            Self::Risky => "🔴",
33        }
34    }
35}
36
37/// Category of a finding — which tool/ecosystem it belongs to.
38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
39pub enum Category {
40    Xcode,
41    Node,
42    Homebrew,
43    Python,
44    Rust,
45    Docker,
46    Ollama,
47    HuggingFace,
48    Claude,
49    VSCode,
50    Gradle,
51    CocoaPods,
52    Generic,
53}
54
55impl fmt::Display for Category {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        match self {
58            Self::Xcode => write!(f, "Xcode"),
59            Self::Node => write!(f, "Node.js"),
60            Self::Homebrew => write!(f, "Homebrew"),
61            Self::Python => write!(f, "Python"),
62            Self::Rust => write!(f, "Rust"),
63            Self::Docker => write!(f, "Docker"),
64            Self::Ollama => write!(f, "Ollama"),
65            Self::HuggingFace => write!(f, "HuggingFace"),
66            Self::Claude => write!(f, "Claude"),
67            Self::VSCode => write!(f, "VS Code"),
68            Self::Gradle => write!(f, "Gradle"),
69            Self::CocoaPods => write!(f, "CocoaPods"),
70            Self::Generic => write!(f, "Generic"),
71        }
72    }
73}
74
75/// A single finding — a path that can be cleaned up.
76#[derive(Debug, Clone, Serialize)]
77pub struct Finding {
78    /// Absolute path to the directory or file.
79    pub path: PathBuf,
80    /// Which ecosystem this belongs to.
81    pub category: Category,
82    /// How risky it is to delete.
83    pub risk: RiskLevel,
84    /// Size in bytes.
85    pub size_bytes: u64,
86    /// Human-readable description of what this is.
87    pub description: String,
88    /// Last modification time, if available.
89    #[serde(skip)]
90    pub last_modified: Option<SystemTime>,
91}
92
93impl Finding {
94    pub fn size_human(&self) -> String {
95        crate::size::format_bytes(self.size_bytes)
96    }
97}