Skip to main content

vortex_fs/
real.rs

1//! `RealFs` — production pass-through to `std::fs`.
2//!
3//! Implements [`VortexFs`] by delegating directly to the OS. Zero overhead.
4
5use crate::traits::{FileMetadata, FileType, VortexFs, VortexFsError, VortexFsResult};
6
7/// Production filesystem implementation — delegates to `std::fs`.
8pub struct RealFs;
9
10impl RealFs {
11    pub fn new() -> Self {
12        Self
13    }
14}
15
16impl Default for RealFs {
17    fn default() -> Self {
18        Self::new()
19    }
20}
21
22impl VortexFs for RealFs {
23    fn read_file(&self, path: &str) -> VortexFsResult<Vec<u8>> {
24        std::fs::read(path).map_err(|e| map_io_error(path, e))
25    }
26
27    fn write_file(&mut self, path: &str, data: &[u8]) -> VortexFsResult<()> {
28        // Ensure parent directory exists
29        if let Some(parent) = std::path::Path::new(path).parent()
30            && !parent.as_os_str().is_empty()
31        {
32            std::fs::create_dir_all(parent).map_err(|e| map_io_error(path, e))?;
33        }
34        std::fs::write(path, data).map_err(|e| map_io_error(path, e))
35    }
36
37    fn append_file(&mut self, path: &str, data: &[u8]) -> VortexFsResult<()> {
38        use std::io::Write;
39        let mut file = std::fs::OpenOptions::new()
40            .create(true)
41            .append(true)
42            .open(path)
43            .map_err(|e| map_io_error(path, e))?;
44        file.write_all(data).map_err(|e| map_io_error(path, e))
45    }
46
47    fn remove_file(&mut self, path: &str) -> VortexFsResult<()> {
48        std::fs::remove_file(path).map_err(|e| map_io_error(path, e))
49    }
50
51    fn rename(&mut self, from: &str, to: &str) -> VortexFsResult<()> {
52        std::fs::rename(from, to).map_err(|e| map_io_error(from, e))
53    }
54
55    fn create_dir_all(&mut self, path: &str) -> VortexFsResult<()> {
56        std::fs::create_dir_all(path).map_err(|e| map_io_error(path, e))
57    }
58
59    fn remove_dir(&mut self, path: &str) -> VortexFsResult<()> {
60        std::fs::remove_dir(path).map_err(|e| map_io_error(path, e))
61    }
62
63    fn read_dir(&self, path: &str) -> VortexFsResult<Vec<String>> {
64        let entries = std::fs::read_dir(path).map_err(|e| map_io_error(path, e))?;
65        let mut names = Vec::new();
66        for entry in entries {
67            let entry = entry.map_err(|e| map_io_error(path, e))?;
68            if let Some(name) = entry.file_name().to_str() {
69                names.push(name.to_string());
70            }
71        }
72        names.sort(); // Deterministic ordering
73        Ok(names)
74    }
75
76    fn metadata(&self, path: &str) -> VortexFsResult<FileMetadata> {
77        let meta = std::fs::metadata(path).map_err(|e| map_io_error(path, e))?;
78        Ok(FileMetadata {
79            file_type: if meta.is_dir() {
80                FileType::Directory
81            } else {
82                FileType::File
83            },
84            size: meta.len(),
85        })
86    }
87
88    fn exists(&self, path: &str) -> bool {
89        std::path::Path::new(path).exists()
90    }
91
92    fn fsync(&mut self, path: &str) -> VortexFsResult<()> {
93        let file = std::fs::File::open(path).map_err(|e| map_io_error(path, e))?;
94        file.sync_all().map_err(|e| map_io_error(path, e))
95    }
96}
97
98fn map_io_error(path: &str, err: std::io::Error) -> VortexFsError {
99    match err.kind() {
100        std::io::ErrorKind::NotFound => VortexFsError::NotFound(path.into()),
101        std::io::ErrorKind::PermissionDenied => VortexFsError::PermissionDenied(path.into()),
102        std::io::ErrorKind::AlreadyExists => VortexFsError::AlreadyExists(path.into()),
103        _ => VortexFsError::IoError(format!("{path}: {err}")),
104    }
105}