tiny_std/io.rs
1#[cfg(feature = "alloc")]
2use alloc::string::String;
3#[cfg(feature = "alloc")]
4use alloc::vec::Vec;
5use core::{fmt, str};
6
7use rusl::error::Errno;
8
9use crate::error::{Error, Result};
10
11#[cfg(feature = "alloc")]
12pub(crate) mod read_buf;
13
14pub trait Read {
15 /// Read into to provided buffer
16 /// # Errors
17 /// Eventual Errors specific to the implementation
18 fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
19
20 /// Reads to the end of this Reader,
21 /// # Errors
22 /// Eventual Errors specific to the implementation
23 #[cfg(feature = "alloc")]
24 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
25 default_read_to_end(self, buf)
26 }
27
28 /// Reads to the end of the provided buffer
29 /// # Errors
30 /// Eventual Errors specific to the implementation
31 #[cfg(feature = "alloc")]
32 fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
33 default_read_to_string(self, buf)
34 }
35
36 /// Reads exactly enough bytes to fill the buffer
37 /// # Errors
38 /// Eventual Errors specific to the implementation
39 fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
40 default_read_exact(self, buf)
41 }
42
43 /// Get this reader by mut ref
44 /// # Errors
45 /// Eventual Errors specific to the implementation
46 fn by_ref(&mut self) -> &mut Self
47 where
48 Self: Sized,
49 {
50 self
51 }
52}
53
54// This uses an adaptive system to extend the vector when it fills. We want to
55// avoid paying to allocate and zero a huge chunk of memory if the reader only
56// has 4 bytes while still making large reads if the reader does have a ton
57// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
58// time is 4,500 times (!) slower than a default reservation size of 32 if the
59// reader has a very small amount of data to return.
60#[cfg(feature = "alloc")]
61pub(crate) fn default_read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
62 let start_len = buf.len();
63 let start_cap = buf.capacity();
64
65 let mut initialized = 0; // Extra initialized bytes from previous loop iteration
66 loop {
67 if buf.len() == buf.capacity() {
68 buf.reserve(32); // buf is full, need more space
69 }
70
71 let mut read_buf = crate::io::read_buf::ReadBuf::uninit(buf.spare_capacity_mut());
72
73 // SAFETY: These bytes were initialized but not filled in the previous loop
74 unsafe {
75 read_buf.assume_init(initialized);
76 }
77
78 match default_read_buf(|b| r.read(b), &mut read_buf) {
79 Ok(()) => {}
80 Err(ref e) if e.matches_errno(Errno::EINTR) => continue,
81 Err(e) => return Err(e),
82 }
83
84 if read_buf.filled_len() == 0 {
85 return Ok(buf.len() - start_len);
86 }
87
88 // store how much was initialized but not filled
89 initialized = read_buf.initialized_len() - read_buf.filled_len();
90 let new_len = read_buf.filled_len() + buf.len();
91
92 // SAFETY: ReadBuf's invariants mean this much memory is init
93 unsafe {
94 buf.set_len(new_len);
95 }
96
97 if buf.len() == buf.capacity() && buf.capacity() == start_cap {
98 // The buffer might be an exact fit. Let's read into a probe buffer
99 // and see if it returns `Ok(0)`. If so, we've avoided an
100 // unnecessary doubling of the capacity. But if not, append the
101 // probe buffer to the primary buffer and let its capacity grow.
102 let mut probe = [0u8; 32];
103
104 loop {
105 match r.read(&mut probe) {
106 Ok(0) => return Ok(buf.len() - start_len),
107 Ok(n) => {
108 buf.extend_from_slice(&probe[..n]);
109 break;
110 }
111 Err(ref e) if e.matches_errno(Errno::EINTR) => continue,
112 Err(e) => return Err(e),
113 }
114 }
115 }
116 }
117}
118
119#[cfg(feature = "alloc")]
120pub(crate) fn default_read_to_string<R: Read + ?Sized>(
121 r: &mut R,
122 buf: &mut String,
123) -> Result<usize> {
124 // Note that we do *not* call `r.read_to_end()` here. We are passing
125 // `&mut Vec<u8>` (the raw contents of `buf`) into the `read_to_end`
126 // method to fill it up. An arbitrary implementation could overwrite the
127 // entire contents of the vector, not just append to it (which is what
128 // we are expecting).
129 //
130 // To prevent extraneously checking the UTF-8-ness of the entire buffer
131 // we pass it to our hardcoded `default_read_to_end` implementation which
132 // we know is guaranteed to only read data into the end of the buffer.
133 unsafe { append_to_string(buf, |b| default_read_to_end(r, b)) }
134}
135
136// Several `read_to_string` and `read_line` methods in the standard library will
137// append data into a `String` buffer, but we need to be pretty careful when
138// doing this. The implementation will just call `.as_mut_vec()` and then
139// delegate to a byte-oriented reading method, but we must ensure that when
140// returning we never leave `buf` in a state such that it contains invalid UTF-8
141// in its bounds.
142//
143// To this end, we use an RAII guard (to protect against panics) which updates
144// the length of the string when it is dropped. This guard initially truncates
145// the string to the prior length and only after we've validated that the
146// new contents are valid UTF-8 do we allow it to set a longer length.
147//
148// The unsafety in this function is twofold:
149//
150// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8
151// checks.
152// 2. We're passing a raw buffer to the function `f`, and it is expected that
153// the function only *appends* bytes to the buffer. We'll get undefined
154// behavior if existing bytes are overwritten to have non-UTF-8 data.
155#[cfg(feature = "alloc")]
156pub(crate) unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
157where
158 F: FnOnce(&mut Vec<u8>) -> Result<usize>,
159{
160 struct Guard<'a> {
161 buf: &'a mut Vec<u8>,
162 len: usize,
163 }
164
165 impl Drop for Guard<'_> {
166 fn drop(&mut self) {
167 unsafe {
168 self.buf.set_len(self.len);
169 }
170 }
171 }
172
173 let mut g = Guard {
174 len: buf.len(),
175 buf: buf.as_mut_vec(),
176 };
177 let ret = f(g.buf);
178 if str::from_utf8(&g.buf[g.len..]).is_err() {
179 ret.and_then(|_| Err(Error::no_code("Stream did not contain valid UTF-8")))
180 } else {
181 g.len = g.buf.len();
182 ret
183 }
184}
185
186pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [u8]) -> Result<()> {
187 while !buf.is_empty() {
188 match this.read(buf) {
189 Ok(0) => break,
190 Ok(n) => {
191 let tmp = buf;
192 buf = &mut tmp[n..];
193 }
194 Err(ref e) if e.matches_errno(Errno::EINTR) => {}
195 Err(e) => return Err(e),
196 }
197 }
198 if buf.is_empty() {
199 Ok(())
200 } else {
201 Err(Error::no_code("Failed to fill whole buffer"))
202 }
203}
204
205#[cfg(feature = "alloc")]
206pub(crate) fn default_read_buf<F>(read: F, buf: &mut crate::io::read_buf::ReadBuf<'_>) -> Result<()>
207where
208 F: FnOnce(&mut [u8]) -> Result<usize>,
209{
210 let n = read(buf.initialize_unfilled())?;
211 buf.add_filled(n);
212 Ok(())
213}
214
215pub trait Write {
216 /// Tries to write the contents of the provided buffer into this writer
217 /// returning how many bytes were written.
218 /// # Errors
219 /// `Writer` failing to write
220 fn write(&mut self, buf: &[u8]) -> Result<usize>;
221
222 /// Flushes this `Writer`
223 /// # Errors
224 /// Formatting the provided arguments, or the `Writer` failing to write
225 fn flush(&mut self) -> Result<()>;
226
227 /// Writes the full buffer into this `Writer`
228 /// # Errors
229 /// `Writer` failing to write
230 fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
231 while !buf.is_empty() {
232 match self.write(buf) {
233 Ok(0) => {
234 return Err(Error::no_code("failed to write whole buffer"));
235 }
236 Ok(n) => buf = &buf[n..],
237 Err(ref e) if e.matches_errno(Errno::EINTR) => {}
238 Err(e) => return Err(e),
239 }
240 }
241 Ok(())
242 }
243
244 /// Writes format arguments into this `Writer`
245 /// # Errors
246 /// Formatting the provided arguments, or the `Writer` failing to write
247 fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<()> {
248 // Create a shim which translates a Write to a fmt::Write and saves
249 // off I/O errors. instead of discarding them
250 struct Adapter<'a, T: ?Sized + 'a> {
251 inner: &'a mut T,
252 error: Result<()>,
253 }
254
255 impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
256 fn write_str(&mut self, s: &str) -> fmt::Result {
257 match self.inner.write_all(s.as_bytes()) {
258 Ok(()) => Ok(()),
259 Err(e) => {
260 self.error = Err(e);
261 Err(fmt::Error)
262 }
263 }
264 }
265 }
266
267 let mut output = Adapter {
268 inner: self,
269 error: Ok(()),
270 };
271 match fmt::write(&mut output, fmt) {
272 Ok(()) => Ok(()),
273 Err(..) => {
274 // check if the error came from the underlying `Write` or not
275 if output.error.is_err() {
276 output.error
277 } else {
278 Err(Error::no_code("formatter error"))
279 }
280 }
281 }
282 }
283
284 /// Get this `Writer` as a mutable reference
285 fn by_ref(&mut self) -> &mut Self
286 where
287 Self: Sized,
288 {
289 self
290 }
291}