Skip to content

Commit baf2bca

Browse files
authored
Rollup merge of #97015 - nrc:read-buf-cursor, r=Mark-Simulacrum
std::io: migrate ReadBuf to BorrowBuf/BorrowCursor This PR replaces `ReadBuf` (used by the `Read::read_buf` family of methods) with `BorrowBuf` and `BorrowCursor`. The general idea is to split `ReadBuf` because its API is large and confusing. `BorrowBuf` represents a borrowed buffer which is mostly read-only and (other than for construction) deals only with filled vs unfilled segments. a `BorrowCursor` is a mostly write-only view of the unfilled part of a `BorrowBuf` which distinguishes between initialized and uninitialized segments. For `Read::read_buf`, the caller would create a `BorrowBuf`, then pass a `BorrowCursor` to `read_buf`. In addition to the major API split, I've made the following smaller changes: * Removed some methods entirely from the API (mostly the functionality can be replicated with two calls rather than a single one) * Unified naming, e.g., by replacing initialized with init and assume_init with set_init * Added an easy way to get the number of bytes written to a cursor (`written` method) As well as simplifying the API (IMO), this approach has the following advantages: * Since we pass the cursor by value, we remove the 'unsoundness footgun' where a malicious `read_buf` could swap out the `ReadBuf`. * Since `read_buf` cannot write into the filled part of the buffer, we prevent the filled part shrinking or changing which could cause underflow for the caller or unexpected behaviour. ## Outline ```rust pub struct BorrowBuf<'a> impl Debug for BorrowBuf<'_> impl<'a> From<&'a mut [u8]> for BorrowBuf<'a> impl<'a> From<&'a mut [MaybeUninit<u8>]> for BorrowBuf<'a> impl<'a> BorrowBuf<'a> { pub fn capacity(&self) -> usize pub fn len(&self) -> usize pub fn init_len(&self) -> usize pub fn filled(&self) -> &[u8] pub fn unfilled<'this>(&'this mut self) -> BorrowCursor<'this, 'a> pub fn clear(&mut self) -> &mut Self pub unsafe fn set_init(&mut self, n: usize) -> &mut Self } pub struct BorrowCursor<'buf, 'data> impl<'buf, 'data> BorrowCursor<'buf, 'data> { pub fn clone<'this>(&'this mut self) -> BorrowCursor<'this, 'data> pub fn capacity(&self) -> usize pub fn written(&self) -> usize pub fn init_ref(&self) -> &[u8] pub fn init_mut(&mut self) -> &mut [u8] pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] pub unsafe fn advance(&mut self, n: usize) -> &mut Self pub fn ensure_init(&mut self) -> &mut Self pub unsafe fn set_init(&mut self, n: usize) -> &mut Self pub fn append(&mut self, buf: &[u8]) } ``` ## TODO * ~~Migrate non-unix libs and tests~~ * ~~Naming~~ * ~~`BorrowBuf` or `BorrowedBuf` or `SliceBuf`? (We might want an owned equivalent for the async IO traits)~~ * ~~Should we rename the `readbuf` module? We might keep the name indicate it includes both the buf and cursor variations and someday the owned version too. Or we could change it. It is not publicly exposed, so it is not that important~~. * ~~`read_buf` method: we read into the cursor now, so the `_buf` suffix is a bit weird.~~ * ~~Documentation~~ * Tests are incomplete (I adjusted existing tests, but did not add new ones). cc rust-lang/rust#78485, rust-lang/rust#94741 supersedes: rust-lang/rust#95770, rust-lang/rust#93359 fixes #93305
2 parents 5fcb021 + 739d746 commit baf2bca

File tree

21 files changed

+472
-418
lines changed

21 files changed

+472
-418
lines changed

std/src/fs.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ mod tests;
1313

1414
use crate::ffi::OsString;
1515
use crate::fmt;
16-
use crate::io::{self, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write};
16+
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
1717
use crate::path::{Path, PathBuf};
1818
use crate::sys::fs as fs_imp;
1919
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
@@ -703,8 +703,8 @@ impl Read for File {
703703
self.inner.read_vectored(bufs)
704704
}
705705

706-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
707-
self.inner.read_buf(buf)
706+
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
707+
self.inner.read_buf(cursor)
708708
}
709709

710710
#[inline]
@@ -755,8 +755,8 @@ impl Read for &File {
755755
self.inner.read(buf)
756756
}
757757

758-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
759-
self.inner.read_buf(buf)
758+
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
759+
self.inner.read_buf(cursor)
760760
}
761761

