Skip to content
/ rust Public
forked from rust-lang/rust

Commit 7e750c4

Browse files
authored
Rollup merge of rust-lang#156527 - bushrat011899:core_io_test_merge, r=clarfonthey
Move `std::io` tests to `alloctests` & add prelude ACP: rust-lang/libs-team#755 Tracking issue: rust-lang#154046 ~~Blocked on: rust-lang#158548~~ ## Description * Moves tests out of `std::io` into `alloctests` now that the relevant items are fully available from `alloc::io`. * Adds documentation to `alloc::io` * Adds prelude modules to `core::io` and `alloc::io`. --- ## Notes * No AI tooling of any kind was used during the creation of this PR.
2 parents 73dc916 + 5b49a9d commit 7e750c4

18 files changed

Lines changed: 286 additions & 83 deletions

File tree

library/alloc/src/io/mod.rs

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,188 @@
11
//! Traits, helpers, and type definitions for core I/O functionality.
2+
//!
3+
//! The `io` module contains a number of common things you'll need
4+
//! when doing input and output. The most core part of this module is
5+
//! the [`Read`] and [`Write`] traits, which provide the
6+
//! most general interface for reading and writing input and output.
7+
//!
8+
//! ## Read and Write
9+
//!
10+
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
11+
//! of other types, and you can implement them for your types too. As such,
12+
//! you'll see a few different types of I/O throughout the documentation in
13+
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
14+
//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
15+
//! [`File`]s:
16+
//!
17+
//! ```no_run
18+
//! use std::io;
19+
//! use std::io::prelude::*;
20+
//! use std::fs::File;
21+
//!
22+
//! fn main() -> io::Result<()> {
23+
//! let mut f = File::open("foo.txt")?;
24+
//! let mut buffer = [0; 10];
25+
//!
26+
//! // read up to 10 bytes
27+
//! let n = f.read(&mut buffer)?;
28+
//!
29+
//! println!("The bytes: {:?}", &buffer[..n]);
30+
//! Ok(())
31+
//! }
32+
//! ```
33+
//!
34+
//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
35+
//! nickname: readers and writers. So you'll sometimes see 'a reader' instead
36+
//! of 'a type that implements the [`Read`] trait'. Much easier!
37+
//!
38+
//! ## Seek and BufRead
39+
//!
40+
//! Beyond that, there are two important traits that are provided: [`Seek`]
41+
//! and [`BufRead`]. Both of these build on top of a reader to control
42+
//! how the reading happens. [`Seek`] lets you control where the next byte is
43+
//! coming from:
44+
//!
45+
//! ```no_run
46+
//! use std::io;
47+
//! use std::io::prelude::*;
48+
//! use std::io::SeekFrom;
49+
//! use std::fs::File;
50+
//!
51+
//! fn main() -> io::Result<()> {
52+
//! let mut f = File::open("foo.txt")?;
53+
//! let mut buffer = [0; 10];
54+
//!
55+
//! // skip to the last 10 bytes of the file
56+
//! f.seek(SeekFrom::End(-10))?;
57+
//!
58+
//! // read up to 10 bytes
59+
//! let n = f.read(&mut buffer)?;
60+
//!
61+
//! println!("The bytes: {:?}", &buffer[..n]);
62+
//! Ok(())
63+
//! }
64+
//! ```
65+
//!
66+
//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
67+
//! to show it off, we'll need to talk about buffers in general. Keep reading!
68+
//!
69+
//! ## BufReader and BufWriter
70+
//!
71+
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
72+
//! making near-constant calls to the operating system. To help with this,
73+
//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
74+
//! readers and writers. The wrapper uses a buffer, reducing the number of
75+
//! calls and providing nicer methods for accessing exactly what you want.
76+
//!
77+
//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
78+
//! methods to any reader:
79+
//!
80+
//! ```no_run
81+
//! use std::io;
82+
//! use std::io::prelude::*;
83+
//! use std::io::BufReader;
84+
//! use std::fs::File;
85+
//!
86+
//! fn main() -> io::Result<()> {
87+
//! let f = File::open("foo.txt")?;
88+
//! let mut reader = BufReader::new(f);
89+
//! let mut buffer = String::new();
90+
//!
91+
//! // read a line into buffer
92+
//! reader.read_line(&mut buffer)?;
93+
//!
94+
//! println!("{buffer}");
95+
//! Ok(())
96+
//! }
97+
//! ```
98+
//!
99+
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
100+
//! to [`write`][`Write::write`]:
101+
//!
102+
//! ```no_run
103+
//! use std::io;
104+
//! use std::io::prelude::*;
105+
//! use std::io::BufWriter;
106+
//! use std::fs::File;
107+
//!
108+
//! fn main() -> io::Result<()> {
109+
//! let f = File::create("foo.txt")?;
110+
//! {
111+
//! let mut writer = BufWriter::new(f);
112+
//!
113+
//! // write a byte to the buffer
114+
//! writer.write(&[42])?;
115+
//!
116+
//! } // the buffer is flushed once writer goes out of scope
117+
//!
118+
//! Ok(())
119+
//! }
120+
//! ```
121+
//!
122+
//! ## Iterator types
123+
//!
124+
//! A large number of the structures provided by `std::io` are for various
125+
//! ways of iterating over I/O. For example, [`Lines`] is used to split over
126+
//! lines:
127+
//!
128+
//! ```no_run
129+
//! use std::io;
130+
//! use std::io::prelude::*;
131+
//! use std::io::BufReader;
132+
//! use std::fs::File;
133+
//!
134+
//! fn main() -> io::Result<()> {
135+
//! let f = File::open("foo.txt")?;
136+
//! let reader = BufReader::new(f);
137+
//!
138+
//! for line in reader.lines() {
139+
//! println!("{}", line?);
140+
//! }
141+
//! Ok(())
142+
//! }
143+
//! ```
144+
//!
145+
//! ## io::Result
146+
//!
147+
//! Last, but certainly not least, is [`io::Result`]. This type is used
148+
//! as the return type of many `std::io` functions that can cause an error, and
149+
//! can be returned from your own functions as well. Many of the examples in this
150+
//! module use the [`?` operator]:
151+
//!
152+
//! ```no_run
153+
//! use std::io;
154+
//!
155+
//! # #[allow(dead_code)]
156+
//! fn read_input() -> io::Result<()> {
157+
//! let mut input = String::new();
158+
//!
159+
//! io::stdin().read_line(&mut input)?;
160+
//!
161+
//! println!("You typed: {}", input.trim());
162+
//!
163+
//! Ok(())
164+
//! }
165+
//! ```
166+
//!
167+
//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
168+
//! common type for functions which don't have a 'real' return value, but do want to
169+
//! return errors if they happen. In this case, the only purpose of this function is
170+
//! to read the line and print it, so we use `()`.
171+
//!
172+
//! [`File`]: ../../std/fs/struct.File.html
173+
//! [`TcpStream`]: ../../std/net/struct.TcpStream.html
174+
//! [`Vec<T>`]: crate::vec::Vec
175+
//! [`io::Result`]: self::Result
176+
//! [`?` operator]: ../../book/appendix-02-operators.html
2177
3178
mod buf_read;
4179
mod buffered;
5180
mod copy;
6181
mod cursor;
7182
mod error;
8183
mod impls;
184+
#[unstable(feature = "alloc_io", issue = "154046")]
185+
pub mod prelude;
9186
mod read;
10187
mod util;
11188

