file_system/operations/
base.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 shared::AnyByLayout;
7
8use crate::{Context, ControlCommandIdentifier, Error, Position, Result, Size};
9
10/// Core trait for all device implementations in the file system.
11///
12/// A device represents any storage medium or I/O endpoint that can be read from and written to.
13/// This includes physical storage devices (hard drives, SSDs, SD cards), memory devices for testing,
14/// partition devices, and other specialized I/O devices.
15///
16/// ## Thread Safety
17///
18/// All device implementations must be thread-safe (`Send + Sync`) as they may be accessed
19/// by multiple tasks/threads concurrently. Implementations should use appropriate synchronization
20/// primitives like `RwLock` or `Mutex` to handle concurrent access.
21///
22/// ## Non-Blocking Operations
23///
24/// Devices should never block indefinitely. If an operation would block, implementations should
25/// return [`Error::RessourceBusy`] instead. This means implementations should prefer
26/// `try_read()` and `try_write()` variants of synchronization primitives.
27///
28/// ## Position Management
29///
30/// Devices maintain an internal position cursor that affects read and write operations.
31/// The position can be manipulated using [`BaseOperations::set_position`].
32///
33/// # Examples
34///
35/// ```rust
36/// # extern crate alloc;
37/// # use file_system::{Size, MemoryDevice, DirectBaseOperations, Position};
38///
39/// // Create a memory device for testing
40/// let device = MemoryDevice::<512>::new(1024);
41///
42/// // Write data
43/// let data = b"Hello, World!";
44/// let bytes_written = device.write(data, 0).unwrap();
45/// assert_eq!(bytes_written, data.len());
46///
47/// // Reset position and read back
48/// device.set_position(0, &Position::Start(0)).unwrap();
49/// let mut buffer = alloc::vec![0u8; data.len()];
50/// let bytes_read = device.read(&mut buffer, 0).unwrap();
51/// assert_eq!(bytes_read, data.len());
52/// assert_eq!(&buffer, data);
53/// ```
54pub trait BaseOperations: Send + Sync {
55    fn open(&self, _context: &mut Context) -> Result<()> {
56        Ok(())
57    }
58
59    fn close(&self, _context: &mut Context) -> Result<()> {
60        Ok(())
61    }
62
63    /// Read data from the device at the current position.
64    ///
65    /// Reads up to `Buffer.len()` bytes from the device into the provided buffer.
66    /// The actual number of bytes read may be less than requested.
67    ///
68    /// # Arguments
69    ///
70    /// * `context` - File system context
71    /// * `Buffer` - Mutable byte slice to read data into
72    ///
73    /// # Returns
74    ///
75    /// * `Ok(Size)` - Number of bytes successfully read
76    /// * `Err(Error)` - Error if read operation failed
77    ///
78    /// # Errors
79    ///
80    /// * [`Error::InputOutput`] - I/O error during read operation
81    /// * [`Error::RessourceBusy`] - Device is temporarily unavailable
82    /// * [`Error::InvalidParameter`] - Invalid buffer or device state
83    fn read(
84        &self,
85        context: &mut Context,
86        buffer: &mut [u8],
87        absolute_position: Size,
88    ) -> Result<usize>;
89
90    fn read_until(
91        &self,
92        context: &mut Context,
93        buffer: &mut [u8],
94        absolute_position: Size,
95        delimiter: &[u8],
96    ) -> Result<usize> {
97        if delimiter.is_empty() {
98            return Err(Error::InvalidParameter);
99        }
100
101        let mut total_read = 0;
102        let mut match_count = 0;
103
104        while total_read < buffer.len() {
105            let bytes_read = self.read(
106                context,
107                &mut buffer[total_read..total_read + 1],
108                absolute_position + total_read as Size,
109            )?;
110
111            if bytes_read == 0 {
112                break; // End of file or no more data
113            }
114
115            total_read += bytes_read;
116
117            // Check if we're matching the delimiter
118            if buffer[total_read - 1] == delimiter[match_count] {
119                match_count += 1;
120                if match_count == delimiter.len() {
121                    break; // Found complete delimiter
122                }
123            } else {
124                // Reset and check if current byte starts a new match
125                match_count = 0;
126                if buffer[total_read - 1] == delimiter[0] {
127                    match_count = 1;
128                }
129            }
130        }
131
132        Ok(total_read)
133    }
134
135    /// Write data to the device at the current position.
136    ///
137    /// Writes up to `Buffer.len()` bytes from the buffer to the device.
138    /// The actual number of bytes written may be less than requested.
139    ///
140    /// # Arguments
141    ///
142    /// * `context` - File system context
143    /// * `Buffer` - Byte slice containing data to write
144    ///
145    /// # Returns
146    ///
147    /// * `Ok(Size)` - Number of bytes successfully written
148    /// * `Err(Error)` - Error if write operation failed
149    ///
150    /// # Errors
151    ///
152    /// * [`Error::InputOutput`] - I/O error during write operation
153    /// * [`Error::NoSpaceLeft`] - Device is full
154    /// * [`Error::RessourceBusy`] - Device is temporarily unavailable
155    /// * [`Error::PermissionDenied`] - Device is read-only
156    fn write(&self, context: &mut Context, buffer: &[u8], absolute_position: Size)
157    -> Result<usize>;
158
159    fn write_pattern(
160        &self,
161        context: &mut Context,
162        pattern: &[u8],
163        count: usize,
164        absolute_position: Size,
165    ) -> Result<usize> {
166        let mut total_written = 0;
167
168        for _ in 0..count {
169            let bytes_written =
170                self.write(context, pattern, absolute_position + total_written as Size)?;
171            if bytes_written == 0 {
172                break; // Unable to write more
173            }
174            total_written += bytes_written;
175        }
176
177        Ok(total_written)
178    }
179
180    fn write_vectored(
181        &self,
182        context: &mut Context,
183        buffers: &[&[u8]],
184        absolute_position: Size,
185    ) -> Result<usize> {
186        let mut total_written = 0;
187
188        for buffer in buffers {
189            if buffer.is_empty() {
190                continue; // Skip empty buffers
191            }
192            let bytes_written =
193                self.write(context, buffer, absolute_position + total_written as Size)?;
194            if bytes_written == 0 {
195                break; // Unable to write more
196            }
197            total_written += bytes_written;
198        }
199
200        Ok(total_written)
201    }
202
203    /// Set the current position cursor for read/write operations.
204    ///
205    /// The position affects where subsequent read and write operations will occur.
206    /// Different position types allow for absolute positioning, relative positioning,
207    /// and positioning from the end of the device.
208    ///
209    /// # Arguments
210    ///
211    /// * `context` - File system context
212    /// * `Position` - The new position to set
213    ///
214    /// # Returns
215    ///
216    /// * `Ok(Size)` - The new absolute position after the operation
217    /// * `Err(Error)` - Error if position is invalid
218    ///
219    /// # Errors
220    ///
221    /// * [`Error::InvalidParameter`] - Position is beyond device bounds
222    fn set_position(
223        &self,
224        _context: &mut Context,
225        _current_position: Size,
226        _position: &Position,
227    ) -> Result<Size> {
228        match _position {
229            Position::Start(position) => Ok(*position),
230            Position::Current(offset) => Ok(_current_position.wrapping_add(*offset as Size)),
231            Position::End(_) => Err(Error::UnsupportedOperation),
232        }
233    }
234
235    /// Flush any buffered data to the underlying storage.
236    ///
237    /// Ensures that all pending write operations are committed to the physical device.
238    /// This is important for data integrity, especially on buffered devices.
239    ///
240    /// # Arguments
241    ///
242    /// * `context` - File system context
243    ///
244    /// # Returns
245    ///
246    /// * `Ok(())` - Flush completed successfully
247    /// * `Err(Error)` - Error during flush operation
248    fn flush(&self, _context: &mut Context) -> Result<()> {
249        Ok(())
250    }
251
252    fn control(
253        &self,
254        _context: &mut Context,
255        _command: ControlCommandIdentifier,
256        _input: &AnyByLayout,
257        _output: &mut AnyByLayout,
258    ) -> Result<()> {
259        Err(Error::UnsupportedOperation)
260    }
261
262    fn clone_context(&self, context: &Context) -> Result<Context>;
263}
264
265pub fn open_close_operation<D, R>(device: &D, operation: impl Fn(&D) -> Result<R>) -> Result<R>
266where
267    D: DirectBaseOperations,
268{
269    device.open()?;
270    let result = operation(device);
271    device.close()?;
272    result
273}
274
275pub trait DirectBaseOperations: Send + Sync {
276    fn open(&self) -> Result<()> {
277        Ok(())
278    }
279
280    fn close(&self) -> Result<()> {
281        Ok(())
282    }
283
284    fn read(&self, buffer: &mut [u8], absolute_position: Size) -> Result<usize>;
285
286    fn read_until(
287        &self,
288        buffer: &mut [u8],
289        absolute_position: Size,
290        delimiter: &[u8],
291    ) -> Result<usize> {
292        if delimiter.is_empty() {
293            return Err(Error::InvalidParameter);
294        }
295
296        let mut total_read = 0;
297        let mut match_count = 0;
298
299        while total_read < buffer.len() {
300            let bytes_read = self.read(
301                &mut buffer[total_read..total_read + 1],
302                absolute_position + total_read as Size,
303            )?;
304
305            if bytes_read == 0 {
306                break; // End of file or no more data
307            }
308
309            total_read += bytes_read;
310
311            // Check if we're matching the delimiter
312            if buffer[total_read - 1] == delimiter[match_count] {
313                match_count += 1;
314                if match_count == delimiter.len() {
315                    break; // Found complete delimiter
316                }
317            } else {
318                // Reset and check if current byte starts a new match
319                match_count = 0;
320                if buffer[total_read - 1] == delimiter[0] {
321                    match_count = 1;
322                }
323            }
324        }
325
326        Ok(total_read)
327    }
328
329    fn write(&self, buffer: &[u8], absolute_position: Size) -> Result<usize>;
330
331    fn write_pattern(
332        &self,
333        pattern: &[u8],
334        count: usize,
335        absolute_position: Size,
336    ) -> Result<usize> {
337        let mut total_written = 0;
338
339        for _ in 0..count {
340            let bytes_written = self.write(pattern, absolute_position + total_written as Size)?;
341            if bytes_written == 0 {
342                break; // Unable to write more
343            }
344            total_written += bytes_written;
345        }
346
347        Ok(total_written)
348    }
349
350    fn write_vectored(&self, buffers: &[&[u8]], absolute_position: Size) -> Result<usize> {
351        let mut total_written = 0;
352
353        for buffer in buffers {
354            if buffer.is_empty() {
355                continue; // Skip empty buffers
356            }
357            let bytes_written = self.write(buffer, absolute_position + total_written as Size)?;
358            if bytes_written == 0 {
359                break; // Unable to write more
360            }
361            total_written += bytes_written;
362        }
363
364        Ok(total_written)
365    }
366
367    fn flush(&self) -> Result<()> {
368        Ok(())
369    }
370
371    fn set_position(&self, _current_position: Size, _position: &Position) -> Result<Size> {
372        match _position {
373            Position::Start(position) => Ok(*position),
374            Position::Current(offset) => Ok(_current_position.wrapping_add(*offset as Size)),
375            Position::End(_) => Err(Error::UnsupportedOperation),
376        }
377    }
378
379    fn control(
380        &self,
381        _command: ControlCommandIdentifier,
382        _input: &AnyByLayout,
383        _output: &mut AnyByLayout,
384    ) -> Result<()> {
385        Err(Error::UnsupportedOperation)
386    }
387}
388
389impl<T> BaseOperations for T
390where
391    T: DirectBaseOperations + Send + Sync,
392{
393    fn open(&self, _: &mut Context) -> Result<()> {
394        self.open()
395    }
396
397    fn read(&self, _: &mut Context, buffer: &mut [u8], absolute_position: Size) -> Result<usize> {
398        self.read(buffer, absolute_position)
399    }
400
401    fn write(&self, _: &mut Context, buffer: &[u8], absolute_position: Size) -> Result<usize> {
402        self.write(buffer, absolute_position)
403    }
404
405    fn write_pattern(
406        &self,
407        _: &mut Context,
408        pattern: &[u8],
409        count: usize,
410        absolute_position: Size,
411    ) -> Result<usize> {
412        self.write_pattern(pattern, count, absolute_position)
413    }
414
415    fn write_vectored(
416        &self,
417        _context: &mut Context,
418        buffers: &[&[u8]],
419        absolute_position: Size,
420    ) -> Result<usize> {
421        self.write_vectored(buffers, absolute_position)
422    }
423
424    fn flush(&self, _: &mut Context) -> Result<()> {
425        self.flush()
426    }
427
428    fn set_position(
429        &self,
430        _context: &mut Context,
431        current_position: Size,
432        position: &Position,
433    ) -> Result<Size> {
434        self.set_position(current_position, position)
435    }
436
437    fn control(
438        &self,
439        _: &mut Context,
440        command: ControlCommandIdentifier,
441        input: &AnyByLayout,
442        output: &mut AnyByLayout,
443    ) -> Result<()> {
444        self.control(command, input, output)
445    }
446
447    fn clone_context(&self, _context: &Context) -> Result<Context> {
448        Ok(Context::new_empty())
449    }
450}