Skip to content

Commit 458095a

Browse files
authored
Rollup merge of rust-lang#137107 - thaliaarchi:io-optional-methods/cursors, r=joboet
Override default `Write` methods for cursor-like types Override the default `io::Write` methods for cursor-like types to provide more efficient versions. Writes to resizable containers already write everything, so implement `write_all` and `write_all_vectored` in terms of those. For fixed-sized containers, cut out unnecessary error checking and looping for those same methods. | `impl Write for T` | `vectored` | `all` | `all_vectored` | `fmt` | | ------------------------------- | ---------- | ----- | -------------- | ------- | | `&mut [u8]` | Y | Y | new | | | `Vec<u8>` | Y | Y | new | rust-lang#137762 | | `VecDeque<u8>` | Y | Y | new | rust-lang#137762 | | `std::io::Cursor<&mut [u8]>` | Y | new | new | | | `std::io::Cursor<&mut Vec<u8>>` | Y | new | new | rust-lang#137762 | | `std::io::Cursor<Vec<u8>>` | Y | new | new | rust-lang#137762 | | `std::io::Cursor<Box<[u8]>>` | Y | new | new | | | `std::io::Cursor<[u8; N]>` | Y | new | new | | | `core::io::BorrowedCursor<'_>` | new | new | new | | Tracked in rust-lang#136756. # Open questions Is it guaranteed by `Write::write_all` that the maximal write is performed when not everything can be written? Its documentation describes the behavior of the default implementation, which writes until a 0-length write is encountered, thus implying that a maximal write is expected. In contrast, `Read::read_exact` declares that the contents of the buffer are unspecified for short reads. If it were allowed, these cursor-like types could bail on the write altogether if it has insufficient capacity.
2 parents 0b151c6 + 41bdd2b commit 458095a

File tree

2 files changed

+146
-14
lines changed

2 files changed

+146
-14
lines changed

library/std/src/io/cursor.rs

+87-13
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,27 @@ fn slice_write_vectored(
439439
Ok(nwritten)
440440
}
441441