library/alloc/src/io/prelude.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! The I/O Prelude.
2+
//!
3+
//! The purpose of this module is to alleviate imports of many common I/O traits
4+
//! by adding a glob import to the top of I/O heavy modules:
5+
//!
6+
//! ```
7+
//! # #![allow(unused_imports)]
8+
//! use std::io::prelude::*;
9+
//! ```
10+
11+
#[stable(feature = "rust1", since = "1.0.0")]
12+
pub use crate::io::{BufRead, Read, Seek, Write};
Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::io::prelude::*;
1+
use std::io::prelude::*;
22

33
#[bench]
44
fn bench_read_slice(b: &mut test::Bencher) {
@@ -55,3 +55,26 @@ fn bench_write_vec(b: &mut test::Bencher) {
5555
}
5656
})
5757
}
58+
59+
#[bench]
60+
#[cfg(unix)]
61+
#[cfg_attr(target_os = "emscripten", ignore)] // no /dev
62+
fn bench_copy_buf_reader(b: &mut test::Bencher) {
63+
use std::fs::{File, OpenOptions};
64+
65+
let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
66+
// use dyn to avoid specializations unrelated to readbuf
67+
let dyn_in = &mut file_in as &mut dyn Read;
68+
let mut reader = std::io::BufReader::with_capacity(256 * 1024, dyn_in.take(0));
69+
let mut writer =
70+
OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
71+
72+
const BYTES: u64 = 1024 * 1024;
73+
74+
b.bytes = BYTES;
75+
76+
b.iter(|| {
77+
reader.get_mut().set_limit(BYTES);
78+
std::io::copy(&mut reader, &mut writer).unwrap()
79+
});
80+
}

library/alloctests/benches/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern crate test;
1212

