layered_io/
read_layered.rs

1use super::{Bufferable, Status};
2use std::io::{self, IoSliceMut, Read};
3
4/// An extension of [`Read`], with `read_with_status` and
5/// `read_vectored_with_status` which return status information and zero is not
6/// special-cased. It also allows streams to specify a `minimum_buffer_size`.
7pub trait ReadLayered: Read + Bufferable {
8    /// Like [`Read::read`], but also returns a `Status`.
9    fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)>;
10
11    /// Like [`Read::read_vectored`], but also returns a `Status`.
12    #[inline]
13    fn read_vectored_with_status(
14        &mut self,
15        bufs: &mut [IoSliceMut<'_>],
16    ) -> io::Result<(usize, Status)> {
17        default_read_vectored_with_status(self, bufs)
18    }
19
20    /// Like `Read::read_exact`, but uses `read_with_status` to avoid
21    /// performing an extra `read` at the end.
22    #[inline]
23    fn read_exact_using_status(&mut self, buf: &mut [u8]) -> io::Result<Status> {
24        default_read_exact_using_status(self, buf)
25    }
26
27    /// Some streams require a buffer of at least a certain size.
28    #[inline]
29    fn minimum_buffer_size(&self) -> usize {
30        0
31    }
32}
33
34/// Default implementation of [`Read::read`] in terms of
35/// [`ReadLayered::read_with_status`].
36#[inline]
37pub fn default_read<Inner: ReadLayered + ?Sized>(
38    inner: &mut Inner,
39    buf: &mut [u8],
40) -> io::Result<usize> {
41    inner.read_with_status(buf).and_then(to_std_io_read_result)
42}
43
44/// Default implementation of [`Read::read_vectored`] in terms of
45/// [`ReadLayered::read_vectored_with_status`].
46pub fn default_read_vectored<Inner: ReadLayered + ?Sized>(
47    inner: &mut Inner,
48    bufs: &mut [IoSliceMut<'_>],
49) -> io::Result<usize> {
50    inner
51        .read_vectored_with_status(bufs)
52        .and_then(to_std_io_read_result)
53}
54
55/// Default implementation of [`Read::read_to_end`] in terms of
56/// [`ReadLayered::read_with_status`].
57#[allow(clippy::indexing_slicing)]
58pub fn default_read_to_end<Inner: ReadLayered + ?Sized>(
59    inner: &mut Inner,
60    buf: &mut Vec<u8>,
61) -> io::Result<usize> {
62    let start_len = buf.len();
63    let buffer_size = inner.suggested_buffer_size();
64    let mut read_len = buffer_size;
65    loop {
66        let read_pos = buf.len();
67
68        // Allocate space in the buffer. This needlessly zeros out the
69        // memory, however the current way to avoid it is to be part of the
70        // standard library so that we can make assumptions about the
71        // compiler not exploiting undefined behavior.
72        // https://github.com/rust-lang/rust/issues/42788 for details.
73        buf.resize(read_pos + read_len, 0);
74
75        match inner.read_with_status(&mut buf[read_pos..]) {
76            Ok((size, status)) => {
77                buf.resize(read_pos + size, 0);
78                match status {
79                    Status::Open(_) => {
80                        read_len -= size;
81                        if read_len < inner.minimum_buffer_size() {
82                            read_len += buffer_size;
83                        }
84                    }
85                    Status::End => return Ok(buf.len() - start_len),
86                }
87            }
88            Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
89            Err(e) => {
90                buf.resize(start_len, 0);
91                return Err(e);
92            }
93        }
94    }
95}
96
97/// Default implementation of [`Read::read_to_string`] in terms of
98/// [`Read::read_to_end`].
99pub fn default_read_to_string<Inner: ReadLayered + ?Sized>(
100    inner: &mut Inner,
101    buf: &mut String,
102) -> io::Result<usize> {
103    // Allocate a `Vec` and read into it. This needlessly allocates,
104    // rather than reading directly into `buf`'s buffer, but similarly
105    // avoids issues of undefined behavior for now.
106    let mut vec = Vec::new();
107    let size = inner.read_to_end(&mut vec)?;
108    let new = String::from_utf8(vec).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
109    buf.push_str(&new);
110    Ok(size)
111}
112
113/// Default implementation of [`ReadLayered::read_exact_using_status`] in terms
114/// of [`ReadLayered::read_with_status`].
115#[allow(clippy::indexing_slicing)]
116pub fn default_read_exact_using_status<Inner: ReadLayered + ?Sized>(
117    inner: &mut Inner,
118    mut buf: &mut [u8],
119) -> io::Result<Status> {
120    let mut result_status = Status::active();
121
122    while !buf.is_empty() {
123        match inner.read_with_status(buf) {
124            Ok((size, status)) => {
125                let t = buf;
126                buf = &mut t[size..];
127                if status.is_end() {
128                    result_status = status;
129                    break;
130                }
131            }
132            Err(e) => return Err(e),
133        }
134    }
135
136    if buf.is_empty() {
137        Ok(result_status)
138    } else {
139        Err(io::Error::new(
140            io::ErrorKind::UnexpectedEof,
141            "failed to fill whole buffer",
142        ))
143    }
144}
145
146/// Default implementation of [`ReadLayered::read_vectored_with_status`] in
147/// terms of [`ReadLayered::read_with_status`].
148pub fn default_read_vectored_with_status<Inner: ReadLayered + ?Sized>(
149    inner: &mut Inner,
150    bufs: &mut [IoSliceMut<'_>],
151) -> io::Result<(usize, Status)> {
152    let buf = bufs
153        .iter_mut()
154        .find(|b| !b.is_empty())
155        .map_or(&mut [][..], |b| &mut **b);
156    inner.read_with_status(buf)
157}
158
159/// Default implementation of [`Read::is_read_vectored`] accompanying
160/// [`default_read_vectored_with_status`].
161#[cfg(can_vector)]
162pub fn default_is_read_vectored<Inner: ReadLayered + ?Sized>(_inner: &Inner) -> bool {
163    false
164}
165
166/// Translate from `read_with_status`'s return value with independent size and
167/// status to a [`std::io::Read::read`] return value where 0 is special-cased
168/// to mean end-of-stream, an `io::ErrorKind::Interrupted` error is used to
169/// indicate a zero-length read, and pushes are not reported.
170pub fn to_std_io_read_result(size_and_status: (usize, Status)) -> io::Result<usize> {
171    match size_and_status {
172        (0, Status::Open(_)) => Err(io::Error::new(
173            io::ErrorKind::Interrupted,
174            "read zero bytes from stream",
175        )),
176        (size, _) => Ok(size),
177    }
178}
179
180impl<R: ReadLayered> ReadLayered for Box<R> {
181    #[inline]
182    fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
183        self.as_mut().read_with_status(buf)
184    }
185
186    #[inline]
187    fn read_vectored_with_status(
188        &mut self,
189        bufs: &mut [IoSliceMut<'_>],
190    ) -> io::Result<(usize, Status)> {
191        self.as_mut().read_vectored_with_status(bufs)
192    }
193
194    #[inline]
195    fn minimum_buffer_size(&self) -> usize {
196        self.as_ref().minimum_buffer_size()
197    }
198}
199
200impl<R: ReadLayered> ReadLayered for &mut R {
201    #[inline]
202    fn read_with_status(&mut self, buf: &mut [u8]) -> io::Result<(usize, Status)> {
203        (**self).read_with_status(buf)
204    }
205
206    #[inline]
207    fn read_vectored_with_status(
208        &mut self,
209        bufs: &mut [IoSliceMut<'_>],
210    ) -> io::Result<(usize, Status)> {
211        (**self).read_vectored_with_status(bufs)
212    }
213
214    #[inline]
215    fn minimum_buffer_size(&self) -> usize {
216        (**self).minimum_buffer_size()
217    }
218}