Skip to content

Commit 29814a8

Browse files
committed
Add Write implementation for [MaybeUninit<u8>]
There’s `Write` implement for slice of bytes so it’s not unreasonable to also have one for slice of `MaybeUninit` bytes. This makes dealing with uninitialised memory slightly easier in some cases (though it sadly doesn’t eliminate use of `unsafe` once the data is written) and makes it possible to use existing APIs which `Write` data (e.g. `serde_json::to_writer`) to initialise memory.
1 parent ea34650 commit 29814a8

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

library/std/src/io/impls.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,65 @@ impl Write for &mut [u8] {
474474
}
475475
}
476476

477+
/// Write is implemented for `&mut [MaybeUninit<u8>]` by copying into the slice,
478+
/// initialising its data.
479+
///
480+
/// Note that writing updates the slice to point to the yet unwritten part.
481+
/// The slice will be empty when it has been completely overwritten.
482+
///
483+
/// If the number of bytes to be written exceeds the size of the slice, write
484+
/// operations will return short writes: ultimately, `Ok(0)`; in this situation,
485+
/// `write_all` returns an error of kind `ErrorKind::WriteZero`.
486+
#[stable(feature = "maybe_uninit_slice_io_write", since = "1.87.0")]
487+
impl Write for &mut [mem::MaybeUninit<u8>] {
488+
#[inline]
489+
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
490+
let amt = cmp::min(data.len(), self.len());
491+
let (a, b) = mem::take(self).split_at_mut(amt);
492+
a.write_copy_of_slice(&data[..amt]);
493+
*self = b;
494+
Ok(amt)
495+
}
496+
497+
#[inline]
498+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
499+
let mut nwritten = 0;
500+
for buf in bufs {
501+
nwritten += self.write(buf)?;
502+
if self.is_empty() {
503+
break;
504+
}
505+
}
506+
507+
Ok(nwritten)
508+
}
509+
510+
#[inline]
511+
fn is_write_vectored(&self) -> bool {
512+
true
513+
}
514+
515+
#[inline]
516+
fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
517+
if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) }
518+
}
519+
520+
#[inline]
521+
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> {
522+
for buf in bufs {
523+
if self.write(buf)? < buf.len() {
524+
return Err(io::Error::WRITE_ALL_EOF);
525+
}
526+
}
527+
Ok(())
528+
}
529+
530+
#[inline]
531+
fn flush(&mut self) -> io::Result<()> {
532+
Ok(())
533+
}
534+
}
535+
477536
/// Write is implemented for `Vec<u8>` by appending to the vector.
478537
/// The vector will grow as needed.
479538
#[stable(feature = "rust1", since = "1.0.0")]

library/std/src/io/tests.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,3 +945,20 @@ fn try_oom_error() {
945945
let io_err = io::Error::from(reserve_err);
946946
assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind());
947947
}
948+
949+
#[test]
950+
fn write_maybe_uninit_slice() {
951+
let mut buf = [MaybeUninit::uninit(); 16];
952+
953+
let mut cursor = &mut buf[..];
954+
assert_eq!(3, cursor.write(b"foo").unwrap());
955+
assert_eq!(6, cursor.write_vectored(&[IoSlice::new(b"bar"), IoSlice::new(b"baz"),]).unwrap());
956+
assert_eq!(7, cursor.len());
957+
cursor.write_all(b"qux").unwrap();
958+
cursor.write_all(b"toolong").unwrap_err();
959+
assert_eq!(0, cursor.len());
960+
961+
// SAFETY: We’ve initialised it using Write interface.
962+
let buf = unsafe { buf.assume_init_ref() };
963+
assert_eq!(b"foobarbazquxtool", buf);
964+
}

0 commit comments

Comments
 (0)