axio/
lib.rs

1//! [`std::io`]-like I/O traits for `no_std` environment.
2
3#![cfg_attr(not(doc), no_std)]
4#![feature(doc_cfg)]
5#![feature(core_io_borrowed_buf)]
6#![cfg_attr(not(borrowedbuf_init), feature(maybe_uninit_fill))]
7
8#[cfg(feature = "alloc")]
9extern crate alloc;
10
11use core::fmt;
12
13mod buffered;
14mod error;
15mod impls;
16
17pub mod prelude;
18
19pub use self::buffered::BufReader;
20pub use self::error::{Error, Result};
21
22#[cfg(feature = "alloc")]
23use alloc::{string::String, vec::Vec};
24
25use axerrno::ax_err;
26
27/// Default [`Read::read_to_end`] implementation with optional size hint.
28///
29/// Adapted from [`std::io::default_read_to_end`].
30///
31/// [`std::io::default_read_to_end`]: https://github.com/rust-lang/rust/blob/30f168ef811aec63124eac677e14699baa9395bd/library/std/src/io/mod.rs#L409
32#[cfg(feature = "alloc")]
33pub fn default_read_to_end<R: Read + ?Sized>(
34    r: &mut R,
35    buf: &mut Vec<u8>,
36    size_hint: Option<usize>,
37) -> Result<usize> {
38    use core::io::BorrowedBuf;
39
40    const DEFAULT_BUF_SIZE: usize = 1024;
41
42    let start_len = buf.len();
43    let start_cap = buf.capacity();
44    // Optionally limit the maximum bytes read on each iteration.
45    // This adds an arbitrary fiddle factor to allow for more data than we expect.
46    let mut max_read_size = size_hint
47        .and_then(|s| {
48            s.checked_add(1024)?
49                .checked_next_multiple_of(DEFAULT_BUF_SIZE)
50        })
51        .unwrap_or(DEFAULT_BUF_SIZE);
52
53    const PROBE_SIZE: usize = 32;
54
55    fn small_probe_read<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
56        let mut probe = [0u8; PROBE_SIZE];
57
58        let n = r.read(&mut probe)?;
59        buf.extend_from_slice(&probe[..n]);
60        Ok(n)
61    }
62
63    if (size_hint.is_none() || size_hint == Some(0)) && buf.capacity() - buf.len() < PROBE_SIZE {
64        let read = small_probe_read(r, buf)?;
65
66        if read == 0 {
67            return Ok(0);
68        }
69    }
70
71    #[cfg(borrowedbuf_init)]
72    let mut initialized = 0; // Extra initialized bytes from previous loop iteration
73    #[cfg(borrowedbuf_init)]
74    let mut consecutive_short_reads = 0;
75
76    loop {
77        if buf.len() == buf.capacity() && buf.capacity() == start_cap {
78            // The buffer might be an exact fit. Let's read into a probe buffer
79            // and see if it returns `Ok(0)`. If so, we've avoided an
80            // unnecessary doubling of the capacity. But if not, append the
81            // probe buffer to the primary buffer and let its capacity grow.
82            let read = small_probe_read(r, buf)?;
83
84            if read == 0 {
85                return Ok(buf.len() - start_len);
86            }
87        }
88
89        if buf.len() == buf.capacity() {
90            // buf is full, need more space
91            if let Err(e) = buf.try_reserve(PROBE_SIZE) {
92                return ax_err!(NoMemory, e);
93            }
94        }
95
96        let mut spare = buf.spare_capacity_mut();
97        let buf_len = spare.len().min(max_read_size);
98        spare = &mut spare[..buf_len];
99        let mut read_buf: BorrowedBuf<'_> = spare.into();
100
101        #[cfg(borrowedbuf_init)]
102        // SAFETY: These bytes were initialized but not filled in the previous loop
103        unsafe {
104            read_buf.set_init(initialized);
105        }
106
107        let mut cursor = read_buf.unfilled();
108        // Difference from `std`: We don't have a `read_buf` method that returns both data and an error, so we return early on error.
109        #[cfg(borrowedbuf_init)]
110        {
111            let n = r.read(cursor.ensure_init().init_mut())?;
112            cursor.advance(n);
113        }
114        #[cfg(not(borrowedbuf_init))]
115        {
116            // SAFETY: We do not uninitialize any part of the buffer.
117            let n = r.read(unsafe { cursor.as_mut().write_filled(0) })?;
118            assert!(n <= cursor.capacity());
119            // SAFETY: We've initialized the entire buffer, and `read` can't make it uninitialized.
120            unsafe {
121                cursor.advance(n);
122            }
123        }
124
125        #[cfg(borrowedbuf_init)]
126        let unfilled_but_initialized = cursor.init_mut().len();
127        let bytes_read = cursor.written();
128        #[cfg(borrowedbuf_init)]
129        let was_fully_initialized = read_buf.init_len() == buf_len;
130
131        // SAFETY: BorrowedBuf's invariants mean this much memory is initialized.
132        unsafe {
133            let new_len = bytes_read + buf.len();
134            buf.set_len(new_len);
135        }
136
137        if bytes_read == 0 {
138            return Ok(buf.len() - start_len);
139        }
140
141        #[cfg(borrowedbuf_init)]
142        if bytes_read < buf_len {
143            consecutive_short_reads += 1;
144        } else {
145            consecutive_short_reads = 0;
146        }
147
148        #[cfg(borrowedbuf_init)]
149        {
150            // store how much was initialized but not filled
151            initialized = unfilled_but_initialized;
152        }
153
154        // Use heuristics to determine the max read size if no initial size hint was provided
155        if size_hint.is_none() {
156            #[cfg(borrowedbuf_init)]
157            // The reader is returning short reads but it doesn't call ensure_init().
158            // In that case we no longer need to restrict read sizes to avoid
159            // initialization costs.
160            // When reading from disk we usually don't get any short reads except at EOF.
161            // So we wait for at least 2 short reads before uncapping the read buffer;
162            // this helps with the Windows issue.
163            if !was_fully_initialized && consecutive_short_reads > 1 {
164                max_read_size = usize::MAX;
165            }
166
167            // we have passed a larger buffer than previously and the
168            // reader still hasn't returned a short read
169            if buf_len >= max_read_size && bytes_read == buf_len {
170                max_read_size = max_read_size.saturating_mul(2);
171            }
172        }
173    }
174}
175
176/// The `Read` trait allows for reading bytes from a source.
177pub trait Read {
178    /// Pull some bytes from this source into the specified buffer, returning
179    /// how many bytes were read.
180    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
181
182    /// Read all bytes until EOF in this source, placing them into `buf`.
183    #[cfg(feature = "alloc")]
184    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
185        default_read_to_end(self, buf, None)
186    }
187
188    /// Read all bytes until EOF in this source, appending them to `buf`.
189    #[cfg(feature = "alloc")]
190    fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
191        unsafe { append_to_string(buf, |b| self.read_to_end(b)) }
192    }
193
194    /// Read the exact number of bytes required to fill `buf`.
195    fn read_exact(&mut self, mut buf: &mut [u8]) -> Result {
196        while !buf.is_empty() {
197            match self.read(buf) {
198                Ok(0) => break,
199                Ok(n) => {
200                    let tmp = buf;
201                    buf = &mut tmp[n..];
202                }
203                Err(e) => return Err(e),
204            }
205        }
206        if !buf.is_empty() {
207            ax_err!(UnexpectedEof, "failed to fill whole buffer")
208        } else {
209            Ok(())
210        }
211    }
212}
213
214/// A trait for objects which are byte-oriented sinks.
215pub trait Write {
216    /// Write a buffer into this writer, returning how many bytes were written.
217    fn write(&mut self, buf: &[u8]) -> Result<usize>;
218
219    /// Flush this output stream, ensuring that all intermediately buffered
220    /// contents reach their destination.
221    fn flush(&mut self) -> Result;
222
223    /// Attempts to write an entire buffer into this writer.
224    fn write_all(&mut self, mut buf: &[u8]) -> Result {
225        while !buf.is_empty() {
226            match self.write(buf) {
227                Ok(0) => return ax_err!(WriteZero, "failed to write whole buffer"),
228                Ok(n) => buf = &buf[n..],
229                Err(e) => return Err(e),
230            }
231        }
232        Ok(())
233    }
234
235    /// Writes a formatted string into this writer, returning any error
236    /// encountered.
237    fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
238        // Create a shim which translates a Write to a fmt::Write and saves
239        // off I/O errors. instead of discarding them
240        struct Adapter<'a, T: ?Sized + 'a> {
241            inner: &'a mut T,
242            error: Result<()>,
243        }
244
245        impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
246            fn write_str(&mut self, s: &str) -> fmt::Result {
247                match self.inner.write_all(s.as_bytes()) {
248                    Ok(()) => Ok(()),
249                    Err(e) => {
250                        self.error = Err(e);
251                        Err(fmt::Error)
252                    }
253                }
254            }
255        }
256
257        let mut output = Adapter {
258            inner: self,
259            error: Ok(()),
260        };
261        match fmt::write(&mut output, fmt) {
262            Ok(()) => Ok(()),
263            Err(..) => {
264                // check if the error came from the underlying `Write` or not
265                if output.error.is_err() {
266                    output.error
267                } else {
268                    ax_err!(InvalidData, "formatter error")
269                }
270            }
271        }
272    }
273}
274
275/// The `Seek` trait provides a cursor which can be moved within a stream of
276/// bytes.
277pub trait Seek {
278    /// Seek to an offset, in bytes, in a stream.
279    ///
280    /// A seek beyond the end of a stream is allowed, but behavior is defined
281    /// by the implementation.
282    ///
283    /// If the seek operation completed successfully,
284    /// this method returns the new position from the start of the stream.
285    /// That position can be used later with [`SeekFrom::Start`].
286    fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
287
288    /// Rewind to the beginning of a stream.
289    ///
290    /// This is a convenience method, equivalent to `seek(SeekFrom::Start(0))`.
291    fn rewind(&mut self) -> Result<()> {
292        self.seek(SeekFrom::Start(0))?;
293        Ok(())
294    }
295
296    /// Returns the current seek position from the start of the stream.
297    ///
298    /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
299    fn stream_position(&mut self) -> Result<u64> {
300        self.seek(SeekFrom::Current(0))
301    }
302}
303
304/// Enumeration of possible methods to seek within an I/O object.
305///
306/// It is used by the [`Seek`] trait.
307#[derive(Copy, PartialEq, Eq, Clone, Debug)]
308pub enum SeekFrom {
309    /// Sets the offset to the provided number of bytes.
310    Start(u64),
311
312    /// Sets the offset to the size of this object plus the specified number of
313    /// bytes.
314    ///
315    /// It is possible to seek beyond the end of an object, but it's an error to
316    /// seek before byte 0.
317    End(i64),
318
319    /// Sets the offset to the current position plus the specified number of
320    /// bytes.
321    ///
322    /// It is possible to seek beyond the end of an object, but it's an error to
323    /// seek before byte 0.
324    Current(i64),
325}
326
327/// A `BufRead` is a type of `Read`er which has an internal buffer, allowing it
328/// to perform extra ways of reading.
329pub trait BufRead: Read {
330    /// Returns the contents of the internal buffer, filling it with more data
331    /// from the inner reader if it is empty.
332    fn fill_buf(&mut self) -> Result<&[u8]>;
333
334    /// Tells this buffer that `amt` bytes have been consumed from the buffer,
335    /// so they should no longer be returned in calls to `read`.
336    fn consume(&mut self, amt: usize);
337
338    /// Check if the underlying `Read` has any data left to be read.
339    fn has_data_left(&mut self) -> Result<bool> {
340        self.fill_buf().map(|b| !b.is_empty())
341    }
342
343    /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached.
344    #[cfg(feature = "alloc")]
345    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
346        let mut read = 0;
347        loop {
348            let (done, used) = {
349                let available = match self.fill_buf() {
350                    Ok(n) => n,
351                    Err(Error::WouldBlock) => continue,
352                    Err(e) => return Err(e),
353                };
354                match available.iter().position(|&b| b == byte) {
355                    Some(i) => {
356                        buf.extend_from_slice(&available[..=i]);
357                        (true, i + 1)
358                    }
359                    None => {
360                        buf.extend_from_slice(available);
361                        (false, available.len())
362                    }
363                }
364            };
365            self.consume(used);
366            read += used;
367            if done || used == 0 {
368                return Ok(read);
369            }
370        }
371    }
372
373    /// Read all bytes until a newline (the `0xA` byte) is reached, and append
374    /// them to the provided `String` buffer.
375    #[cfg(feature = "alloc")]
376    fn read_line(&mut self, buf: &mut String) -> Result<usize> {
377        unsafe { append_to_string(buf, |b| self.read_until(b'\n', b)) }
378    }
379}
380
381#[cfg(feature = "alloc")]
382unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
383where
384    F: FnOnce(&mut Vec<u8>) -> Result<usize>,
385{
386    let old_len = buf.len();
387    let buf = unsafe { buf.as_mut_vec() };
388    let ret = f(buf)?;
389    if core::str::from_utf8(&buf[old_len..]).is_err() {
390        ax_err!(InvalidData, "stream did not contain valid UTF-8")
391    } else {
392        Ok(ret)
393    }
394}
395
396/// I/O poll results.
397#[derive(Debug, Default, Clone, Copy)]
398pub struct PollState {
399    /// Object can be read now.
400    pub readable: bool,
401    /// Object can be writen now.
402    pub writable: bool,
403}