442+
#[inline]
443+
fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> {
444+
let n = slice_write(pos_mut, slice, buf)?;
445+
if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
446+
}
447+
448+
#[inline]
449+
fn slice_write_all_vectored(
450+
pos_mut: &mut u64,
451+
slice: &mut [u8],
452+
bufs: &[IoSlice<'_>],
453+
) -> io::Result<()> {
454+
for buf in bufs {
455+
let n = slice_write(pos_mut, slice, buf)?;
456+
if n < buf.len() {
457+
return Err(io::Error::WRITE_ALL_EOF);
458+
}
459+
}
460+
Ok(())
461+
}
462+
442463
/// Reserves the required space, and pads the vec with 0s if necessary.
443464
fn reserve_and_pad<A: Allocator>(
444465
pos_mut: &mut u64,
@@ -481,9 +502,12 @@ fn reserve_and_pad<A: Allocator>(
481502
Ok(pos)
482503
}
483504

484-
/// Writes the slice to the vec without allocating
485-
/// # Safety: vec must have buf.len() spare capacity
486-
unsafe fn vec_write_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
505+
/// Writes the slice to the vec without allocating.
506+
///
507+
/// # Safety
508+
///
509+
/// `vec` must have `buf.len()` spare capacity.
510+
unsafe fn vec_write_all_unchecked<A>(pos: usize, vec: &mut Vec<u8, A>, buf: &[u8]) -> usize
487511
where
488512
A: Allocator,
489513
{
@@ -492,7 +516,7 @@ where
492516
pos + buf.len()
493517
}
494518

495-
/// Resizing write implementation for [`Cursor`]
519+
/// Resizing `write_all` implementation for [`Cursor`].
496520
///
497521
/// Cursor is allowed to have a pre-allocated and initialised
498522
/// vector body, but with a position of 0. This means the [`Write`]
@@ -501,7 +525,7 @@ where
501525
/// This also allows for the vec body to be empty, but with a position of N.
502526
/// This means that [`Write`] will pad the vec with 0 initially,
503527
/// before writing anything from that point
504-
fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
528+
fn vec_write_all<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
505529
where
506530
A: Allocator,
507531
{
@@ -512,7 +536,7 @@ where
512536
// Safety: we have ensured that the capacity is available
513537
// and that all bytes get written up to pos
514538
unsafe {
515-
pos = vec_write_unchecked(pos, vec, buf);
539+
pos = vec_write_all_unchecked(pos, vec, buf);
516540
if pos > vec.len() {
517541
vec.set_len(pos);
518542
}
@@ -523,7 +547,7 @@ where
523547
Ok(buf_len)
524548
}
525549

526-
/// Resizing write_vectored implementation for [`Cursor`]
550+
/// Resizing `write_all_vectored` implementation for [`Cursor`].
527551
///
528552
/// Cursor is allowed to have a pre-allocated and initialised
529553
/// vector body, but with a position of 0. This means the [`Write`]
@@ -532,7 +556,7 @@ where
532556
/// This also allows for the vec body to be empty, but with a position of N.
533557
/// This means that [`Write`] will pad the vec with 0 initially,
534558
/// before writing anything from that point
535-
fn vec_write_vectored<A>(
559+
fn vec_write_all_vectored<A>(
536560
pos_mut: &mut u64,
537561
vec: &mut Vec<u8, A>,
538562
bufs: &[IoSlice<'_>],
@@ -550,7 +574,7 @@ where
550574
// and that all bytes get written up to the last pos
551575
unsafe {
552576
for buf in bufs {
553-
pos = vec_write_unchecked(pos, vec, buf);
577+
pos = vec_write_all_unchecked(pos, vec, buf);
554578
}
555579
if pos > vec.len() {
556580
vec.set_len(pos);
@@ -579,6 +603,16 @@ impl Write for Cursor<&mut [u8]> {
579603
true
580604
}
581605

606+
#[inline]
607+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
608+
slice_write_all(&mut self.pos, self.inner, buf)
609+
}
610+
611+
#[inline]
612+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
613+
slice_write_all_vectored(&mut self.pos, self.inner, bufs)
614+
}
615+
582616
#[inline]
583617
fn flush(&mut self) -> io::Result<()> {
584618
Ok(())
@@ -591,18 +625,28 @@ where
591625
A: Allocator,
592626
{
593627
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
594-
vec_write(&mut self.pos, self.inner, buf)
628+
vec_write_all(&mut self.pos, self.inner, buf)
595629
}
596630

597631
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
598-
vec_write_vectored(&mut self.pos, self.inner, bufs)
632+
vec_write_all_vectored(&mut self.pos, self.inner, bufs)
599633
}
600634

601635
#[inline]
602636
fn is_write_vectored(&self) -> bool {
603637
true
604638
}
605639

640+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
641+
vec_write_all(&mut self.pos, self.inner, buf)?;
642+
Ok(())
643+
}
644+
645+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
646+
vec_write_all_vectored(&mut self.pos, self.inner, bufs)?;
647+
Ok(())
648+
}
649+
606650
#[inline]
607651
fn flush(&mut self) -> io::Result<()> {
608652
Ok(())
@@ -615,18 +659,28 @@ where
615659
A: Allocator,
616660
{
617661
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
618-
vec_write(&mut self.pos, &mut self.inner, buf)
662+
vec_write_all(&mut self.pos, &mut self.inner, buf)
619663
}
620664

621665
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
622-
vec_write_vectored(&mut self.pos, &mut self.inner, bufs)
666+
vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
623667
}
624668

625669
#[inline]
626670
fn is_write_vectored(&self) -> bool {
627671
true
628672
}
629673

674+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
675+
vec_write_all(&mut self.pos, &mut self.inner, buf)?;
676+
Ok(())
677+
}
678+
679+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
680+
vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)?;
681+
Ok(())
682+
}
683+
630684
#[inline]
631685
fn flush(&mut self) -> io::Result<()> {
632686
Ok(())
@@ -653,6 +707,16 @@ where
653707
true
654708
}
655709

710+
#[inline]
711+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
712+
slice_write_all(&mut self.pos, &mut self.inner, buf)
713+
}
714+
715+
#[inline]
716+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
717+
slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
718+
}
719+
656720
#[inline]
657721
fn flush(&mut self) -> io::Result<()> {
658722
Ok(())
@@ -676,6 +740,16 @@ impl<const N: usize> Write for Cursor<[u8; N]> {
676740
true
677741
}
678742

743+
#[inline]
744+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
745+
slice_write_all(&mut self.pos, &mut self.inner, buf)
746+
}
747+
748+
#[inline]
749+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
750+
slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs)
751+
}
752+
679753
#[inline]
680754
fn flush(&mut self) -> io::Result<()> {
681755
Ok(())

library/std/src/io/impls.rs

+59-1
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,17 @@ impl Write for &mut [u8] {
455455

456456
#[inline]
457457
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
458-
if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) }
458+
if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
459+
}
460+
461+
#[inline]
462+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
463+
for buf in bufs {
464+
if self.write(buf)? < buf.len() {
465+
return Err(io::Error::WRITE_ALL_EOF);
466+
}
467+
}
468+
Ok(())
459469
}
460470

