file_system/
memory_device.rs

1//! In-memory device implementation for testing and simulation.
2
3//!
4//! This module provides a memory-based device implementation that stores data
5//! in RAM instead of on physical storage. It's primarily used for testing,
6//! simulation, and development purposes where you need a device that behaves
7//! like storage but doesn't require actual hardware.
8
9use alloc::vec;
10use alloc::vec::Vec;
11use futures::block_on;
12use synchronization::{blocking_mutex::raw::CriticalSectionRawMutex, rwlock::RwLock};
13
14use crate::{DeviceTrait, Position, Size};
15
16/// In-memory device implementation with configurable block size.
17///
18/// This device stores all data in memory using a `Vec<u8>` and provides the same
19/// interface as physical storage devices. It's thread-safe and supports all standard
20/// device operations. The block size is configurable at compile time through the
21/// const generic parameter.
22///
23/// # Type Parameters
24///
25/// * `Block_size` - The block size in bytes (must be a power of 2, typically 512)
26///
27/// # Examples
28///
29/// ```rust
30/// # extern crate alloc;
31/// # use file_system::*;
32///
33/// // Create a 1MB memory device with 512-byte blocks
34/// let device = Memory_device_type::<512>::new(1024 * 1024);
35/// let device = create_device!(device);
36///
37/// // Write some data
38/// let data = b"Hello, Memory Device!";
39/// device.Write(data).unwrap();
40///
41/// // Reset position and read back
42/// device.Set_position(&Position_type::Start(0)).unwrap();
43/// let mut buffer = alloc::vec![0u8; data.len()];
44/// device.Read(&mut buffer).unwrap();
45/// assert_eq!(&buffer, data);
46/// ```
47///
48/// # Thread Safety
49///
50/// The device uses an `RwLock` to ensure thread-safe access to the underlying data.
51/// Multiple readers can access the device simultaneously, but writes are exclusive.
52pub struct MemoryDevice<const BLOCK_SIZE: usize>(RwLock<CriticalSectionRawMutex, (Vec<u8>, usize)>);
53
54impl<const BLOCK_SIZE: usize> MemoryDevice<BLOCK_SIZE> {
55    /// Create a new memory device with the specified size.
56    ///
57    /// The device will be initialized with zeros and have the specified total size.
58    /// The size must be a multiple of the block size.
59    ///
60    /// # Arguments
61    ///
62    /// * `Size` - Total size of the device in bytes
63    ///
64    /// # Panics
65    ///
66    /// Panics if `Size` is not a multiple of `Block_size`.
67    ///
68    /// # Examples
69    ///
70    /// ```rust
71    /// # extern crate alloc;
72    /// # use file_system::Memory_device_type;
73    ///
74    /// // Create a 4KB device with 512-byte blocks
75    /// let device = Memory_device_type::<512>::new(4096);
76    /// ```
77    pub fn new(size: usize) -> Self {
78        assert!(size.is_multiple_of(BLOCK_SIZE));
79
80        let data: Vec<u8> = vec![0; size];
81
82        Self(RwLock::new((data, 0)))
83    }
84
85    /// Create a memory device from existing data.
86    ///
87    /// This allows you to create a device with pre-populated data, useful for
88    /// testing with known data patterns or loading device images.
89    ///
90    /// # Arguments
91    ///
92    /// * `Data` - Vector containing the initial device data
93    ///
94    /// # Panics
95    ///
96    /// Panics if the data length is not a multiple of `Block_size`.
97    ///
98    /// # Examples
99    ///
100    /// ```rust
101    /// # extern crate alloc;
102    /// # use file_system::Memory_device_type;
103    /// # use alloc::vec;
104    ///
105    /// // Create device with specific data
106    /// let data = vec![0x42; 1024]; // 1KB of 0x42 bytes
107    /// let device = Memory_device_type::<512>::From_vec(data);
108    /// ```
109    pub fn from_vec(data: Vec<u8>) -> Self {
110        assert!(data.len().is_multiple_of(BLOCK_SIZE));
111
112        Self(RwLock::new((data, 0)))
113    }
114
115    /// Get the number of blocks in this device.
116    ///
117    /// Returns the total number of blocks of size `Block_size` that fit in the device.
118    ///
119    /// # Returns
120    ///
121    /// The number of blocks in the device.
122    ///
123    /// # Examples
124    ///
125    /// ```rust
126    /// # extern crate alloc;
127    /// # use file_system::Memory_device_type;
128    ///
129    /// let device = Memory_device_type::<512>::new(2048);
130    /// assert_eq!(device.get_block_count(), 4); // 2048 / 512 = 4
131    /// ```
132    pub fn get_block_count(&self) -> usize {
133        let inner = block_on(self.0.read());
134
135        inner.0.len() / BLOCK_SIZE
136    }
137}
138
139impl<const BLOCK_SIZE: usize> DeviceTrait for MemoryDevice<BLOCK_SIZE> {
140    /// Read data from the memory device.
141    ///
142    /// Reads data from the current position into the provided buffer.
143    /// The position is automatically advanced by the number of bytes read.
144    fn read(&self, buffer: &mut [u8]) -> crate::Result<Size> {
145        let mut inner = self
146            .0
147            .try_write()
148            .map_err(|_| crate::Error::RessourceBusy)?;
149        let (data, position) = &mut *inner;
150
151        let read_size = buffer.len().min(data.len().saturating_sub(*position));
152        buffer[..read_size].copy_from_slice(&data[*position..*position + read_size]);
153        *position += read_size;
154        Ok(read_size.into())
155    }
156
157    fn write(&self, buffer: &[u8]) -> crate::Result<Size> {
158        let mut inner = block_on(self.0.write());
159        let (data, position) = &mut *inner;
160
161        data[*position..*position + buffer.len()].copy_from_slice(buffer);
162        *position += buffer.len();
163        Ok(buffer.len().into())
164    }
165
166    fn get_size(&self) -> crate::Result<Size> {
167        let inner = block_on(self.0.read());
168
169        Ok(Size::new(inner.0.len() as u64))
170    }
171
172    fn set_position(&self, position: &Position) -> crate::Result<Size> {
173        let mut inner = block_on(self.0.write());
174        let (data, device_position) = &mut *inner;
175
176        match position {
177            Position::Start(position) => *device_position = *position as usize,
178            Position::Current(position) => {
179                *device_position = (*device_position as isize + *position as isize) as usize
180            }
181            Position::End(position) => {
182                *device_position = (data.len() as isize - *position as isize) as usize
183            }
184        }
185
186        Ok(Size::new(*device_position as u64))
187    }
188
189    fn erase(&self) -> crate::Result<()> {
190        let mut inner = block_on(self.0.write());
191
192        let (data, position) = &mut *inner;
193
194        data[*position..*position + BLOCK_SIZE].fill(0);
195
196        Ok(())
197    }
198
199    fn flush(&self) -> crate::Result<()> {
200        Ok(())
201    }
202
203    fn get_block_size(&self) -> crate::Result<usize> {
204        Ok(BLOCK_SIZE)
205    }
206
207    fn dump_device(&self) -> crate::Result<Vec<u8>> {
208        let inner = block_on(self.0.read());
209
210        Ok(inner.0.clone())
211    }
212
213    fn is_a_terminal(&self) -> bool {
214        false
215    }
216
217    fn is_a_block_device(&self) -> bool {
218        false
219    }
220}