From cada71e3f4a0bcd2886b278523dd07eeff2e3e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 19 Dec 2022 20:16:49 +0100 Subject: [PATCH 1/3] `io::Chain`: specialize some `Read` methods --- library/std/src/io/mod.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 23a13523fc275..23159459a70e0 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2389,6 +2389,39 @@ impl Read for Chain { } self.second.read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + self.first.is_read_vectored() || self.second.is_read_vectored() + } + + fn read_to_end(&mut self, buf: &mut Vec) -> Result { + let mut read = 0; + if !self.done_first { + read += self.first.read_to_end(buf)?; + self.done_first = true; + } + read += self.second.read_to_end(buf)?; + Ok(read) + } + + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { + if buf.capacity() == 0 { + return Ok(()); + } + + if !self.done_first { + let old_len = buf.written(); + self.first.read_buf(buf.reborrow())?; + + if buf.written() != old_len { + return Ok(()); + } else { + self.done_first = true; + } + } + self.second.read_buf(buf) + } } #[stable(feature = "chain_bufread", since = "1.9.0")] From cba6e102ec49d81086a780c12ef3a51f1c2bd340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 19 Dec 2022 20:36:21 +0100 Subject: [PATCH 2/3] `io::Chain`: specialize some `BufRead` methods --- library/std/src/io/mod.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 23159459a70e0..3617b956e8069 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2429,9 +2429,7 @@ impl BufRead for Chain { fn fill_buf(&mut self) -> Result<&[u8]> { if !self.done_first { match self.first.fill_buf()? { - buf if buf.is_empty() => { - self.done_first = true; - } + buf if buf.is_empty() => self.done_first = true, buf => return Ok(buf), } } @@ -2441,6 +2439,21 @@ impl BufRead for Chain { fn consume(&mut self, amt: usize) { if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) } } + + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { + let mut read = 0; + if !self.done_first { + let n = self.first.read_until(byte, buf)?; + read += n; + + match buf.last() { + Some(b) if *b == byte && n != 0 => return Ok(read), + _ => self.done_first = true, + } + } + read += self.second.read_until(byte, buf)?; + Ok(read) + } } impl SizeHint for Chain { From ebc59703292fd216d7ec1e027e0f3b78387a8ddf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Mon, 12 Jun 2023 18:17:48 +0200 Subject: [PATCH 3/3] Add tests and comments about `read_to_string` and `read_line` specializations --- library/std/src/io/mod.rs | 6 ++++++ library/std/src/io/tests.rs | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 3617b956e8069..244512e2780c5 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2405,6 +2405,9 @@ impl Read for Chain { Ok(read) } + // We don't override `read_to_string` here because an UTF-8 sequence could + // be split between the two parts of the chain + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> { if buf.capacity() == 0 { return Ok(()); @@ -2454,6 +2457,9 @@ impl BufRead for Chain { read += self.second.read_until(byte, buf)?; Ok(read) } + + // We don't override `read_line` here because an UTF-8 sequence could be + // split between the two parts of the chain } impl SizeHint for Chain { diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f4a886d889a99..4a205f30d44ba 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -231,6 +231,17 @@ fn chain_bufread() { cmp_bufread(chain1, chain2, &testdata[..]); } +#[test] +fn chain_splitted_char() { + let chain = b"\xc3".chain(b"\xa9".as_slice()); + assert_eq!(crate::io::read_to_string(chain).unwrap(), "é"); + + let mut chain = b"\xc3".chain(b"\xa9\n".as_slice()); + let mut buf = String::new(); + assert_eq!(chain.read_line(&mut buf).unwrap(), 3); + assert_eq!(buf, "é\n"); +} + #[test] fn bufreader_size_hint() { let testdata = b"ABCDEFGHIJKL";