762762
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {

std/src/io/buffered/bufreader.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod buffer;
22

33
use crate::fmt;
44
use crate::io::{
5-
self, BufRead, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
5+
self, BorrowedCursor, BufRead, IoSliceMut, Read, Seek, SeekFrom, SizeHint, DEFAULT_BUF_SIZE,
66
};
77
use buffer::Buffer;
88

@@ -266,21 +266,21 @@ impl<R: Read> Read for BufReader<R> {
266266
Ok(nread)
267267
}
268268

269-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
269+
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
270270
// If we don't have any buffered data and we're doing a massive read
271271
// (larger than our internal buffer), bypass our internal buffer
272272
// entirely.
273-
if self.buf.pos() == self.buf.filled() && buf.remaining() >= self.capacity() {
273+
if self.buf.pos() == self.buf.filled() && cursor.capacity() >= self.capacity() {
274274
self.discard_buffer();
275-
return self.inner.read_buf(buf);
275+
return self.inner.read_buf(cursor);
276276
}
277277

278-
let prev = buf.filled_len();
278+
let prev = cursor.written();
279279

280280
let mut rem = self.fill_buf()?;
281-
rem.read_buf(buf)?;
281+
rem.read_buf(cursor.reborrow())?;
282282

283-
self.consume(buf.filled_len() - prev); //slice impl of read_buf known to never unfill buf
283+
self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf
284284

285285
Ok(())
286286
}

std/src/io/buffered/bufreader/buffer.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
/// that user code which wants to do reads from a `BufReader` via `buffer` + `consume` can do so
1010
/// without encountering any runtime bounds checks.
1111
use crate::cmp;
12-
use crate::io::{self, Read, ReadBuf};
12+
use crate::io::{self, BorrowedBuf, Read};
1313
use crate::mem::MaybeUninit;
1414

1515
pub struct Buffer {
@@ -93,11 +93,15 @@ impl Buffer {
9393
if self.pos >= self.filled {
9494
debug_assert!(self.pos == self.filled);
9595

96-
let mut readbuf = ReadBuf::uninit(&mut self.buf);
96+
let mut buf = BorrowedBuf::from(&mut *self.buf);
97+
// SAFETY: `self.filled` bytes will always have been initialized.
98+
unsafe {
99+
buf.set_init(self.filled);
100+
}
97101

98-
reader.read_buf(&mut readbuf)?;
102+
reader.read_buf(buf.unfilled())?;
99103

100-
self.filled = readbuf.filled_len();
104+
self.filled = buf.len();
101105
self.pos = 0;
102106
}
103107
Ok(self.buffer())

std/src/io/buffered/tests.rs

+18-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use crate::io::prelude::*;
2-
use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, ReadBuf, SeekFrom};
2+
use crate::io::{
3+
self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom,
4+
};
35
use crate::mem::MaybeUninit;
46
use crate::panic;
57
use crate::sync::atomic::{AtomicUsize, Ordering};
@@ -61,48 +63,48 @@ fn test_buffered_reader_read_buf() {
6163
let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
6264
let mut reader = BufReader::with_capacity(2, inner);
6365

64-
let mut buf = [MaybeUninit::uninit(); 3];
65-
let mut buf = ReadBuf::uninit(&mut buf);
66+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
67+
let mut buf: BorrowedBuf<'_> = buf.into();
6668

67-
reader.read_buf(&mut buf).unwrap();
69+
reader.read_buf(buf.unfilled()).unwrap();
6870

6971
assert_eq!(buf.filled(), [5, 6, 7]);
7072
assert_eq!(reader.buffer(), []);
7173

72-
let mut buf = [MaybeUninit::uninit(); 2];
73-
let mut buf = ReadBuf::uninit(&mut buf);
74+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 2];
75+
let mut buf: BorrowedBuf<'_> = buf.into();
7476

75-
reader.read_buf(&mut buf).unwrap();
77+
reader.read_buf(buf.unfilled()).unwrap();
7678

7779
assert_eq!(buf.filled(), [0, 1]);
7880
assert_eq!(reader.buffer(), []);
7981

80-
let mut buf = [MaybeUninit::uninit(); 1];
81-
let mut buf = ReadBuf::uninit(&mut buf);
82+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 1];
83+
let mut buf: BorrowedBuf<'_> = buf.into();
8284

83-
reader.read_buf(&mut buf).unwrap();
85+
reader.read_buf(buf.unfilled()).unwrap();
8486

8587
assert_eq!(buf.filled(), [2]);
8688
assert_eq!(reader.buffer(), [3]);
8789

88-
let mut buf = [MaybeUninit::uninit(); 3];
89-
let mut buf = ReadBuf::uninit(&mut buf);
90+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); 3];
91+
let mut buf: BorrowedBuf<'_> = buf.into();
9092

