Skip to main content

oxihuman_core/
temp_file_manager.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! Temporary file lifecycle manager.
6
7/// A temp file handle (stub — no actual OS file).
8#[derive(Debug, Clone)]
9pub struct TempFile {
10    pub path: String,
11    pub size_bytes: u64,
12    pub deleted: bool,
13}
14
15impl TempFile {
16    pub fn new(path: &str) -> Self {
17        TempFile {
18            path: path.to_string(),
19            size_bytes: 0,
20            deleted: false,
21        }
22    }
23
24    pub fn write_bytes(&mut self, bytes: u64) {
25        self.size_bytes += bytes;
26    }
27
28    pub fn delete(&mut self) {
29        self.deleted = true;
30        self.size_bytes = 0;
31    }
32
33    pub fn is_alive(&self) -> bool {
34        !self.deleted
35    }
36}
37
38/// Temporary file manager.
39pub struct TempFileManager {
40    prefix: String,
41    counter: u64,
42    files: Vec<TempFile>,
43}
44
45impl TempFileManager {
46    pub fn new(prefix: &str) -> Self {
47        TempFileManager {
48            prefix: prefix.to_string(),
49            counter: 0,
50            files: Vec::new(),
51        }
52    }
53
54    pub fn create(&mut self) -> &mut TempFile {
55        let path = format!("{}{}.tmp", self.prefix, self.counter);
56        self.counter += 1;
57        self.files.push(TempFile::new(&path));
58        let len = self.files.len();
59        &mut self.files[len - 1]
60    }
61
62    pub fn cleanup_all(&mut self) {
63        for f in &mut self.files {
64            f.delete();
65        }
66    }
67
68    pub fn alive_count(&self) -> usize {
69        self.files.iter().filter(|f| f.is_alive()).count()
70    }
71
72    pub fn total_size(&self) -> u64 {
73        self.files.iter().map(|f| f.size_bytes).sum()
74    }
75
76    pub fn all_files(&self) -> &[TempFile] {
77        &self.files
78    }
79}
80
81impl Default for TempFileManager {
82    fn default() -> Self {
83        Self::new("/tmp/oxihuman_")
84    }
85}
86
87/// Create a default temp file manager.
88pub fn new_temp_manager() -> TempFileManager {
89    TempFileManager::default()
90}
91
92/// Create N temp files and return their paths.
93pub fn create_n(mgr: &mut TempFileManager, n: usize) -> Vec<String> {
94    (0..n).map(|_| mgr.create().path.clone()).collect()
95}
96
97/// Total bytes across all alive temp files.
98pub fn alive_total_bytes(mgr: &TempFileManager) -> u64 {
99    mgr.files
100        .iter()
101        .filter(|f| f.is_alive())
102        .map(|f| f.size_bytes)
103        .sum()
104}
105
106/// Delete a temp file by path.
107pub fn delete_by_path(mgr: &mut TempFileManager, path: &str) {
108    if let Some(f) = mgr.files.iter_mut().find(|f| f.path == path) {
109        f.delete();
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_create_temp_file() {
119        let mut m = new_temp_manager();
120        let f = m.create();
121        assert!(f.is_alive());
122    }
123
124    #[test]
125    fn test_alive_count() {
126        let mut m = new_temp_manager();
127        create_n(&mut m, 3);
128        assert_eq!(m.alive_count(), 3);
129    }
130
131    #[test]
132    fn test_cleanup_all() {
133        let mut m = new_temp_manager();
134        create_n(&mut m, 2);
135        m.cleanup_all();
136        assert_eq!(m.alive_count(), 0);
137    }
138
139    #[test]
140    fn test_write_bytes() {
141        let mut m = new_temp_manager();
142        m.create().write_bytes(512);
143        assert_eq!(m.total_size(), 512);
144    }
145
146    #[test]
147    fn test_alive_total_bytes() {
148        let mut m = new_temp_manager();
149        m.create().write_bytes(100);
150        assert_eq!(alive_total_bytes(&m), 100);
151    }
152
153    #[test]
154    fn test_delete_by_path() {
155        let mut m = new_temp_manager();
156        let paths = create_n(&mut m, 2);
157        delete_by_path(&mut m, &paths[0]);
158        assert_eq!(m.alive_count(), 1);
159    }
160
161    #[test]
162    fn test_create_n_paths_unique() {
163        let mut m = new_temp_manager();
164        let paths = create_n(&mut m, 3);
165        let unique: std::collections::HashSet<_> = paths.iter().collect();
166        assert_eq!(unique.len(), 3);
167    }
168
169    #[test]
170    fn test_total_size_after_delete() {
171        let mut m = new_temp_manager();
172        m.create().write_bytes(200);
173        m.cleanup_all();
174        assert_eq!(m.total_size(), 0);
175    }
176
177    #[test]
178    fn test_all_files_accessible() {
179        let mut m = new_temp_manager();
180        create_n(&mut m, 2);
181        assert_eq!(m.all_files().len(), 2);
182    }
183
184    #[test]
185    fn test_default_prefix() {
186        let m = TempFileManager::default();
187        assert!(m.prefix.contains("oxihuman"));
188    }
189}