Skip to main content

axfatfs/
io.rs

1use crate::error::IoError;
2
3/// Provides IO error as an associated type.
4///
5/// Must be implemented for all types that also implement at least one of the following traits: `Read`, `Write`,
6/// `Seek`.
7pub trait IoBase {
8    /// Type of errors returned by input/output operations.
9    type Error: IoError;
10}
11
12/// The `Read` trait allows for reading bytes from a source.
13///
14/// It is based on the `std::io::Read` trait.
15pub trait Read: IoBase {
16    /// Pull some bytes from this source into the specified buffer, returning how many bytes were read.
17    ///
18    /// This function does not provide any guarantees about whether it blocks waiting for data, but if an object needs
19    /// to block for a read and cannot, it will typically signal this via an Err return value.
20    ///
21    /// If the return value of this method is `Ok(n)`, then it must be guaranteed that `0 <= n <= buf.len()`. A nonzero
22    /// `n` value indicates that the buffer buf has been filled in with n bytes of data from this source. If `n` is
23    /// `0`, then it can indicate one of two scenarios:
24    ///
25    /// 1. This reader has reached its "end of file" and will likely no longer be able to produce bytes. Note that this
26    ///    does not mean that the reader will always no longer be able to produce bytes.
27    /// 2. The buffer specified was 0 bytes in length.
28    ///
29    /// It is not an error if the returned value `n` is smaller than the buffer size, even when the reader is not at
30    /// the end of the stream yet. This may happen for example because fewer bytes are actually available right now
31    /// (e. g. being close to end-of-file) or because `read()` was interrupted by a signal.
32    ///
33    /// # Errors
34    ///
35    /// If this function encounters any form of I/O or other error, an error will be returned. If an error is returned
36    /// then it must be guaranteed that no bytes were read.
37    /// An error for which `IoError::is_interrupted` returns true is non-fatal and the read operation should be retried
38    /// if there is nothing else to do.
39    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
40
41    /// Read the exact number of bytes required to fill `buf`.
42    ///
43    /// This function reads as many bytes as necessary to completely fill the specified buffer `buf`.
44    ///
45    /// # Errors
46    ///
47    /// If this function encounters an error for which `IoError::is_interrupted` returns true then the error is ignored
48    /// and the operation will continue.
49    ///
50    /// If this function encounters an end of file before completely filling the buffer, it returns an error
51    /// instantiated by a call to `IoError::new_unexpected_eof_error`. The contents of `buf` are unspecified in this
52    /// case.
53    ///
54    /// If this function returns an error, it is unspecified how many bytes it has read, but it will never read more
55    /// than would be necessary to completely fill the buffer.
56    fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), Self::Error> {
57        while !buf.is_empty() {
58            match self.read(buf) {
59                Ok(0) => break,
60                Ok(n) => {
61                    let tmp = buf;
62                    buf = &mut tmp[n..];
63                }
64                Err(ref e) if e.is_interrupted() => {}
65                Err(e) => return Err(e),
66            }
67        }
68        if buf.is_empty() {
69            Ok(())
70        } else {
71            debug!("failed to fill whole buffer in read_exact");
72            Err(Self::Error::new_unexpected_eof_error())
73        }
74    }
75}
76
77/// The `Write` trait allows for writing bytes into the sink.
78///
79/// It is based on the `std::io::Write` trait.
80pub trait Write: IoBase {
81    /// Write a buffer into this writer, returning how many bytes were written.
82    ///
83    /// # Errors
84    ///
85    /// Each call to write may generate an I/O error indicating that the operation could not be completed. If an error
86    /// is returned then no bytes in the buffer were written to this writer.
87    /// It is not considered an error if the entire buffer could not be written to this writer.
88    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error>;
89
90    /// Attempts to write an entire buffer into this writer.
91    ///
92    /// This method will continuously call `write` until there is no more data to be written or an error is returned.
93    /// Errors for which `IoError::is_interrupted` method returns true are being skipped. This method will not return
94    /// until the entire buffer has been successfully written or such an error occurs.
95    /// If `write` returns 0 before the entire buffer has been written this method will return an error instantiated by
96    /// a call to `IoError::new_write_zero_error`.
97    ///
98    /// # Errors
99    ///
100    /// This function will return the first error for which `IoError::is_interrupted` method returns false that `write`
101    /// returns.
102    fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::Error> {
103        while !buf.is_empty() {
104            match self.write(buf) {
105                Ok(0) => {
106                    debug!("failed to write whole buffer in write_all");
107                    return Err(Self::Error::new_write_zero_error());
108                }
109                Ok(n) => buf = &buf[n..],
110                Err(ref e) if e.is_interrupted() => {}
111                Err(e) => return Err(e),
112            }
113        }
114        Ok(())
115    }
116
117    /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
118    ///
119    /// # Errors
120    ///
121    /// It is considered an error if not all bytes could be written due to I/O errors or EOF being reached.
122    fn flush(&mut self) -> Result<(), Self::Error>;
123}
124
125/// Enumeration of possible methods to seek within an I/O object.
126///
127/// It is based on the `std::io::SeekFrom` enum.
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub enum SeekFrom {
130    /// Sets the offset to the provided number of bytes.
131    Start(u64),
132    /// Sets the offset to the size of this object plus the specified number of bytes.
133    End(i64),
134    /// Sets the offset to the current position plus the specified number of bytes.
135    Current(i64),
136}
137
138/// The `Seek` trait provides a cursor which can be moved within a stream of bytes.
139///
140/// It is based on the `std::io::Seek` trait.
141pub trait Seek: IoBase {
142    /// Seek to an offset, in bytes, in a stream.
143    ///
144    /// A seek beyond the end of a stream or to a negative position is not allowed.
145    ///
146    /// If the seek operation completed successfully, this method returns the new position from the start of the
147    /// stream. That position can be used later with `SeekFrom::Start`.
148    ///
149    /// # Errors
150    /// Seeking to a negative offset is considered an error.
151    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error>;
152}
153
154#[cfg(feature = "std")]
155impl From<SeekFrom> for std::io::SeekFrom {
156    fn from(from: SeekFrom) -> Self {
157        match from {
158            SeekFrom::Start(n) => std::io::SeekFrom::Start(n),
159            SeekFrom::End(n) => std::io::SeekFrom::End(n),
160            SeekFrom::Current(n) => std::io::SeekFrom::Current(n),
161        }
162    }
163}
164
165#[cfg(feature = "std")]
166impl From<std::io::SeekFrom> for SeekFrom {
167    fn from(from: std::io::SeekFrom) -> Self {
168        match from {
169            std::io::SeekFrom::Start(n) => SeekFrom::Start(n),
170            std::io::SeekFrom::End(n) => SeekFrom::End(n),
171            std::io::SeekFrom::Current(n) => SeekFrom::Current(n),
172        }
173    }
174}
175
176/// A wrapper struct for types that have implementations for `std::io` traits.
177///
178/// `Read`, `Write`, `Seek` traits from this crate are implemented for this type if
179/// corresponding types from `std::io` are implemented by the inner instance.
180#[cfg(feature = "std")]
181pub struct StdIoWrapper<T> {
182    inner: T,
183}
184
185#[cfg(feature = "std")]
186impl<T> StdIoWrapper<T> {
187    /// Creates a new `StdIoWrapper` instance that wraps the provided `inner` instance.
188    pub fn new(inner: T) -> Self {
189        Self { inner }
190    }
191
192    /// Returns inner struct
193    pub fn into_inner(self) -> T {
194        self.inner
195    }
196}
197
198#[cfg(feature = "std")]
199impl<T> IoBase for StdIoWrapper<T> {
200    type Error = std::io::Error;
201}
202
203#[cfg(feature = "std")]
204impl<T: std::io::Read> Read for StdIoWrapper<T> {
205    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
206        self.inner.read(buf)
207    }
208    fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::Error> {
209        self.inner.read_exact(buf)
210    }
211}
212
213#[cfg(feature = "std")]
214impl<T: std::io::Write> Write for StdIoWrapper<T> {
215    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
216        self.inner.write(buf)
217    }
218
219    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
220        self.inner.write_all(buf)
221    }
222
223    fn flush(&mut self) -> Result<(), Self::Error> {
224        self.inner.flush()
225    }
226}
227
228#[cfg(feature = "std")]
229impl<T: std::io::Seek> Seek for StdIoWrapper<T> {
230    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
231        self.inner.seek(pos.into())
232    }
233}
234
235#[cfg(feature = "std")]
236impl<T> From<T> for StdIoWrapper<T> {
237    fn from(from: T) -> Self {
238        Self::new(from)
239    }
240}
241
242pub(crate) trait ReadLeExt {
243    type Error;
244    fn read_u8(&mut self) -> Result<u8, Self::Error>;
245    fn read_u16_le(&mut self) -> Result<u16, Self::Error>;
246    fn read_u32_le(&mut self) -> Result<u32, Self::Error>;
247}
248
249impl<T: Read> ReadLeExt for T {
250    type Error = <Self as IoBase>::Error;
251
252    fn read_u8(&mut self) -> Result<u8, Self::Error> {
253        let mut buf = [0_u8; 1];
254        self.read_exact(&mut buf)?;
255        Ok(buf[0])
256    }
257
258    fn read_u16_le(&mut self) -> Result<u16, Self::Error> {
259        let mut buf = [0_u8; 2];
260        self.read_exact(&mut buf)?;
261        Ok(u16::from_le_bytes(buf))
262    }
263
264    fn read_u32_le(&mut self) -> Result<u32, Self::Error> {
265        let mut buf = [0_u8; 4];
266        self.read_exact(&mut buf)?;
267        Ok(u32::from_le_bytes(buf))
268    }
269}
270
271pub(crate) trait WriteLeExt {
272    type Error;
273    fn write_u8(&mut self, n: u8) -> Result<(), Self::Error>;
274    fn write_u16_le(&mut self, n: u16) -> Result<(), Self::Error>;
275    fn write_u32_le(&mut self, n: u32) -> Result<(), Self::Error>;
276}
277
278impl<T: Write> WriteLeExt for T {
279    type Error = <Self as IoBase>::Error;
280
281    fn write_u8(&mut self, n: u8) -> Result<(), Self::Error> {
282        self.write_all(&[n])
283    }
284
285    fn write_u16_le(&mut self, n: u16) -> Result<(), Self::Error> {
286        self.write_all(&n.to_le_bytes())
287    }
288
289    fn write_u32_le(&mut self, n: u32) -> Result<(), Self::Error> {
290        self.write_all(&n.to_le_bytes())
291    }
292}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297
298    #[test]
299    fn test_seek_from_variants() {
300        let start = SeekFrom::Start(100);
301        assert_eq!(start, SeekFrom::Start(100));
302        assert_ne!(start, SeekFrom::End(-10));
303
304        let end = SeekFrom::End(-50);
305        assert_eq!(end, SeekFrom::End(-50));
306        assert_ne!(end, SeekFrom::Current(10));
307
308        let current = SeekFrom::Current(20);
309        assert_eq!(current, SeekFrom::Current(20));
310        assert_ne!(current, SeekFrom::Start(20));
311    }
312
313    #[test]
314    fn test_seek_from_debug() {
315        assert_eq!(format!("{:?}", SeekFrom::Start(42)), "Start(42)");
316        assert_eq!(format!("{:?}", SeekFrom::End(-10)), "End(-10)");
317        assert_eq!(format!("{:?}", SeekFrom::Current(5)), "Current(5)");
318    }
319
320    #[test]
321    fn test_seek_from_clone_copy() {
322        let start = SeekFrom::Start(100);
323        let cloned = start.clone();
324        assert_eq!(start, cloned);
325
326        let copied = start;
327        assert_eq!(start, copied);
328    }
329
330    #[cfg(feature = "std")]
331    #[test]
332    fn test_seek_from_std_conversion() {
333        let fatfs_seek = SeekFrom::Start(100);
334        let std_seek: std::io::SeekFrom = fatfs_seek.into();
335        assert_eq!(std_seek, std::io::SeekFrom::Start(100));
336
337        let std_seek = std::io::SeekFrom::End(-50);
338        let fatfs_seek: SeekFrom = std_seek.into();
339        assert_eq!(fatfs_seek, SeekFrom::End(-50));
340
341        let fatfs_seek = SeekFrom::Current(20);
342        let std_seek: std::io::SeekFrom = fatfs_seek.into();
343        assert_eq!(std_seek, std::io::SeekFrom::Current(20));
344    }
345
346    #[cfg(feature = "std")]
347    #[test]
348    fn test_std_io_wrapper() {
349        let mut cursor = std::io::Cursor::new(vec![0u8; 100]);
350        let wrapper = StdIoWrapper::new(&mut cursor);
351
352        // Test IoBase
353        let inner = wrapper.into_inner();
354        let wrapper2 = StdIoWrapper::new(inner);
355        let _inner = wrapper2.into_inner();
356    }
357
358    #[cfg(feature = "std")]
359    #[test]
360    fn test_std_io_wrapper_from() {
361        let cursor = std::io::Cursor::new(vec![0u8; 100]);
362        let wrapper: StdIoWrapper<_> = StdIoWrapper::from(cursor);
363        assert_eq!(wrapper.into_inner().into_inner().len(), 100);
364    }
365}