91-
reader.read_buf(&mut buf).unwrap();
93+
reader.read_buf(buf.unfilled()).unwrap();
9294

9395
assert_eq!(buf.filled(), [3]);
9496
assert_eq!(reader.buffer(), []);
9597

96-
reader.read_buf(&mut buf).unwrap();
98+
reader.read_buf(buf.unfilled()).unwrap();
9799

98100
assert_eq!(buf.filled(), [3, 4]);
99101
assert_eq!(reader.buffer(), []);
100102

101103
buf.clear();
102104

103-
reader.read_buf(&mut buf).unwrap();
105+
reader.read_buf(buf.unfilled()).unwrap();
104106

105-
assert_eq!(buf.filled_len(), 0);
107+
assert!(buf.filled().is_empty());
106108
}
107109

108110
#[test]

std/src/io/copy.rs

+18-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{BufWriter, ErrorKind, Read, ReadBuf, Result, Write, DEFAULT_BUF_SIZE};
1+
use super::{BorrowedBuf, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
22
use crate::mem::MaybeUninit;
33

44
/// Copies the entire contents of a reader into a writer.
@@ -97,37 +97,39 @@ impl<I: Write> BufferedCopySpec for BufWriter<I> {
9797

9898
loop {
9999
let buf = writer.buffer_mut();
100-
let mut read_buf = ReadBuf::uninit(buf.spare_capacity_mut());
100+
let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into();
101101

102-
// SAFETY: init is either 0 or the initialized_len of the previous iteration
103102
unsafe {
104-
read_buf.assume_init(init);
103+
// SAFETY: init is either 0 or the init_len from the previous iteration.
104+
read_buf.set_init(init);
105105
}
106106

107107
if read_buf.capacity() >= DEFAULT_BUF_SIZE {
108-
match reader.read_buf(&mut read_buf) {
108+
let mut cursor = read_buf.unfilled();
109+
match reader.read_buf(cursor.reborrow()) {
109110
Ok(()) => {
110-
let bytes_read = read_buf.filled_len();
111+
let bytes_read = cursor.written();
111112

112113
if bytes_read == 0 {
113114
return Ok(len);
114115
}
115116

116-
init = read_buf.initialized_len() - bytes_read;
117+
init = read_buf.init_len() - bytes_read;
118+
len += bytes_read as u64;
117119

118-
// SAFETY: ReadBuf guarantees all of its filled bytes are init
120+
// SAFETY: BorrowedBuf guarantees all of its filled bytes are init
119121
unsafe { buf.set_len(buf.len() + bytes_read) };
120-
len += bytes_read as u64;
122+
121123
// Read again if the buffer still has enough capacity, as BufWriter itself would do
122124
// This will occur if the reader returns short reads
123-
continue;
124125
}
125-
Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
126+
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
126127
Err(e) => return Err(e),
127128
}
129+
} else {
130+
writer.flush_buf()?;
131+
init = 0;
128132
}
129-
130-
writer.flush_buf()?;
131133
}
132134
}
133135
}
@@ -136,13 +138,13 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
136138
reader: &mut R,
137139
writer: &mut W,
138140
) -> Result<u64> {
139-
let mut buf = [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
140-
let mut buf = ReadBuf::uninit(&mut buf);
141+
let buf: &mut [_] = &mut [MaybeUninit::uninit(); DEFAULT_BUF_SIZE];
142+
let mut buf: BorrowedBuf<'_> = buf.into();
141143

142144
let mut len = 0;
143145

144146
loop {
145-
match reader.read_buf(&mut buf) {
147+
match reader.read_buf(buf.unfilled()) {
146148
Ok(()) => {}
147149
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
148150
Err(e) => return Err(e),

std/src/io/cursor.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::io::prelude::*;
55

66
use crate::alloc::Allocator;
77
use crate::cmp;
8-
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
8+
use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, SeekFrom};
99

1010
/// A `Cursor` wraps an in-memory buffer and provides it with a
1111
/// [`Seek`] implementation.
@@ -323,12 +323,12 @@ where
323323
Ok(n)
324324
}
325325

326-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
327-
let prev_filled = buf.filled_len();
326+
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
327+
let prev_written = cursor.written();
328328

329-
Read::read_buf(&mut self.fill_buf()?, buf)?;
329+
Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
330330

331-
self.pos += (buf.filled_len() - prev_filled) as u64;
331+
self.pos += (cursor.written() - prev_written) as u64;
332332

333333
Ok(())
334334
}

std/src/io/impls.rs

+11-11
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::cmp;
66
use crate::collections::VecDeque;
77
use crate::fmt;
88
use crate::io::{
9-
self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
9+
self, BorrowedCursor, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write,
1010
};
1111
use crate::mem;
1212

@@ -21,8 +21,8 @@ impl<R: Read + ?Sized> Read for &mut R {
2121
}
2222

2323
#[inline]
24-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
25-
(**self).read_buf(buf)
24+
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
25+
(**self).read_buf(cursor)
2626
}
2727

2828
#[inline]
@@ -125,8 +125,8 @@ impl<R: Read + ?Sized> Read for Box<R> {
125125
}
126126

127127
#[inline]
128-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
129-
(**self).read_buf(buf)
128+
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
129+
(**self).read_buf(cursor)
130130
}
131131

132132
#[inline]
@@ -249,11 +249,11 @@ impl Read for &[u8] {
249249
}
250250

251251
#[inline]
252-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
253-
let amt = cmp::min(buf.remaining(), self.len());
252+
fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
253+
let amt = cmp::min(cursor.capacity(), self.len());
254254
let (a, b) = self.split_at(amt);
255255

256-
buf.append(a);
256+
cursor.append(a);
257257

258258
*self = b;
259259
Ok(())
@@ -427,10 +427,10 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
427427
}
428428

429429
#[inline]
430-
fn read_buf(&mut self, buf: &mut ReadBuf<'_>) -> io::Result<()> {
430+
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
431431
let (ref mut front, _) = self.as_slices();
432-
let n = cmp::min(buf.remaining(), front.len());
433-
Read::read_buf(front, buf)?;
432+
let n = cmp::min(cursor.capacity(), front.len());
433+
Read::read_buf(front, cursor)?;
434434
self.drain(..n);
435435
Ok(())
436436
}

0 commit comments

Comments
 (0)