Skip to content

Commit ce76292

Browse files
authored
Rollup merge of #137051 - thaliaarchi:io-optional-impls/empty, r=m-ou-se
Implement default methods for `io::Empty` and `io::Sink` Implements default methods of `io::Read`, `io::BufRead`, and `io::Write` for `io::Empty` and `io::Sink`. These implementations are equivalent to the defaults, except in doing less unnecessary work. `Read::read_to_string` and `BufRead::read_line` both have a redundant call to `str::from_utf8` which can't be inlined from `core` and `Write::write_all_vectored` has slicing logic which can't be simplified (See on [Compiler Explorer](https://rust.godbolt.org/z/KK6xcrWr4)). The rest are optimized to the minimal with `-C opt-level=3`, but this PR gives that benefit to unoptimized builds. This includes an implementation of `Write::write_fmt` which just ignores the `fmt::Arguments<'_>`. This could be problematic whenever a user formatting impl is impure, but the docs do not guarantee that the args will be expanded. Tracked in #136756. r? `@m-ou-se`
2 parents d46cc71 + 523b9d9 commit ce76292

File tree

3 files changed

+218
-13
lines changed

3 files changed

+218
-13
lines changed

library/std/src/io/util.rs

+116
Original file line numberDiff line numberDiff line change
@@ -67,27 +67,83 @@ impl Read for Empty {
6767
fn read_buf(&mut self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
6868
Ok(())
6969
}
70+
71+
#[inline]
72+
fn read_vectored(&mut self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
73+
Ok(0)
74+
}
75+
76+
#[inline]
77+
fn is_read_vectored(&self) -> bool {
78+
// Do not force `Chain<Empty, T>` or `Chain<T, Empty>` to use vectored
79+
// reads, unless the other reader is vectored.
80+
false
81+
}
82+
83+
#[inline]
84+
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
85+
if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
86+
}
87+
88+
#[inline]
89+
fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
90+
if cursor.capacity() != 0 { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
91+
}
92+
93+
#[inline]
94+
fn read_to_end(&mut self, _buf: &mut Vec<u8>) -> io::Result<usize> {
95+
Ok(0)
96+
}
97+
98+
#[inline]
99+
fn read_to_string(&mut self, _buf: &mut String) -> io::Result<usize> {
100+
Ok(0)
101+
}
70102
}
71103
#[stable(feature = "rust1", since = "1.0.0")]
72104
impl BufRead for Empty {
73105
#[inline]
74106
fn fill_buf(&mut self) -> io::Result<&[u8]> {
75107
Ok(&[])
76108
}
109+
77110
#[inline]
78111
fn consume(&mut self, _n: usize) {}
112+
113+
#[inline]
114+
fn has_data_left(&mut self) -> io::Result<bool> {
115+
Ok(false)
116+
}
117+
118+
#[inline]
119+
fn read_until(&mut self, _byte: u8, _buf: &mut Vec<u8>) -> io::Result<usize> {
120+
Ok(0)
121+
}
122+
123+
#[inline]
124+
fn skip_until(&mut self, _byte: u8) -> io::Result<usize> {
125+
Ok(0)
126+
}
127+
128+
#[inline]
129+
fn read_line(&mut self, _buf: &mut String) -> io::Result<usize> {
130+
Ok(0)
131+
}
79132
}
80133

81134
#[stable(feature = "empty_seek", since = "1.51.0")]
82135
impl Seek for Empty {
136+
#[inline]
83137
fn seek(&mut self, _pos: SeekFrom) -> io::Result<u64> {
84138
Ok(0)
85139
}
86140

141+
#[inline]
87142
fn stream_len(&mut self) -> io::Result<u64> {
88143
Ok(0)
89144
}
90145

146+
#[inline]
91147
fn stream_position(&mut self) -> io::Result<u64> {
92148
Ok(0)
93149
}
@@ -118,6 +174,21 @@ impl Write for Empty {
118174
true
119175
}
120176

177+
#[inline]
178+
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
179+
Ok(())
180+
}
181+
182+
#[inline]
183+
fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
184+
Ok(())
185+
}
186+
187+
#[inline]
188+
fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> {
189+
Ok(())
190+
}
191+
121192
#[inline]
122193
fn flush(&mut self) -> io::Result<()> {
123194
Ok(())
@@ -142,6 +213,21 @@ impl Write for &Empty {
142213
true
143214
}
144215

216+
#[inline]
217+
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
218+
Ok(())
219+
}
220+
221+
#[inline]
222+
fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
223+
Ok(())
224+
}
225+
226+
#[inline]
227+
fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> {
228+
Ok(())
229+
}
230+
145231
#[inline]
146232
fn flush(&mut self) -> io::Result<()> {
147233
Ok(())
@@ -301,6 +387,21 @@ impl Write for Sink {
301387
true
302388
}
303389

390+
#[inline]
391+
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
392+
Ok(())
393+
}
394+
395+
#[inline]
396+
fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
397+
Ok(())
398+
}
399+
400+
#[inline]
401+
fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> {
402+
Ok(())
403+
}
404+
304405
#[inline]
305406
fn flush(&mut self) -> io::Result<()> {
306407
Ok(())
@@ -325,6 +426,21 @@ impl Write for &Sink {
325426
true
326427
}
327428

429+
#[inline]
430+
fn write_all(&mut self, _buf: &[u8]) -> io::Result<()> {
431+
Ok(())
432+
}
433+
434+
#[inline]
435+
fn write_all_vectored(&mut self, _bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
436+
Ok(())
437+
}
438+
439+
#[inline]
440+
fn write_fmt(&mut self, _args: fmt::Arguments<'_>) -> io::Result<()> {
441+
Ok(())
442+
}
443+
328444
#[inline]
329445
fn flush(&mut self) -> io::Result<()> {
330446
Ok(())

library/std/src/io/util/tests.rs

+100-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,51 @@
1+
use crate::fmt;
12
use crate::io::prelude::*;
2-
use crate::io::{BorrowedBuf, Empty, Repeat, SeekFrom, Sink, empty, repeat, sink};
3+
use crate::io::{
4+
BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink,
5+
};
36
use crate::mem::MaybeUninit;
47

8+
struct ErrorDisplay;
9+
10+
impl fmt::Display for ErrorDisplay {
11+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
12+
Err(fmt::Error)
13+
}
14+
}
15+
16+
struct PanicDisplay;
17+
18+
impl fmt::Display for PanicDisplay {
19+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
panic!()
21+
}
22+
}
23+
24+
#[track_caller]
25+
fn test_sinking<W: Write>(mut w: W) {
26+
assert_eq!(w.write(&[]).unwrap(), 0);
27+
assert_eq!(w.write(&[0]).unwrap(), 1);
28+
assert_eq!(w.write(&[0; 1024]).unwrap(), 1024);
29+
w.write_all(&[]).unwrap();
30+
w.write_all(&[0]).unwrap();
31+
w.write_all(&[0; 1024]).unwrap();
32+
let mut bufs =
33+
[IoSlice::new(&[]), IoSlice::new(&[0]), IoSlice::new(&[0; 1024]), IoSlice::new(&[])];
34+
assert!(w.is_write_vectored());
35+
assert_eq!(w.write_vectored(&[]).unwrap(), 0);
36+
assert_eq!(w.write_vectored(&bufs).unwrap(), 1025);
37+
w.write_all_vectored(&mut []).unwrap();
38+
w.write_all_vectored(&mut bufs).unwrap();
39+
assert!(w.flush().is_ok());
40+
assert_eq!(w.by_ref().write(&[0; 1024]).unwrap(), 1024);
41+
// Ignores fmt arguments
42+
w.write_fmt(format_args!("{}", ErrorDisplay)).unwrap();
43+
w.write_fmt(format_args!("{}", PanicDisplay)).unwrap();
44+
}
45+
546
#[test]
647
fn sink_sinks() {
7-
let mut s = sink();
8-
assert_eq!(s.write(&[]).unwrap(), 0);
9-
assert_eq!(s.write(&[0]).unwrap(), 1);
10-
assert_eq!(s.write(&[0; 1024]).unwrap(), 1024);
11-
assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024);
48+
test_sinking(sink());
1249
}
1350

