file_system/devices/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 core::fmt::Debug;
10
11use alloc::vec::Vec;
12use alloc::{boxed::Box, vec};
13use shared::AnyByLayout;
14use synchronization::{blocking_mutex::raw::CriticalSectionRawMutex, rwlock::RwLock};
15
16use crate::block_device::GET_BLOCK_SIZE;
17use crate::{
18 ControlCommand, DirectBaseOperations, DirectBlockDevice, Error, MountOperations, Result, Size,
19 block_device,
20};
21
22/// In-memory device implementation with configurable block size.
23///
24/// This device stores all data in memory using a `Vec<u8>` and provides the same
25/// interface as physical storage devices. It's thread-safe and supports all standard
26/// device operations. The block size is configurable at compile time through the
27/// const generic parameter.
28///
29/// # Type Parameters
30///
31/// * `Block_size` - The block size in bytes (must be a power of 2, typically 512)
32///
33/// # Examples
34///
35/// ```rust
36/// extern crate alloc;
37/// use file_system::{MemoryDevice, DirectBaseOperations, Position};
38///
39/// // Create a 1MB memory device with 512-byte blocks
40/// let device = MemoryDevice::<512>::new(1024 * 1024);
41///
42/// // Write some data
43/// let data = b"Hello, Memory Device!";
44/// device.write(data, 0).unwrap();
45///
46/// // Reset position and read back
47/// device.set_position(0, &Position::Start(0)).unwrap();
48/// let mut buffer = alloc::vec![0u8; data.len()];
49/// device.read(&mut buffer, 0).unwrap();
50/// assert_eq!(&buffer, data);
51/// ```
52///
53/// # Thread Safety
54///
55/// The device uses an `RwLock` to ensure thread-safe access to the underlying data.
56/// Multiple readers can access the device simultaneously, but writes are exclusive.
57pub struct MemoryDevice<const BLOCK_SIZE: u32>(RwLock<CriticalSectionRawMutex, Vec<u8>>);
58
59impl<const BLOCK_SIZE: u32> Debug for MemoryDevice<BLOCK_SIZE> {
60 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61 f.debug_struct("MemoryDevice")
62 .field("size", &self.0.try_read().map(|data| data.len()))
63 .finish()
64 }
65}
66
67impl<const BLOCK_SIZE: u32> MemoryDevice<BLOCK_SIZE> {
68 /// Create a new memory device with the specified size.
69 ///
70 /// The device will be initialized with zeros and have the specified total size.
71 /// The size must be a multiple of the block size.
72 ///
73 /// # Arguments
74 ///
75 /// * `Size` - Total size of the device in bytes
76 ///
77 /// # Panics
78 ///
79 /// Panics if `Size` is not a multiple of `Block_size`.
80 ///
81 /// # Examples
82 ///
83 /// ```rust
84 /// # extern crate alloc;
85 /// # use file_system::MemoryDevice;
86 ///
87 /// // Create a 4KB device with 512-byte blocks
88 /// let device = MemoryDevice::<512>::new(4096);
89 /// ```
90 pub fn new(size: usize) -> Self {
91 assert!(size.is_multiple_of(BLOCK_SIZE as usize));
92
93 let data: Vec<u8> = vec![0; size];
94
95 Self(RwLock::new(data))
96 }
97
98 pub fn new_static(size: usize) -> &'static Self {
99 Box::leak(Box::new(Self::new(size)))
100 }
101
102 /// Create a memory device from existing data.
103 ///
104 /// This allows you to create a device with pre-populated data, useful for
105 /// testing with known data patterns or loading device images.
106 ///
107 /// # Arguments
108 ///
109 /// * `Data` - Vector containing the initial device data
110 ///
111 /// # Panics
112 ///
113 /// Panics if the data length is not a multiple of `Block_size`.
114 ///
115 /// # Examples
116 ///
117 /// ```rust
118 /// # extern crate alloc;
119 /// # use file_system::MemoryDevice;
120 /// # use alloc::vec;
121 ///
122 /// // Create device with specific data
123 /// let data = vec![0x42; 1024]; // 1KB of 0x42 bytes
124 /// let device = MemoryDevice::<512>::from_vec(data);
125 /// ```
126 pub fn from_vec(data: Vec<u8>) -> Self {
127 assert!(data.len().is_multiple_of(BLOCK_SIZE as usize));
128
129 Self(RwLock::new(data))
130 }
131}
132
133impl<const BLOCK_SIZE: u32> DirectBaseOperations for MemoryDevice<BLOCK_SIZE> {
134 /// Read data from the memory device.
135 ///
136 /// Reads data from the current position into the provided buffer.
137 /// The position is automatically advanced by the number of bytes read.
138 fn read(&self, buffer: &mut [u8], absolute_position: Size) -> Result<usize> {
139 let inner = self
140 .0
141 .try_write()
142 .map_err(|_| crate::Error::RessourceBusy)?;
143
144 let absolute_position = absolute_position as usize;
145
146 let read_size = buffer
147 .len()
148 .min(inner.len().saturating_sub(absolute_position));
149 buffer[..read_size]
150 .copy_from_slice(&inner[absolute_position..absolute_position + read_size]);
151 Ok(read_size as _)
152 }
153
154 fn write(&self, buffer: &[u8], absolute_position: Size) -> Result<usize> {
155 let mut inner = self
156 .0
157 .try_write()
158 .map_err(|_| crate::Error::RessourceBusy)?;
159
160 let absolute_position = absolute_position as usize;
161
162 let write_size = buffer
163 .len()
164 .min(inner.len().saturating_sub(absolute_position));
165 inner[absolute_position..absolute_position + write_size]
166 .copy_from_slice(&buffer[..write_size]);
167
168 Ok(write_size as _)
169 }
170
171 fn control(
172 &self,
173 command: crate::ControlCommandIdentifier,
174 _: &AnyByLayout,
175 output: &mut AnyByLayout,
176 ) -> Result<()> {
177 match command {
178 GET_BLOCK_SIZE::IDENTIFIER => {
179 let output = GET_BLOCK_SIZE::cast_output(output)?;
180 *output = BLOCK_SIZE;
181 }
182 block_device::GET_BLOCK_COUNT::IDENTIFIER => {
183 let output = block_device::GET_BLOCK_COUNT::cast_output(output)?;
184
185 *output = (self
186 .0
187 .try_read()
188 .map_err(|_| crate::Error::RessourceBusy)?
189 .len()
190 / BLOCK_SIZE as usize) as u32;
191 }
192 _ => return Err(Error::UnsupportedOperation),
193 }
194
195 Ok(())
196 }
197}
198
199impl<const BLOCK_SIZE: u32> MountOperations for MemoryDevice<BLOCK_SIZE> {}
200
201impl<const BLOCK_SIZE: u32> DirectBlockDevice for MemoryDevice<BLOCK_SIZE> {}
202
203#[cfg(test)]
204mod tests {
205 use super::*;
206 use crate::implement_block_device_tests;
207
208 implement_block_device_tests!(MemoryDevice::<512>::new(4096));
209}