utf8_io/
read_str.rs

1#[cfg(feature = "layered-io")]
2use layered_io::{ReadLayered, Status};
3use std::io::{self, Read};
4
5/// Extend the `Read` trait with `read_str`, a method for reading UTF-8 data.
6pub trait ReadStr: Read {
7    /// Like `read` but produces the result in a `str`. Be sure to check the
8    /// `size` field of the return value to see how many bytes were written.
9    ///
10    /// `buf` must be at least 4 bytes long, so that any valid UTF-8 codepoint
11    /// can be read.
12    fn read_str(&mut self, buf: &mut str) -> io::Result<usize>;
13
14    /// Like `read_exact` but produces the result in a `str`.
15    #[inline]
16    fn read_exact_str(&mut self, buf: &mut str) -> io::Result<()> {
17        default_read_exact_str(self, buf)
18    }
19}
20
21/// Extend the `ReadLayered` trait with `read_str_with_status`, a method for
22/// reading UTF-8 data.
23#[cfg(feature = "layered-io")]
24pub trait ReadStrLayered: ReadLayered + ReadStr {
25    /// Like `read_with_status` but produces the result in a `str`. Be sure to
26    /// check the return value to see how many bytes were written.
27    ///
28    /// `buf` must be at least 4 bytes long, so that any valid UTF-8 codepoint
29    /// can be read.
30    fn read_str_with_status(&mut self, buf: &mut str) -> io::Result<(usize, Status)>;
31
32    /// Like `read_exact` but produces the result in a `str`.
33    ///
34    /// Also, like `ReadStr::read_exact_str`, but uses `read_str_with_status`
35    /// to avoid performing an extra `read` at the end.
36    #[inline]
37    fn read_exact_str_using_status(&mut self, buf: &mut str) -> io::Result<Status> {
38        default_read_exact_str_using_status(self, buf)
39    }
40}
41
42/// Default implementation of [`ReadStr::read_exact_str`].
43pub fn default_read_exact_str<Inner: ReadStr + ?Sized>(
44    inner: &mut Inner,
45    mut buf: &mut str,
46) -> io::Result<()> {
47    while !buf.is_empty() {
48        match inner.read_str(buf) {
49            Ok(0) => break,
50            Ok(size) => buf = buf.split_at_mut(size).1,
51            Err(e) => return Err(e),
52        }
53    }
54
55    if buf.is_empty() {
56        Ok(())
57    } else {
58        Err(io::Error::new(
59            io::ErrorKind::UnexpectedEof,
60            "failed to fill whole buffer",
61        ))
62    }
63}
64
65/// Default implementation of [`ReadStrLayered::read_exact_str_using_status`].
66#[cfg(feature = "layered-io")]
67pub fn default_read_exact_str_using_status<Inner: ReadStrLayered + ?Sized>(
68    inner: &mut Inner,
69    mut buf: &mut str,
70) -> io::Result<Status> {
71    let mut result_status = Status::active();
72
73    while !buf.is_empty() {
74        match inner.read_str_with_status(buf) {
75            Ok((size, status)) => {
76                buf = buf.split_at_mut(size).1;
77                if status.is_end() {
78                    result_status = status;
79                    break;
80                }
81            }
82            Err(e) => return Err(e),
83        }
84    }
85
86    if buf.is_empty() {
87        Ok(result_status)
88    } else {
89        Err(io::Error::new(
90            io::ErrorKind::UnexpectedEof,
91            "failed to fill whole buffer",
92        ))
93    }
94}