1451
#[test]
@@ -19,6 +56,21 @@ fn empty_reads() {
1956
assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0);
2057
assert_eq!(Read::by_ref(&mut e).read(&mut [0; 1024]).unwrap(), 0);
2158

59+
e.read_exact(&mut []).unwrap();
60+
assert_eq!(e.read_exact(&mut [0]).unwrap_err().kind(), ErrorKind::UnexpectedEof);
61+
assert_eq!(e.read_exact(&mut [0; 1024]).unwrap_err().kind(), ErrorKind::UnexpectedEof);
62+
63+
assert!(!e.is_read_vectored());
64+
assert_eq!(e.read_vectored(&mut []).unwrap(), 0);
65+
let (mut buf1, mut buf1024) = ([0], [0; 1024]);
66+
let bufs = &mut [
67+
IoSliceMut::new(&mut []),
68+
IoSliceMut::new(&mut buf1),
69+
IoSliceMut::new(&mut buf1024),
70+
IoSliceMut::new(&mut []),
71+
];
72+
assert_eq!(e.read_vectored(bufs).unwrap(), 0);
73+
2274
let buf: &mut [MaybeUninit<_>] = &mut [];
2375
let mut buf: BorrowedBuf<'_> = buf.into();
2476
e.read_buf(buf.unfilled()).unwrap();
@@ -42,6 +94,47 @@ fn empty_reads() {
4294
Read::by_ref(&mut e).read_buf(buf.unfilled()).unwrap();
4395
assert_eq!(buf.len(), 0);
4496
assert_eq!(buf.init_len(), 0);
97+
98+
let buf: &mut [MaybeUninit<_>] = &mut [];
99+
let mut buf: BorrowedBuf<'_> = buf.into();
100+
e.read_buf_exact(buf.unfilled()).unwrap();
101+
assert_eq!(buf.len(), 0);
102+
assert_eq!(buf.init_len(), 0);
103+
104+
let buf: &mut [_] = &mut [MaybeUninit::uninit()];
105+
let mut buf: BorrowedBuf<'_> = buf.into();
106+
assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
107+
assert_eq!(buf.len(), 0);
108+
assert_eq!(buf.init_len(), 0);
109+
110+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
111+
let mut buf: BorrowedBuf<'_> = buf.into();
112+
assert_eq!(e.read_buf_exact(buf.unfilled()).unwrap_err().kind(), ErrorKind::UnexpectedEof);
113+
assert_eq!(buf.len(), 0);
114+
assert_eq!(buf.init_len(), 0);
115+
116+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1024];
117+
let mut buf: BorrowedBuf<'_> = buf.into();
118+
assert_eq!(
119+
Read::by_ref(&mut e).read_buf_exact(buf.unfilled()).unwrap_err().kind(),
120+
ErrorKind::UnexpectedEof,
121+
);
122+
assert_eq!(buf.len(), 0);
123+
assert_eq!(buf.init_len(), 0);
124+
125+
let mut buf = Vec::new();
126+
assert_eq!(e.read_to_end(&mut buf).unwrap(), 0);
127+
assert_eq!(buf, vec![]);
128+
let mut buf = vec![1, 2, 3];
129+
assert_eq!(e.read_to_end(&mut buf).unwrap(), 0);
130+
assert_eq!(buf, vec![1, 2, 3]);
131+
132+
let mut buf = String::new();
133+
assert_eq!(e.read_to_string(&mut buf).unwrap(), 0);
134+
assert_eq!(buf, "");
135+
let mut buf = "hello".to_owned();
136+
assert_eq!(e.read_to_string(&mut buf).unwrap(), 0);
137+
assert_eq!(buf, "hello");
45138
}
46139

