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}