Skip to main content

palladium_runtime/
fs.rs

1use std::future::Future;
2use std::path::Path;
3use std::pin::Pin;
4
5/// Abstraction over the filesystem to support deterministic simulation.
6///
7/// In production, this uses real OS files (`std::fs` or `tokio::fs`).
8/// In simulation, `SimVfs` provides an in-memory virtual disk.
9pub trait FileSystem: Clone + Send + Sync + 'static {
10    /// Read the entire contents of a file into a vector of bytes.
11    fn read(
12        &self,
13        path: &Path,
14    ) -> Pin<Box<dyn Future<Output = std::io::Result<Vec<u8>>> + Send + 'static>>;
15
16    /// Write a slice as the entire contents of a file.
17    fn write(
18        &self,
19        path: &Path,
20        contents: Vec<u8>,
21    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>>;
22
23    /// Remove a file from the filesystem.
24    fn remove_file(
25        &self,
26        path: &Path,
27    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>>;
28
29    /// Create a directory and all of its parent components if they are missing.
30    fn create_dir_all(
31        &self,
32        path: &Path,
33    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>>;
34
35    /// Return true if the path points to an existing entity.
36    fn exists(&self, path: &Path) -> Pin<Box<dyn Future<Output = bool> + Send + 'static>>;
37}
38
39/// Production implementation of `FileSystem` using `tokio::fs`.
40#[derive(Clone, Default)]
41pub struct TokioFileSystem;
42
43impl FileSystem for TokioFileSystem {
44    fn read(
45        &self,
46        path: &Path,
47    ) -> Pin<Box<dyn Future<Output = std::io::Result<Vec<u8>>> + Send + 'static>> {
48        let p = path.to_path_buf();
49        Box::pin(async move { tokio::fs::read(p).await })
50    }
51
52    fn write(
53        &self,
54        path: &Path,
55        contents: Vec<u8>,
56    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>> {
57        let p = path.to_path_buf();
58        Box::pin(async move { tokio::fs::write(p, contents).await })
59    }
60
61    fn remove_file(
62        &self,
63        path: &Path,
64    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>> {
65        let p = path.to_path_buf();
66        Box::pin(async move { tokio::fs::remove_file(p).await })
67    }
68
69    fn create_dir_all(
70        &self,
71        path: &Path,
72    ) -> Pin<Box<dyn Future<Output = std::io::Result<()>> + Send + 'static>> {
73        let p = path.to_path_buf();
74        Box::pin(async move { tokio::fs::create_dir_all(p).await })
75    }
76
77    fn exists(&self, path: &Path) -> Pin<Box<dyn Future<Output = bool> + Send + 'static>> {
78        let p = path.to_path_buf();
79        Box::pin(async move { tokio::fs::metadata(p).await.is_ok() })
80    }
81}