Skip to content

Commit bea5beb

Browse files
committed
Auto merge of #105917 - a1phyr:read_chain_more_impls, r=workingjubilee
Specialize some methods of `io::Chain` This PR specializes the implementation of some methods of `io::Chain`, which could bring performance improvements when using it.
2 parents d573564 + ebc5970 commit bea5beb

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

library/std/src/io/mod.rs

+55-3
Original file line numberDiff line numberDiff line change
@@ -2672,16 +2672,50 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
26722672
}
26732673
self.second.read_vectored(bufs)
26742674
}
2675+
2676+
#[inline]
2677+
fn is_read_vectored(&self) -> bool {
2678+
self.first.is_read_vectored() || self.second.is_read_vectored()
2679+
}
2680+
2681+
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
2682+
let mut read = 0;
2683+
if !self.done_first {
2684+
read += self.first.read_to_end(buf)?;
2685+
self.done_first = true;
2686+
}
2687+
read += self.second.read_to_end(buf)?;
2688+
Ok(read)
2689+
}
2690+
2691+
// We don't override `read_to_string` here because an UTF-8 sequence could
2692+
// be split between the two parts of the chain
2693+
2694+
fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> Result<()> {
2695+
if buf.capacity() == 0 {
2696+
return Ok(());
2697+
}
2698+
2699+
if !self.done_first {
2700+
let old_len = buf.written();
2701+
self.first.read_buf(buf.reborrow())?;
2702+
2703+
if buf.written() != old_len {
2704+
return Ok(());
2705+
} else {
2706+
self.done_first = true;
2707+
}
2708+
}
2709+
self.second.read_buf(buf)
2710+
}
26752711
}
26762712

26772713
#[stable(feature = "chain_bufread", since = "1.9.0")]
26782714
impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
26792715
fn fill_buf(&mut self) -> Result<&[u8]> {
26802716
if !self.done_first {
26812717
match self.first.fill_buf()? {
2682-
buf if buf.is_empty() => {
2683-
self.done_first = true;
2684-
}
2718+
buf if buf.is_empty() => self.done_first = true,
26852719
buf => return Ok(buf),
26862720
}
26872721
}
@@ -2691,6 +2725,24 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
26912725
fn consume(&mut self, amt: usize) {
26922726
if !self.done_first { self.first.consume(amt) } else { self.second.consume(amt) }
26932727
}
2728+
2729+
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
2730+
let mut read = 0;
2731+
if !self.done_first {
2732+
let n = self.first.read_until(byte, buf)?;
2733+
read += n;
2734+
2735+
match buf.last() {
2736+
Some(b) if *b == byte && n != 0 => return Ok(read),
2737+
_ => self.done_first = true,
2738+
}
2739+
}
2740+
read += self.second.read_until(byte, buf)?;
2741+
Ok(read)
2742+
}
2743+
2744+
// We don't override `read_line` here because an UTF-8 sequence could be
2745+
// split between the two parts of the chain
26942746
}
26952747

26962748
impl<T, U> SizeHint for Chain<T, U> {

library/std/src/io/tests.rs

+11
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,17 @@ fn chain_bufread() {
261261
cmp_bufread(chain1, chain2, &testdata[..]);
262262
}
263263

264+
#[test]
265+
fn chain_splitted_char() {
266+
let chain = b"\xc3".chain(b"\xa9".as_slice());
267+
assert_eq!(crate::io::read_to_string(chain).unwrap(), "é");
268+
269+
let mut chain = b"\xc3".chain(b"\xa9\n".as_slice());
270+
let mut buf = String::new();
271+
assert_eq!(chain.read_line(&mut buf).unwrap(), 3);
272+
assert_eq!(buf, \n");
273+
}
274+
264275
#[test]
265276
fn bufreader_size_hint() {
266277
let testdata = b"ABCDEFGHIJKL";

0 commit comments

Comments
 (0)