Skip to content

Commit

Permalink
Don't reimplement IoSlice::advance_slices (stabilized in 1.81.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
Ten0 committed Nov 12, 2024
1 parent cb4368d commit e77a9bb
Showing 1 changed file with 6 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,23 @@ use std::io::{Error, ErrorKind, IoSlice, Result, Write};

pub(super) fn write_all_vectored<'a, W: Write, const N: usize>(
writer: &mut W,
mut slices: [&'a [u8]; N],
slices: [&'a [u8]; N],
) -> Result<()> {
let mut bufs = slices.map(IoSlice::new);
write_all_vectored_inner(writer, &mut slices, &mut bufs)
write_all_vectored_inner(writer, &mut bufs)
}

/// Taken from std before stabilization
/// https://github.com/rust-lang/rust/issues/70436
///
/// One less level of generics compared to the function above
fn write_all_vectored_inner<'a, W: Write>(
writer: &mut W,
mut slices: &mut [&'a [u8]],
mut bufs: &mut [IoSlice<'a>],
) -> Result<()> {
// Guarantee that bufs is empty if it contains no data,
// to avoid calling write_vectored if there is no data to be written.
advance_slices(&mut slices, &mut bufs, 0);
IoSlice::advance_slices(&mut bufs, 0);
while !bufs.is_empty() {
match writer.write_vectored(bufs) {
Ok(0) => {
Expand All @@ -26,50 +27,10 @@ fn write_all_vectored_inner<'a, W: Write>(
"failed to write whole buffer",
));
}
Ok(n) => advance_slices(&mut slices, &mut bufs, n),
Ok(n) => IoSlice::advance_slices(&mut bufs, n),
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => return Err(e),
}
}
Ok(())
}

/// ~Taken from std before stabilization
/// https://github.com/rust-lang/rust/issues/62726
///
/// We need to pass both slices and bufs because otherwise we have no way to
/// advance an IoSlice, so we just re-construct it from the original slice
/// https://github.com/rust-lang/rust/issues/62726#issuecomment-542826827
///
/// This has been FCPd recently though so it shouldn't take long to stabilize.
fn advance_slices<'a>(slices: &mut &mut [&'a [u8]], bufs: &mut &mut [IoSlice<'a>], n: usize) {
assert_eq!(slices.len(), bufs.len());
// Number of buffers to remove.
let mut remove = 0;
// Remaining length before reaching n. This prevents overflow
// that could happen if the length of slices in `bufs` were instead
// accumulated. Those slice may be aliased and, if they are large
// enough, their added length may overflow a `usize`.
let mut left = n;
for slice in slices.iter() {
if let Some(remainder) = left.checked_sub(slice.len()) {
left = remainder;
remove += 1;
} else {
break;
}
}

*slices = &mut std::mem::take(slices)[remove..];
*bufs = &mut std::mem::take(bufs)[remove..];
if slices.is_empty() {
assert!(left == 0, "advancing io slices beyond their length");
} else {
// Edited from std's implementation because they don't make `IoSlice::advance`
// available
let first = &mut slices[0];
let new_slice = &(*first)[left..];
*first = new_slice;
bufs[0] = IoSlice::new(new_slice);
}
}

0 comments on commit e77a9bb

Please sign in to comment.