1313
mod binary_heap;
1414
mod btree;
15+
mod io;
1516
mod linked_list;
1617
mod slice;
1718
mod str;
Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
use crate::io::prelude::*;
2-
use crate::io::{
3-
self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom,
1+
//! Tests for buffering wrappers for I/O traits
2+
3+
use alloc::io::{
4+
self, BorrowedBuf, BufRead, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, Read, Seek,
5+
SeekFrom, Write,
46
};
5-
use crate::mem::MaybeUninit;
6-
use crate::sync::atomic::{AtomicUsize, Ordering};
7-
use crate::{panic, thread};
7+
use core::mem::MaybeUninit;
8+
use core::sync::atomic::{AtomicUsize, Ordering};
9+
use std::{panic, thread};
10+
11+
extern crate test;
812

913
/// A dummy reader intended at testing short-reads propagation.
1014
pub struct ShortReader {
@@ -488,7 +492,7 @@ fn dont_panic_in_drop_on_panicked_flush() {
488492
}
489493

490494
#[test]
491-
#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads
495+
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
492496
fn panic_in_write_doesnt_flush_in_drop() {
493497
static WRITES: AtomicUsize = AtomicUsize::new(0);
494498

@@ -504,12 +508,11 @@ fn panic_in_write_doesnt_flush_in_drop() {
504508
}
505509
}
506510

507-
thread::spawn(|| {
511+
panic::catch_unwind(panic::AssertUnwindSafe(|| {
508512
let mut writer = BufWriter::new(PanicWriter);
509513
let _ = writer.write(b"hello world");
510514
let _ = writer.flush();
511-
})
512-
.join()
515+
}))
513516
.unwrap_err();
514517

515518
assert_eq!(WRITES.load(Ordering::SeqCst), 1);
@@ -681,7 +684,7 @@ fn line_vectored() {
681684

682685
#[test]
683686
fn line_vectored_partial_and_errors() {
684-
use crate::collections::VecDeque;
687+
use alloc::collections::VecDeque;
685688

686689
enum Call {
687690
Write { inputs: Vec<&'static [u8]>, output: io::Result<usize> },
@@ -1150,7 +1153,7 @@ struct WriteRecorder {
11501153

11511154
impl Write for WriteRecorder {
11521155
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1153-
use crate::str::from_utf8;
1156+
use core::str::from_utf8;
11541157

11551158
self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string()));
11561159
Ok(buf.len())
@@ -1183,7 +1186,7 @@ fn single_formatted_write() {
11831186
fn bufreader_full_initialize() {
11841187
struct OneByteReader;
11851188
impl Read for OneByteReader {
1186-
fn read(&mut self, buf: &mut [u8]) -> crate::io::Result<usize> {
1189+
fn read(&mut self, buf: &mut [u8]) -> alloc::io::Result<usize> {
11871190
if buf.len() > 0 {
11881191
buf[0] = 0;
11891192
Ok(1)
@@ -1206,7 +1209,7 @@ fn bufreader_full_initialize() {
12061209
/// This is a regression test for https://github.com/rust-lang/rust/issues/127584.
12071210
#[test]
12081211
fn bufwriter_aliasing() {
1209-
use crate::io::{BufWriter, Cursor};
1212+
use alloc::io::{BufWriter, Cursor};
12101213
let mut v = vec![0; 1024];
12111214
let c = Cursor::new(&mut v);
12121215
let w = BufWriter::new(Box::new(c));
Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
use crate::cmp::{max, min};
2-
use crate::collections::VecDeque;
3-
use crate::io;
4-
use crate::io::*;
1+
use alloc::collections::VecDeque;
2+
use alloc::io::{self, *};
3+
use core::cmp::{max, min};
54

65
#[test]
76
fn copy_copies() {
@@ -65,15 +64,15 @@ fn copy_specializes_bufreader() {
6564
let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source));
6665

6766
let mut sink = Vec::new();
68-
assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
67+
assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
6968
assert_eq!(source.as_slice(), sink.as_slice());
7069

7170
let buf_sz = 71 * 1024;
7271
assert!(buf_sz > DEFAULT_BUF_SIZE, "test precondition");
7372

7473
let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source));
7574
let mut sink = WriteObserver { observed_buffer: 0 };
76-
assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
75+
assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64);
7776
assert_eq!(
7877
sink.observed_buffer, buf_sz,
7978
"expected a large buffer to be provided to the writer"
@@ -117,32 +116,3 @@ fn copy_specializes_from_slice() {
117116
assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap());
118117
assert_eq!(60 * 1024, sink.observed_buffer);
119118
}
120-
121-
#[cfg(unix)]
122-
mod io_benches {
123-
use test::Bencher;
124-
125-
use crate::fs::{File, OpenOptions};
126-
use crate::io::BufReader;
127-
use crate::io::prelude::*;
128-
129-
#[bench]
130-
#[cfg_attr(target_os = "emscripten", ignore)] // no /dev
131-
fn bench_copy_buf_reader(b: &mut Bencher) {
132-
let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed");
133-
// use dyn to avoid specializations unrelated to readbuf
134-
let dyn_in = &mut file_in as &mut dyn Read;
135-
let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0));
136-
let mut writer =
137-
OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed");
138-
139-
const BYTES: u64 = 1024 * 1024;
140-
141-
b.bytes = BYTES;
142-
143-
b.iter(|| {
144-
reader.get_mut().set_limit(BYTES);
145-
crate::io::copy(&mut reader, &mut writer).unwrap()
146-
});
147-
}
148-
}
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use crate::io::prelude::*;
2-
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
1+
use alloc::io::{Cursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
2+
3+
extern crate test;
34

45
#[test]
56
fn test_vec_writer() {

0 commit comments

Comments
 (0)