file_system/device.rs
1//! Device abstraction for storage and I/O operations.
2//!
3//! This module provides the core device trait and types for abstracting various
4//! storage devices, peripherals, and I/O endpoints in the file system.
5
6use core::fmt;
7use core::fmt::{Debug, Formatter};
8
9use alloc::sync::Arc;
10use alloc::vec;
11use alloc::vec::Vec;
12
13use crate::{Error, Position, Result, Size};
14
15/// Convenience macro for creating a new [`Device`] from any type implementing [`DeviceTrait`].
16///
17/// This macro wraps the provided device implementation in an `Arc` and creates a `DeviceType`.
18///
19/// # Examples
20///
21/// ```rust
22/// # extern crate alloc;
23/// # use file_system::*;
24///
25/// let memory_device = Memory_device_type::<512>::new(1024);
26/// let device = create_device!(memory_device);
27/// ```
28#[macro_export]
29macro_rules! create_device {
30 ($Device:expr) => {
31 $crate::Device::new(alloc::sync::Arc::new($Device))
32 };
33}
34
35/// Core trait for all device implementations in the file system.
36///
37/// A device represents any storage medium or I/O endpoint that can be read from and written to.
38/// This includes physical storage devices (hard drives, SSDs, SD cards), memory devices for testing,
39/// partition devices, and other specialized I/O devices.
40///
41/// ## Thread Safety
42///
43/// All device implementations must be thread-safe (`Send + Sync`) as they may be accessed
44/// by multiple tasks/threads concurrently. Implementations should use appropriate synchronization
45/// primitives like `RwLock` or `Mutex` to handle concurrent access.
46///
47/// ## Non-Blocking Operations
48///
49/// Devices should never block indefinitely. If an operation would block, implementations should
50/// return [`Error::RessourceBusy`] instead. This means implementations should prefer
51/// `try_read()` and `try_write()` variants of synchronization primitives.
52///
53/// ## Position Management
54///
55/// Devices maintain an internal position cursor that affects read and write operations.
56/// The position can be manipulated using [`DeviceTrait::set_position`].
57///
58/// # Examples
59///
60/// ```rust
61/// # extern crate alloc;
62/// # use file_system::*;
63///
64/// // Create a memory device for testing
65/// let device = create_device!(Memory_device_type::<512>::new(1024));
66///
67/// // Write data
68/// let data = b"Hello, World!";
69/// let bytes_written = device.Write(data).unwrap();
70/// assert_eq!(bytes_written.As_u64(), data.len() as u64);
71///
72/// // Reset position and read back
73/// device.Set_position(&Position_type::Start(0)).unwrap();
74/// let mut buffer = alloc::vec![0u8; data.len()];
75/// let bytes_read = device.Read(&mut buffer).unwrap();
76/// assert_eq!(bytes_read.As_u64(), data.len() as u64);
77/// assert_eq!(&buffer, data);
78/// ```
79pub trait DeviceTrait: Send + Sync {
80 /// Read data from the device at the current position.
81 ///
82 /// Reads up to `Buffer.len()` bytes from the device into the provided buffer.
83 /// The actual number of bytes read may be less than requested.
84 ///
85 /// # Arguments
86 ///
87 /// * `Buffer` - Mutable byte slice to read data into
88 ///
89 /// # Returns
90 ///
91 /// * `Ok(Size)` - Number of bytes successfully read
92 /// * `Err(Error)` - Error if read operation failed
93 ///
94 /// # Errors
95 ///
96 /// * [`Error::InputOutput`] - I/O error during read operation
97 /// * [`Error::RessourceBusy`] - Device is temporarily unavailable
98 /// * [`Error::InvalidParameter`] - Invalid buffer or device state
99 fn read(&self, buffer: &mut [u8]) -> Result<Size>;
100
101 /// Write data to the device at the current position.
102 ///
103 /// Writes up to `Buffer.len()` bytes from the buffer to the device.
104 /// The actual number of bytes written may be less than requested.
105 ///
106 /// # Arguments
107 ///
108 /// * `Buffer` - Byte slice containing data to write
109 ///
110 /// # Returns
111 ///
112 /// * `Ok(Size)` - Number of bytes successfully written
113 /// * `Err(Error)` - Error if write operation failed
114 ///
115 /// # Errors
116 ///
117 /// * [`Error::InputOutput`] - I/O error during write operation
118 /// * [`Error::NoSpaceLeft`] - Device is full
119 /// * [`Error::RessourceBusy`] - Device is temporarily unavailable
120 /// * [`Error::PermissionDenied`] - Device is read-only
121 fn write(&self, buffer: &[u8]) -> Result<Size>;
122
123 /// Get the total size of the device in bytes.
124 ///
125 /// Returns the maximum amount of data that can be stored on or read from the device.
126 ///
127 /// # Returns
128 ///
129 /// * `Ok(Size)` - Total device size in bytes
130 /// * `Err(Error)` - Error if size cannot be determined
131 fn get_size(&self) -> Result<Size>;
132
133 /// Set the current position cursor for read/write operations.
134 ///
135 /// The position affects where subsequent read and write operations will occur.
136 /// Different position types allow for absolute positioning, relative positioning,
137 /// and positioning from the end of the device.
138 ///
139 /// # Arguments
140 ///
141 /// * `Position` - The new position to set
142 ///
143 /// # Returns
144 ///
145 /// * `Ok(Size)` - The new absolute position after the operation
146 /// * `Err(Error)` - Error if position is invalid
147 ///
148 /// # Errors
149 ///
150 /// * [`Error::InvalidParameter`] - Position is beyond device bounds
151 fn set_position(&self, position: &Position) -> Result<Size>;
152
153 /// Flush any buffered data to the underlying storage.
154 ///
155 /// Ensures that all pending write operations are committed to the physical device.
156 /// This is important for data integrity, especially on buffered devices.
157 ///
158 /// # Returns
159 ///
160 /// * `Ok(())` - Flush completed successfully
161 /// * `Err(Error)` - Error during flush operation
162 fn flush(&self) -> Result<()>;
163
164 /// Erase the entire device.
165 ///
166 /// This operation is primarily intended for flash memory devices and similar
167 /// storage that requires explicit erase operations. For most devices, this
168 /// operation is not supported and will return [`Error::UnsupportedOperation`].
169 ///
170 /// # Returns
171 ///
172 /// * `Ok(())` - Erase completed successfully
173 /// * `Err(Error::UnsupportedOperation)` - Device doesn't support erase
174 /// * `Err(Error)` - Error during erase operation
175 fn erase(&self) -> Result<()> {
176 Err(Error::UnsupportedOperation)
177 }
178
179 /// Get the block size of the device in bytes.
180 ///
181 /// For block devices, this returns the minimum unit of data transfer.
182 /// Operations should ideally be aligned to block boundaries for optimal performance.
183 ///
184 /// # Returns
185 ///
186 /// * `Ok(usize)` - Block size in bytes
187 /// * `Err(Error::UnsupportedOperation)` - Device doesn't have a block size
188 fn get_block_size(&self) -> Result<usize> {
189 Err(Error::UnsupportedOperation)
190 }
191
192 /// Check if this device represents a terminal/console device.
193 ///
194 /// # Returns
195 ///
196 /// * `true` - Device is a terminal
197 /// * `false` - Device is not a terminal
198 fn is_a_terminal(&self) -> bool {
199 false
200 }
201
202 /// Check if this device is a block device.
203 ///
204 /// Block devices support fixed-size block operations and typically represent
205 /// physical storage media like hard drives or SSDs.
206 ///
207 /// # Returns
208 ///
209 /// * `true` - Device is a block device
210 /// * `false` - Device is not a block device
211 fn is_a_block_device(&self) -> bool {
212 false
213 }
214
215 /// Create a complete dump of the device contents.
216 ///
217 /// Reads the entire device contents into a vector. This is primarily useful
218 /// for debugging, testing, and creating backups of small devices.
219 ///
220 /// # Returns
221 ///
222 /// * `Ok(Vec<u8>)` - Complete device contents
223 /// * `Err(Error)` - Error reading device
224 ///
225 /// # Note
226 ///
227 /// This operation can consume significant memory for large devices.
228 /// Use with caution on production systems.
229 fn dump_device(&self) -> Result<Vec<u8>> {
230 let size = self.get_size()?;
231
232 let mut buffer = vec![0; size.into()];
233
234 self.read(&mut buffer)?;
235
236 Ok(buffer)
237 }
238}
239
240/// Thread-safe wrapper for device implementations.
241///
242/// `DeviceType` provides a unified interface for all device implementations by wrapping
243/// them in an `Arc<dyn DeviceTrait>`. This allows for efficient cloning and sharing of
244/// device references across threads while maintaining type erasure.
245///
246/// # Examples
247///
248/// ```rust
249/// # extern crate alloc;
250/// # use file_system::*;
251/// # use alloc::sync::Arc;
252///
253/// // Create a device using the convenience macro
254/// let device1 = create_device!(Memory_device_type::<512>::new(1024));
255///
256/// // Create a device manually
257/// let memory_device = Memory_device_type::<512>::new(1024);
258/// let device2 = DeviceType::new(Arc::new(memory_device));
259///
260/// // Clone the device (cheap operation - only clones the Arc)
261/// let device_clone = device1.clone();
262/// ```
263#[derive(Clone)]
264#[repr(transparent)]
265pub struct Device(Arc<dyn DeviceTrait>);
266
267impl Debug for Device {
268 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
269 write!(formatter, "Device")
270 }
271}
272
273impl Device {
274 /// Create a new device wrapper from any implementation of [`DeviceTrait`].
275 ///
276 /// # Arguments
277 ///
278 /// * `Device` - Arc containing the device implementation
279 ///
280 /// # Examples
281 ///
282 /// ```rust
283 /// # extern crate alloc;
284 /// # use file_system::*;
285 /// # use alloc::sync::Arc;
286 ///
287 /// let memory_device = Memory_device_type::<512>::new(1024);
288 /// let device = DeviceType::new(Arc::new(memory_device));
289 /// ```
290 pub fn new(device: Arc<dyn DeviceTrait>) -> Self {
291 Device(device)
292 }
293
294 /// Read data from the device at the current position.
295 ///
296 /// See [`DeviceTrait::read`] for detailed documentation.
297 pub fn read(&self, buffer: &mut [u8]) -> Result<Size> {
298 self.0.read(buffer)
299 }
300
301 /// Write data to the device at the current position.
302 ///
303 /// See [`DeviceTrait::write`] for detailed documentation.
304 pub fn write(&self, buffer: &[u8]) -> Result<Size> {
305 self.0.write(buffer)
306 }
307
308 /// Get the total size of the device in bytes.
309 ///
310 /// See [`DeviceTrait::get_size`] for detailed documentation.
311 pub fn get_size(&self) -> Result<Size> {
312 self.0.get_size()
313 }
314
315 /// Set the current position cursor for read/write operations.
316 ///
317 /// See [`DeviceTrait::set_position`] for detailed documentation.
318 pub fn set_position(&self, position: &Position) -> Result<Size> {
319 self.0.set_position(position)
320 }
321
322 /// Flush any buffered data to the underlying storage.
323 ///
324 /// See [`DeviceTrait::flush`] for detailed documentation.
325 pub fn flush(&self) -> Result<()> {
326 self.0.flush()
327 }
328
329 /// Erase the entire device.
330 ///
331 /// See [`DeviceTrait::erase`] for detailed documentation.
332 pub fn erase(&self) -> Result<()> {
333 self.0.erase()
334 }
335
336 /// Get the block size of the device in bytes.
337 ///
338 /// See [`DeviceTrait::get_block_size`] for detailed documentation.
339 pub fn get_block_size(&self) -> Result<usize> {
340 self.0.get_block_size()
341 }
342
343 /// Check if this device represents a terminal/console device.
344 ///
345 /// See [`DeviceTrait::is_a_terminal`] for detailed documentation.
346 pub fn is_a_terminal(&self) -> bool {
347 self.0.is_a_terminal()
348 }
349
350 /// Check if this device is a block device.
351 ///
352 /// See [`DeviceTrait::is_a_block_device`] for detailed documentation.
353 pub fn is_a_block_device(&self) -> bool {
354 self.0.is_a_block_device()
355 }
356
357 /// Create a complete dump of the device contents.
358 ///
359 /// See [`DeviceTrait::dump_device`] for detailed documentation.
360 pub fn dump_device(&self) -> Result<Vec<u8>> {
361 self.0.dump_device()
362 }
363}