Skip to content

Commit 0ffdcdb

Browse files
authored
Unrolled build for #158541
Rollup merge of #158541 - bushrat011899:core_io_write, r=clarfonthey Move `std::io::Write` to `core::io` ACP: rust-lang/libs-team#755 Tracking issue: #154046 Split From: #156527 ~~Blocked On: #158537 ~~Blocked On: #158540 ## Description Moves `std::io::Write` to `core::io`. This is effectively a direct cut and paste, but with a large diff due to how many implementations need to be moved into `alloc` and `core`. Blocked on #158537 and #158540. --- ## Notes * No AI tooling of any kind was used during the creation of this PR. * Please see #154046 (comment) for a review order and broader context for this PR.
2 parents d465559 + cb09bff commit 0ffdcdb

17 files changed

Lines changed: 1425 additions & 1308 deletions

File tree

library/alloc/src/io/cursor.rs

Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
use crate::alloc::Allocator;
2+
use crate::boxed::Box;
3+
use crate::io::{
4+
self, Cursor, ErrorKind, IoSlice, WriteThroughCursor, slice_write, slice_write_all,
5+
slice_write_all_vectored, slice_write_vectored,
6+
};
7+
use crate::vec::Vec;
8+
9+
/// Reserves the required space, and pads the vec with 0s if necessary.
10+
fn reserve_and_pad<A: Allocator>(
11+
pos_mut: &mut u64,
12+
vec: &mut Vec<u8, A>,
13+
buf_len: usize,
14+
) -> io::Result<usize> {
15+
let pos: usize = (*pos_mut).try_into().map_err(|_| {
16+
io::const_error!(
17+
ErrorKind::InvalidInput,
18+
"cursor position exceeds maximum possible vector length",
19+
)
20+
})?;
21+
22+
// For safety reasons, we don't want these numbers to overflow
23+
// otherwise our allocation won't be enough
24+
let desired_cap = pos.saturating_add(buf_len);
25+
if desired_cap > vec.capacity() {
26+
// We want our vec's total capacity
27+
// to have room for (pos+buf_len) bytes. Reserve allocates
28+
// based on additional elements from the length, so we need to
29+
// reserve the difference
30+
cfg_select! {
31+
no_global_oom_handling => {
32+
vec.try_reserve(desired_cap - vec.len())?;
33+
}
34+
_ => {
35+
vec.reserve(desired_cap - vec.len());
36+
}
37+
}
38+
}
39+
// Pad if pos is above the current len.
40+
if pos > vec.len() {
41+
let diff = pos - vec.len();
42+
// Unfortunately, `resize()` would suffice but the optimiser does not
43+
// realise the `reserve` it does can be eliminated. So we do it manually
44+
// to eliminate that extra branch
45+
let spare = vec.spare_capacity_mut();
46+
debug_assert!(spare.len() >= diff);
47+
// Safety: we have allocated enough capacity for this.
48+
// And we are only writing, not reading
49+
unsafe {
50+
spare.get_unchecked_mut(..diff).fill(core::mem::MaybeUninit::new(0));
51+
vec.set_len(pos);
52+
}
53+
}
54+
55+
Ok(pos)
56+
}
57+
58+
/// Writes the slice to the vec without allocating.
59+
///
60+
/// # Safety
61+
///
62+
/// `vec` must have `buf.len()` spare capacity.
63+
unsafe fn vec_write_all_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
64+
where
65+
A: Allocator,
66+
{
67+
debug_assert!(vec.capacity() >= pos + buf.len());
68+
unsafe { vec.as_mut_ptr().add(pos).copy_from(buf.as_ptr(), buf.len()) };
69+
pos + buf.len()
70+
}
71+
72+
/// Resizing `write_all` implementation for [`Cursor`].
73+
///
74+
/// Cursor is allowed to have a pre-allocated and initialised
75+
/// vector body, but with a position of 0. This means the [`Write`]
76+
/// will overwrite the contents of the vec.
77+
///
78+
/// This also allows for the vec body to be empty, but with a position of N.
79+
/// This means that [`Write`] will pad the vec with 0 initially,
80+
/// before writing anything from that point
81+
///
82+
/// [`Write`]: crate::io::Write
83+
fn vec_write_all<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
84+
where
85+
A: Allocator,
86+
{
87+
let buf_len = buf.len();
88+
let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?;
89+
90+
// Write the buf then progress the vec forward if necessary
91+
// Safety: we have ensured that the capacity is available
92+
// and that all bytes get written up to pos
93+
unsafe {
94+
pos = vec_write_all_unchecked(pos, vec, buf);
95+
if pos > vec.len() {
96+
vec.set_len(pos);
97+
}
98+
};
99+
100+
// Bump us forward
101+
*pos_mut += buf_len as u64;
102+
Ok(buf_len)
103+
}
104+
105+
/// Resizing `write_all_vectored` implementation for [`Cursor`].
106+
///
107+
/// Cursor is allowed to have a pre-allocated and initialised
108+
/// vector body, but with a position of 0. This means the [`Write`]
109+
/// will overwrite the contents of the vec.
110+
///
111+
/// This also allows for the vec body to be empty, but with a position of N.
112+
/// This means that [`Write`] will pad the vec with 0 initially,
113+
/// before writing anything from that point
114+
///
115+
/// [`Write`]: crate::io::Write
116+
fn vec_write_all_vectored<A>(
117+
pos_mut: &mut u64,
118+
vec: &mut Vec<u8, A>,
119+
bufs: &[IoSlice<'_>],
120+
) -> io::Result<usize>
121+
where
122+
A: Allocator,
123+
{
124+
// For safety reasons, we don't want this sum to overflow ever.
125+
// If this saturates, the reserve should panic to avoid any unsound writing.
126+
let buf_len = bufs.iter().fold(0usize, |a, b| a.saturating_add(b.len()));
127+
let mut pos = reserve_and_pad(pos_mut, vec, buf_len)?;
128+
129+
// Write the buf then progress the vec forward if necessary
130+
// Safety: we have ensured that the capacity is available
131+
// and that all bytes get written up to the last pos
132+
unsafe {
133+
for buf in bufs {
134+
pos = vec_write_all_unchecked(pos, vec, buf);
135+
}
136+
if pos > vec.len() {
137+
vec.set_len(pos);
138+
}
139+
}
140+
141+
// Bump us forward
142+
*pos_mut += buf_len as u64;
143+
Ok(buf_len)
144+
}
145+
146+
#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
147+
impl<A> WriteThroughCursor for &mut Vec<u8, A>
148+
where
149+
A: Allocator,
150+
{
151+
fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> {
152+
let (pos, inner) = this.into_parts_mut();
153+
vec_write_all(pos, inner, buf)
154+
}
155+
156+
fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
157+
let (pos, inner) = this.into_parts_mut();
158+
vec_write_all_vectored(pos, inner, bufs)
159+
}
160+
161+
#[inline]
162+
fn is_write_vectored(_this: &Cursor<Self>) -> bool {
163+
true
164+
}
165+
166+
fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> {
167+
let (pos, inner) = this.into_parts_mut();
168+
vec_write_all(pos, inner, buf)?;
169+
Ok(())
170+
}
171+
172+
fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
173+
let (pos, inner) = this.into_parts_mut();
174+
vec_write_all_vectored(pos, inner, bufs)?;
175+
Ok(())
176+
}
177+
178+
#[inline]
179+
fn flush(_this: &mut Cursor<Self>) -> io::Result<()> {
180+
Ok(())
181+
}
182+
}
183+
184+
#[stable(feature = "rust1", since = "1.0.0")]
185+
impl<A> WriteThroughCursor for Vec<u8, A>
186+
where
187+
A: Allocator,
188+
{
189+
fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> {
190+
let (pos, inner) = this.into_parts_mut();
191+
vec_write_all(pos, inner, buf)
192+
}
193+
194+
fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
195+
let (pos, inner) = this.into_parts_mut();
196+
vec_write_all_vectored(pos, inner, bufs)
197+
}
198+
199+
#[inline]
200+
fn is_write_vectored(_this: &Cursor<Self>) -> bool {
201+
true
202+
}
203+
204+
fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> {
205+
let (pos, inner) = this.into_parts_mut();
206+
vec_write_all(pos, inner, buf)?;
207+
Ok(())
208+
}
209+
210+
fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
211+
let (pos, inner) = this.into_parts_mut();
212+
vec_write_all_vectored(pos, inner, bufs)?;
213+
Ok(())
214+
}
215+
216+
#[inline]
217+
fn flush(_this: &mut Cursor<Self>) -> io::Result<()> {
218+
Ok(())
219+
}
220+
}
221+
222+
#[stable(feature = "cursor_box_slice", since = "1.5.0")]
223+
impl<A> WriteThroughCursor for Box<[u8], A>
224+
where
225+
A: Allocator,
226+
{
227+
#[inline]
228+
fn write(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<usize> {
229+
let (pos, inner) = this.into_parts_mut();
230+
slice_write(pos, inner, buf)
231+
}
232+
233+
#[inline]
234+
fn write_vectored(this: &mut Cursor<Self>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
235+
let (pos, inner) = this.into_parts_mut();
236+
slice_write_vectored(pos, inner, bufs)
237+
}
238+
239+
#[inline]
240+
fn is_write_vectored(_this: &Cursor<Self>) -> bool {
241+
true
242+
}
243+
244+
#[inline]
245+
fn write_all(this: &mut Cursor<Self>, buf: &[u8]) -> io::Result<()> {
246+
let (pos, inner) = this.into_parts_mut();
247+
slice_write_all(pos, inner, buf)
248+
}
249+
250+
#[inline]
251+
fn write_all_vectored(this: &mut Cursor<Self>, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
252+
let (pos, inner) = this.into_parts_mut();
253+
slice_write_all_vectored(pos, inner, bufs)
254+
}
255+
256+
#[inline]
257+
fn flush(_this: &mut Cursor<Self>) -> io::Result<()> {
258+
Ok(())
259+
}
260+
}

0 commit comments

Comments
 (0)