Skip to main content

moonpool_sim/storage/
provider.rs

1//! Simulated storage provider implementation.
2
3use super::file::SimStorageFile;
4use crate::sim::WeakSimWorld;
5use moonpool_core::{OpenOptions, StorageProvider};
6use std::io;
7use std::net::IpAddr;
8
9/// Simulated storage provider for deterministic testing.
10///
11/// Each provider is scoped to a specific process IP address. Files opened
12/// through this provider are tagged with the owner IP, enabling per-process
13/// fault injection and storage isolation.
14///
15/// # Example
16///
17/// ```ignore
18/// let sim = SimWorld::new();
19/// let ip: IpAddr = "10.0.1.1".parse().unwrap();
20/// let provider = SimStorageProvider::new(sim.weak(), ip);
21///
22/// let file = provider.open("test.txt", OpenOptions::create_write()).await?;
23/// ```
24#[derive(Debug, Clone)]
25pub struct SimStorageProvider {
26    sim: WeakSimWorld,
27    /// IP address of the process that owns files opened through this provider.
28    owner_ip: IpAddr,
29}
30
31impl SimStorageProvider {
32    /// Create a new simulated storage provider scoped to a process IP.
33    #[must_use]
34    pub fn new(sim: WeakSimWorld, owner_ip: IpAddr) -> Self {
35        Self { sim, owner_ip }
36    }
37
38    /// Upgrade the weak simulation handle, mapping a dropped simulation to an
39    /// I/O error so storage operations can propagate it with `?`.
40    fn sim(&self) -> io::Result<crate::sim::SimWorld> {
41        self.sim
42            .upgrade()
43            .map_err(|_| io::Error::other("simulation shutdown"))
44    }
45}
46
47impl StorageProvider for SimStorageProvider {
48    type File = SimStorageFile;
49
50    async fn open(&self, path: &str, options: OpenOptions) -> io::Result<Self::File> {
51        let sim = self.sim()?;
52
53        let file_id = sim.open_file(path, options, 0, self.owner_ip)?;
54
55        Ok(SimStorageFile::new(self.sim.clone(), file_id))
56    }
57
58    async fn exists(&self, path: &str) -> io::Result<bool> {
59        let sim = self.sim()?;
60        Ok(sim.file_exists(path))
61    }
62
63    async fn delete(&self, path: &str) -> io::Result<()> {
64        let sim = self.sim()?;
65        sim.delete_file(path)?;
66        Ok(())
67    }
68
69    async fn rename(&self, from: &str, to: &str) -> io::Result<()> {
70        let sim = self.sim()?;
71        sim.rename_file(from, to)?;
72        Ok(())
73    }
74}