47140
#[test]
@@ -66,11 +159,7 @@ fn empty_seeks() {
66159

67160
#[test]
68161
fn empty_sinks() {
69-
let mut e = empty();
70-
assert_eq!(e.write(&[]).unwrap(), 0);
71-
assert_eq!(e.write(&[0]).unwrap(), 1);
72-
assert_eq!(e.write(&[0; 1024]).unwrap(), 1024);
73-
assert_eq!(Write::by_ref(&mut e).write(&[0; 1024]).unwrap(), 1024);
162+
test_sinking(empty());
74163
}
75164

76165
#[test]

tests/ui/write-fmt-errors.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#![feature(io_error_uncategorized)]
55

66
use std::fmt;
7-
use std::io::{self, Error, Write, sink};
7+
use std::io::{self, Error, Write};
88
use std::panic::catch_unwind;
99

1010
struct ErrorDisplay;
@@ -33,7 +33,7 @@ fn main() {
3333
assert!(res.is_err(), "writer error did not propagate");
3434

3535
// Test that the error from the formatter is detected.
36-
let res = catch_unwind(|| write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar"));
36+
let res = catch_unwind(|| write!(vec![], "{} {} {}", 1, ErrorDisplay, "bar"));
3737
let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap();
3838
assert!(
3939
err.contains("formatting trait implementation returned an error"),

0 commit comments

Comments
 (0)