hermit/
io.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::{fmt, result};
4
5// TODO: Integrate with src/errno.rs ?
6#[allow(clippy::upper_case_acronyms)]
7#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)]
8pub enum Error {
9	ENOENT = crate::errno::ENOENT as isize,
10	ENOSYS = crate::errno::ENOSYS as isize,
11	EIO = crate::errno::EIO as isize,
12	EBADF = crate::errno::EBADF as isize,
13	EISDIR = crate::errno::EISDIR as isize,
14	EINVAL = crate::errno::EINVAL as isize,
15	ETIME = crate::errno::ETIME as isize,
16	EAGAIN = crate::errno::EAGAIN as isize,
17	EFAULT = crate::errno::EFAULT as isize,
18	ENOBUFS = crate::errno::ENOBUFS as isize,
19	ENOTCONN = crate::errno::ENOTCONN as isize,
20	ENOTDIR = crate::errno::ENOTDIR as isize,
21	EMFILE = crate::errno::EMFILE as isize,
22	EEXIST = crate::errno::EEXIST as isize,
23	EADDRINUSE = crate::errno::EADDRINUSE as isize,
24	EOVERFLOW = crate::errno::EOVERFLOW as isize,
25	ENOTSOCK = crate::errno::ENOTSOCK as isize,
26}
27
28pub type Result<T> = result::Result<T, Error>;
29
30/// The Read trait allows for reading bytes from a source.
31///
32/// The Read trait is derived from Rust's std library.
33pub trait Read {
34	fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
35
36	/// Read all bytes until EOF in this source, placing them into buf.
37	fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
38		let start_len = buf.len();
39
40		loop {
41			let mut probe = [0u8; 512];
42
43			match self.read(&mut probe) {
44				Ok(0) => return Ok(buf.len() - start_len),
45				Ok(n) => {
46					buf.extend_from_slice(&probe[..n]);
47				}
48				Err(e) => return Err(e),
49			}
50		}
51	}
52
53	/// Read all bytes until EOF in this source, appending them to `buf`.
54	///
55	/// If successful, this function returns the number of bytes which were read
56	/// and appended to `buf`.
57	fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
58		unsafe { self.read_to_end(buf.as_mut_vec()) }
59	}
60}
61
62/// The Write trait allows for reading bytes from a source.
63///
64/// The Write trait is derived from Rust's std library.
65pub trait Write {
66	fn write(&mut self, buf: &[u8]) -> Result<usize>;
67
68	/// Attempts to write an entire buffer into this writer.
69	fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
70		while !buf.is_empty() {
71			match self.write(buf) {
72				Ok(0) => {
73					return Err(Error::EIO);
74				}
75				Ok(n) => buf = &buf[n..],
76				Err(e) => return Err(e),
77			}
78		}
79
80		Ok(())
81	}
82
83	/// Writes a formatted string into this writer, returning any error encountered.
84	fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
85		// Create a shim which translates a Write to a fmt::Write and saves
86		// off I/O errors. instead of discarding them
87		struct Adapter<'a, T: ?Sized> {
88			inner: &'a mut T,
89			error: Result<()>,
90		}
91
92		impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
93			fn write_str(&mut self, s: &str) -> fmt::Result {
94				match self.inner.write_all(s.as_bytes()) {
95					Ok(()) => Ok(()),
96					Err(e) => {
97						self.error = Err(e);
98						Err(fmt::Error)
99					}
100				}
101			}
102		}
103
104		let mut output = Adapter {
105			inner: self,
106			error: Ok(()),
107		};
108		match fmt::write(&mut output, fmt) {
109			Ok(()) => Ok(()),
110			Err(..) => {
111				// check if the error came from the underlying `Write` or not
112				if output.error.is_err() {
113					output.error
114				} else {
115					Err(Error::EINVAL)
116				}
117			}
118		}
119	}
120}