461471
#[inline]
@@ -495,6 +505,12 @@ impl<A: Allocator> Write for Vec<u8, A> {
495505
Ok(())
496506
}
497507

508+
#[inline]
509+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
510+
self.write_vectored(bufs)?;
511+
Ok(())
512+
}
513+
498514
#[inline]
499515
fn flush(&mut self) -> io::Result<()> {
500516
Ok(())
@@ -515,6 +531,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
515531
Ok(n)
516532
}
517533

534+
#[inline]
518535
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
519536
let (front, back) = self.as_slices();
520537

@@ -547,6 +564,7 @@ impl<A: Allocator> Read for VecDeque<u8, A> {
547564
Ok(())
548565
}
549566

567+
#[inline]
550568
fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
551569
let len = cursor.capacity();
552570
let (front, back) = self.as_slices();
@@ -638,6 +656,12 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
638656
Ok(())
639657
}
640658

659+
#[inline]
660+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
661+
self.write_vectored(bufs)?;
662+
Ok(())
663+
}
664+
641665
#[inline]
642666
fn flush(&mut self) -> io::Result<()> {
643667
Ok(())
@@ -646,12 +670,46 @@ impl<A: Allocator> Write for VecDeque<u8, A> {
646670

647671
#[unstable(feature = "read_buf", issue = "78485")]
648672
impl<'a> io::Write for core::io::BorrowedCursor<'a> {
673+
#[inline]
649674
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
650675
let amt = cmp::min(buf.len(), self.capacity());
651676
self.append(&buf[..amt]);
652677
Ok(amt)
653678
}
654679

680+
#[inline]
681+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
682+
let mut nwritten = 0;
683+
for buf in bufs {
684+
let n = self.write(buf)?;
685+
nwritten += n;
686+
if n < buf.len() {
687+
break;
688+
}
689+
}
690+
Ok(nwritten)
691+
}
692+
693+
#[inline]
694+
fn is_write_vectored(&self) -> bool {
695+
true
696+
}
697+
698+
#[inline]
699+
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
700+
if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
701+
}
702+
703+
#[inline]
704+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
705+
for buf in bufs {
706+
if self.write(buf)? < buf.len() {
707+
return Err(io::Error::WRITE_ALL_EOF);
708+
}
709+
}
710+
Ok(())
711+
}
712+
655713
#[inline]
656714
fn flush(&mut self) -> io::Result<()> {
657715
Ok(())

0 commit comments

Comments
 (0)