From 9bad867fe95d748d7384d3d8cf6dfa160ddf9377 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 16:24:18 -0700 Subject: [PATCH 01/12] sketch out new BufMut::bytes_mut --- src/buf/buf_mut.rs | 59 +++++++++++++++++++++++++++++++++++++++++----- src/buf/chain.rs | 6 ++--- src/buf/limit.rs | 3 ++- src/buf/mod.rs | 2 +- src/bytes_mut.rs | 12 +++++----- 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 026bcad02..abaf59db6 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -10,6 +10,11 @@ use core::{ use alloc::{boxed::Box, vec::Vec}; +/// TODO +#[derive(Debug)] +#[repr(transparent)] +pub struct UninitSlice([MaybeUninit]); + /// A trait for values that provide sequential write access to bytes. /// /// Write bytes to a buffer @@ -167,7 +172,7 @@ pub unsafe trait BufMut { /// `bytes_mut` returning an empty slice implies that `remaining_mut` will /// return 0 and `remaining_mut` returning 0 implies that `bytes_mut` will /// return an empty slice. - fn bytes_mut(&mut self) -> &mut [MaybeUninit]; + fn bytes_mut(&mut self) -> &mut UninitSlice; /// Transfer bytes into `self` from `src` and advance the cursor by the /// number of bytes written. @@ -922,7 +927,7 @@ macro_rules! deref_forward_bufmut { (**self).remaining_mut() } - fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { (**self).bytes_mut() } @@ -1007,8 +1012,8 @@ unsafe impl BufMut for &mut [u8] { } #[inline] - fn bytes_mut(&mut self) -> &mut [MaybeUninit] { - // MaybeUninit is repr(transparent), so safe to transmute + fn bytes_mut(&mut self) -> &mut UninitSlice { + // UninitSlice is repr(transparent), so safe to transmute unsafe { mem::transmute(&mut **self) } } @@ -1042,7 +1047,7 @@ unsafe impl BufMut for Vec { } #[inline] - fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { use core::slice; if self.capacity() == self.len() { @@ -1053,7 +1058,11 @@ unsafe impl BufMut for Vec { let len = self.len(); let ptr = self.as_mut_ptr() as *mut MaybeUninit; - unsafe { &mut slice::from_raw_parts_mut(ptr, cap)[len..] } + unsafe { + let maybe_uninit: &mut [MaybeUninit] = + &mut slice::from_raw_parts_mut(ptr, cap)[len..]; + &mut *(maybe_uninit as *mut [MaybeUninit] as *mut _) + } } // Specialize these methods so they can skip checking `remaining_mut` @@ -1088,3 +1097,41 @@ unsafe impl BufMut for Vec { // The existence of this function makes the compiler catch if the BufMut // trait is "object-safe" or not. fn _assert_trait_object(_b: &dyn BufMut) {} + +impl UninitSlice { + /// TODO + pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { + let maybe_init: &mut [MaybeUninit] = std::slice::from_raw_parts_mut(ptr as *mut _, len); + &mut *(maybe_init as *mut [MaybeUninit] as *mut UninitSlice) + } + + /// TODO + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.0.as_mut_ptr() as *mut _ + } + + /// TODO + pub fn len(&self) -> usize { + self.0.len() + } + + // /// TODO + // pub fn slice_mut(&mut self, range: std::ops::Range) -> &mut UninitSlice { + // let maybe_init = &mut self.0[range]; + // unsafe { &mut *(maybe_init as *mut [MaybeUninit] as *mut Uni)} + // } +} + +impl std::ops::Index> for UninitSlice { + type Output = UninitSlice; + + fn index(&self, index: std::ops::RangeTo) -> &UninitSlice { + unimplemented!() + } +} + +impl std::ops::IndexMut> for UninitSlice { + fn index_mut(&mut self, index: std::ops::RangeTo) -> &mut Self::Output { + unimplemented!() + } +} diff --git a/src/buf/chain.rs b/src/buf/chain.rs index cc2c944b7..e59667dff 100644 --- a/src/buf/chain.rs +++ b/src/buf/chain.rs @@ -1,8 +1,6 @@ -use crate::buf::IntoIter; +use crate::buf::{IntoIter, UninitSlice}; use crate::{Buf, BufMut}; -use core::mem::MaybeUninit; - #[cfg(feature = "std")] use std::io::IoSlice; @@ -183,7 +181,7 @@ where self.a.remaining_mut() + self.b.remaining_mut() } - fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { if self.a.has_remaining_mut() { self.a.bytes_mut() } else { diff --git a/src/buf/limit.rs b/src/buf/limit.rs index c6ed3c7b1..a60218520 100644 --- a/src/buf/limit.rs +++ b/src/buf/limit.rs @@ -1,3 +1,4 @@ +use crate::buf::UninitSlice; use crate::BufMut; use core::{cmp, mem::MaybeUninit}; @@ -60,7 +61,7 @@ unsafe impl BufMut for Limit { cmp::min(self.inner.remaining_mut(), self.limit) } - fn bytes_mut(&mut self) -> &mut [MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { let bytes = self.inner.bytes_mut(); let end = cmp::min(bytes.len(), self.limit); &mut bytes[..end] diff --git a/src/buf/mod.rs b/src/buf/mod.rs index 5c6d5f9d5..bbf1cf745 100644 --- a/src/buf/mod.rs +++ b/src/buf/mod.rs @@ -29,7 +29,7 @@ mod vec_deque; mod writer; pub use self::buf_impl::Buf; -pub use self::buf_mut::BufMut; +pub use self::buf_mut::{BufMut, UninitSlice}; pub use self::chain::Chain; pub use self::iter::IntoIter; pub use self::limit::Limit; diff --git a/src/bytes_mut.rs b/src/bytes_mut.rs index 16cb72c2b..38f1ed53d 100644 --- a/src/bytes_mut.rs +++ b/src/bytes_mut.rs @@ -11,7 +11,7 @@ use alloc::{ vec::Vec, }; -use crate::buf::IntoIter; +use crate::buf::{IntoIter, UninitSlice}; use crate::bytes::Vtable; #[allow(unused)] use crate::loom::sync::atomic::AtomicMut; @@ -684,7 +684,7 @@ impl BytesMut { self.reserve(cnt); unsafe { - let dst = self.maybe_uninit_bytes(); + let dst = self.uninit_slice(); // Reserved above debug_assert!(dst.len() >= cnt); @@ -910,12 +910,12 @@ impl BytesMut { } #[inline] - fn maybe_uninit_bytes(&mut self) -> &mut [mem::MaybeUninit] { + fn uninit_slice(&mut self) -> &mut UninitSlice { unsafe { let ptr = self.ptr.as_ptr().offset(self.len as isize); let len = self.cap - self.len; - slice::from_raw_parts_mut(ptr as *mut mem::MaybeUninit, len) + UninitSlice::from_raw_parts_mut(ptr, len) } } } @@ -985,11 +985,11 @@ unsafe impl BufMut for BytesMut { } #[inline] - fn bytes_mut(&mut self) -> &mut [mem::MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { if self.capacity() == self.len() { self.reserve(64); } - self.maybe_uninit_bytes() + self.uninit_slice() } // Specialize these methods so they can skip checking `remaining_mut` From b8fe6f542b06dcf63f89587f9764552df89311b4 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 20:48:20 -0700 Subject: [PATCH 02/12] tweaks --- src/buf/buf_mut.rs | 57 ++++----------------------------------- src/buf/limit.rs | 2 +- src/buf/mod.rs | 4 ++- src/buf/uninit_slice.rs | 60 +++++++++++++++++++++++++++++++++++++++++ tests/test_buf_mut.rs | 3 ++- 5 files changed, 71 insertions(+), 55 deletions(-) create mode 100644 src/buf/uninit_slice.rs diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index abaf59db6..d930e126f 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -1,20 +1,15 @@ -use crate::buf::{limit, Chain, Limit}; +use crate::buf::{limit, Chain, Limit, UninitSlice}; #[cfg(feature = "std")] use crate::buf::{writer, Writer}; use core::{ cmp, - mem::{self, MaybeUninit}, + mem, ptr, usize, }; use alloc::{boxed::Box, vec::Vec}; -/// TODO -#[derive(Debug)] -#[repr(transparent)] -pub struct UninitSlice([MaybeUninit]); - /// A trait for values that provide sequential write access to bytes. /// /// Write bytes to a buffer @@ -1014,7 +1009,7 @@ unsafe impl BufMut for &mut [u8] { #[inline] fn bytes_mut(&mut self) -> &mut UninitSlice { // UninitSlice is repr(transparent), so safe to transmute - unsafe { mem::transmute(&mut **self) } + unsafe { &mut *(*self as *mut [u8] as *mut _) } } #[inline] @@ -1048,8 +1043,6 @@ unsafe impl BufMut for Vec { #[inline] fn bytes_mut(&mut self) -> &mut UninitSlice { - use core::slice; - if self.capacity() == self.len() { self.reserve(64); // Grow the vec } @@ -1057,11 +1050,9 @@ unsafe impl BufMut for Vec { let cap = self.capacity(); let len = self.len(); - let ptr = self.as_mut_ptr() as *mut MaybeUninit; + let ptr = self.as_mut_ptr(); unsafe { - let maybe_uninit: &mut [MaybeUninit] = - &mut slice::from_raw_parts_mut(ptr, cap)[len..]; - &mut *(maybe_uninit as *mut [MaybeUninit] as *mut _) + &mut UninitSlice::from_raw_parts_mut(ptr, cap)[len..] } } @@ -1097,41 +1088,3 @@ unsafe impl BufMut for Vec { // The existence of this function makes the compiler catch if the BufMut // trait is "object-safe" or not. fn _assert_trait_object(_b: &dyn BufMut) {} - -impl UninitSlice { - /// TODO - pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { - let maybe_init: &mut [MaybeUninit] = std::slice::from_raw_parts_mut(ptr as *mut _, len); - &mut *(maybe_init as *mut [MaybeUninit] as *mut UninitSlice) - } - - /// TODO - pub fn as_mut_ptr(&mut self) -> *mut u8 { - self.0.as_mut_ptr() as *mut _ - } - - /// TODO - pub fn len(&self) -> usize { - self.0.len() - } - - // /// TODO - // pub fn slice_mut(&mut self, range: std::ops::Range) -> &mut UninitSlice { - // let maybe_init = &mut self.0[range]; - // unsafe { &mut *(maybe_init as *mut [MaybeUninit] as *mut Uni)} - // } -} - -impl std::ops::Index> for UninitSlice { - type Output = UninitSlice; - - fn index(&self, index: std::ops::RangeTo) -> &UninitSlice { - unimplemented!() - } -} - -impl std::ops::IndexMut> for UninitSlice { - fn index_mut(&mut self, index: std::ops::RangeTo) -> &mut Self::Output { - unimplemented!() - } -} diff --git a/src/buf/limit.rs b/src/buf/limit.rs index a60218520..5cbbbfe6b 100644 --- a/src/buf/limit.rs +++ b/src/buf/limit.rs @@ -1,7 +1,7 @@ use crate::buf::UninitSlice; use crate::BufMut; -use core::{cmp, mem::MaybeUninit}; +use core::cmp; /// A `BufMut` adapter which limits the amount of bytes that can be written /// to an underlying buffer. diff --git a/src/buf/mod.rs b/src/buf/mod.rs index bbf1cf745..c4c0a5724 100644 --- a/src/buf/mod.rs +++ b/src/buf/mod.rs @@ -24,16 +24,18 @@ mod limit; #[cfg(feature = "std")] mod reader; mod take; +mod uninit_slice; mod vec_deque; #[cfg(feature = "std")] mod writer; pub use self::buf_impl::Buf; -pub use self::buf_mut::{BufMut, UninitSlice}; +pub use self::buf_mut::BufMut; pub use self::chain::Chain; pub use self::iter::IntoIter; pub use self::limit::Limit; pub use self::take::Take; +pub use self::uninit_slice::UninitSlice; #[cfg(feature = "std")] pub use self::{reader::Reader, writer::Writer}; diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs new file mode 100644 index 000000000..23112c3a2 --- /dev/null +++ b/src/buf/uninit_slice.rs @@ -0,0 +1,60 @@ +use core::mem::MaybeUninit; +use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; + +/// TODO +#[derive(Debug)] +#[repr(transparent)] +pub struct UninitSlice([MaybeUninit]); + +impl UninitSlice { + /// TODO + pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { + let maybe_init: &mut [MaybeUninit] = std::slice::from_raw_parts_mut(ptr as *mut _, len); + &mut *(maybe_init as *mut [MaybeUninit] as *mut UninitSlice) + } + + /// TODO + pub fn as_ptr(&self) -> *const u8 { + self.0.as_ptr() as *const _ + } + + /// TODO + pub fn as_mut_ptr(&mut self) -> *mut u8 { + self.0.as_mut_ptr() as *mut _ + } + + /// TODO + pub fn len(&self) -> usize { + self.0.len() + } +} + +macro_rules! impl_index { + ($($t:ty),*) => { + $( + impl Index<$t> for UninitSlice { + type Output = UninitSlice; + + fn index(&self, index: $t) -> &UninitSlice { + let maybe_uninit = &self.0[index]; + unsafe { &*(maybe_uninit as *const [MaybeUninit] as *const UninitSlice) } + } + } + + impl IndexMut<$t> for UninitSlice { + fn index_mut(&mut self, index: $t) -> &mut UninitSlice { + let maybe_uninit = &mut self.0[index]; + unsafe { &mut *(maybe_uninit as *mut [MaybeUninit] as *mut UninitSlice) } + } + } + )* + }; +} + +impl_index!( + Range, + RangeFrom, + RangeFull, + RangeInclusive, + RangeTo, + RangeToInclusive); diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index e9948839a..84b29a127 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -1,6 +1,7 @@ #![warn(rust_2018_idioms)] use bytes::{BufMut, BytesMut}; +use bytes::buf::UninitSlice; use core::fmt::Write; use core::usize; @@ -80,7 +81,7 @@ fn test_deref_bufmut_forwards() { unreachable!("remaining_mut"); } - fn bytes_mut(&mut self) -> &mut [std::mem::MaybeUninit] { + fn bytes_mut(&mut self) -> &mut UninitSlice { unreachable!("bytes_mut"); } From 252a31a429ed05a5f01307da802e02750b3ed7bd Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 20:49:25 -0700 Subject: [PATCH 03/12] fmt --- src/buf/buf_mut.rs | 10 ++-------- src/buf/uninit_slice.rs | 11 +++++++---- tests/test_buf_mut.rs | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index d930e126f..40cdd6282 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -2,11 +2,7 @@ use crate::buf::{limit, Chain, Limit, UninitSlice}; #[cfg(feature = "std")] use crate::buf::{writer, Writer}; -use core::{ - cmp, - mem, - ptr, usize, -}; +use core::{cmp, mem, ptr, usize}; use alloc::{boxed::Box, vec::Vec}; @@ -1051,9 +1047,7 @@ unsafe impl BufMut for Vec { let len = self.len(); let ptr = self.as_mut_ptr(); - unsafe { - &mut UninitSlice::from_raw_parts_mut(ptr, cap)[len..] - } + unsafe { &mut UninitSlice::from_raw_parts_mut(ptr, cap)[len..] } } // Specialize these methods so they can skip checking `remaining_mut` diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 23112c3a2..0e3996900 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -1,5 +1,7 @@ use core::mem::MaybeUninit; -use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +use core::ops::{ + Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, +}; /// TODO #[derive(Debug)] @@ -34,13 +36,13 @@ macro_rules! impl_index { $( impl Index<$t> for UninitSlice { type Output = UninitSlice; - + fn index(&self, index: $t) -> &UninitSlice { let maybe_uninit = &self.0[index]; unsafe { &*(maybe_uninit as *const [MaybeUninit] as *const UninitSlice) } } } - + impl IndexMut<$t> for UninitSlice { fn index_mut(&mut self, index: $t) -> &mut UninitSlice { let maybe_uninit = &mut self.0[index]; @@ -57,4 +59,5 @@ impl_index!( RangeFull, RangeInclusive, RangeTo, - RangeToInclusive); + RangeToInclusive +); diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index 84b29a127..b1b903115 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -1,7 +1,7 @@ #![warn(rust_2018_idioms)] -use bytes::{BufMut, BytesMut}; use bytes::buf::UninitSlice; +use bytes::{BufMut, BytesMut}; use core::fmt::Write; use core::usize; From d0ab1de0832ad5a27925897b6fe0abd863da1d70 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 22:09:11 -0700 Subject: [PATCH 04/12] docs --- src/buf/buf_mut.rs | 20 ++++++------- src/buf/uninit_slice.rs | 66 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 40cdd6282..005f405fe 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -71,14 +71,14 @@ pub unsafe trait BufMut { /// /// unsafe { /// // MaybeUninit::as_mut_ptr - /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); + /// buf.bytes_mut()[0..].as_mut_ptr().write(b'h'); + /// buf.bytes_mut()[1..].as_mut_ptr().write(b'e'); /// /// buf.advance_mut(2); /// - /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// buf.bytes_mut()[0..].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[1..].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[2..].as_mut_ptr().write(b'o'); /// /// buf.advance_mut(3); /// } @@ -140,14 +140,14 @@ pub unsafe trait BufMut { /// /// unsafe { /// // MaybeUninit::as_mut_ptr - /// buf.bytes_mut()[0].as_mut_ptr().write(b'h'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'e'); + /// buf.bytes_mut()[0..].as_mut_ptr().write(b'h'); + /// buf.bytes_mut()[1..].as_mut_ptr().write(b'e'); /// /// buf.advance_mut(2); /// - /// buf.bytes_mut()[0].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[1].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[2].as_mut_ptr().write(b'o'); + /// buf.bytes_mut()[0..].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[1..].as_mut_ptr().write(b'l'); + /// buf.bytes_mut()[2..].as_mut_ptr().write(b'o'); /// /// buf.advance_mut(3); /// } diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 0e3996900..1fbd9ee81 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -3,29 +3,83 @@ use core::ops::{ Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -/// TODO +/// Uninititialized byte slice. +/// +/// Returned by `BufMut::bytes_mut()`, the referenced byte slice may be +/// uninitialized. The wrapper provides safe access without introducing +/// undefined behavior. #[derive(Debug)] #[repr(transparent)] pub struct UninitSlice([MaybeUninit]); impl UninitSlice { - /// TODO + /// Create a `&mut UninitSlice` from a pointer and a length. + /// + /// # Safety + /// + /// The caller must ensure that `ptr` references a valid memory region owned + /// by the caller representing a byte slice for the duration of `'a`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::UninitSlice; + /// + /// let bytes = b"hello world".to_vec(); + /// let ptr = bytes.as_ptr() as *mut _; + /// let len = bytes.len(); + /// + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(ptr, len) }; + /// ``` pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice { - let maybe_init: &mut [MaybeUninit] = std::slice::from_raw_parts_mut(ptr as *mut _, len); + let maybe_init: &mut [MaybeUninit] = + core::slice::from_raw_parts_mut(ptr as *mut _, len); &mut *(maybe_init as *mut [MaybeUninit] as *mut UninitSlice) } - /// TODO + /// Return a raw pointer to the slice's buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut data = [0, 1, 2]; + /// let mut slice = &mut data[..]; + /// let ptr = BufMut::bytes_mut(&mut slice).as_ptr(); + /// ``` pub fn as_ptr(&self) -> *const u8 { self.0.as_ptr() as *const _ } - /// TODO + /// Return a raw pointer to the slice's buffer. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut data = [0, 1, 2]; + /// let mut slice = &mut data[..]; + /// let ptr = BufMut::bytes_mut(&mut slice).as_mut_ptr(); + /// ``` pub fn as_mut_ptr(&mut self) -> *mut u8 { self.0.as_mut_ptr() as *mut _ } - /// TODO + /// Returns the number of bytes in the slice. + /// + /// # Examples + /// + /// ``` + /// use bytes::BufMut; + /// + /// let mut data = [0, 1, 2]; + /// let mut slice = &mut data[..]; + /// let len = BufMut::bytes_mut(&mut slice).len(); + /// + /// assert_eq!(len, 3); + /// ``` pub fn len(&self) -> usize { self.0.len() } From 8fea13cd2d225fd92c27bbaca59ad6376bfc350b Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 22:13:12 -0700 Subject: [PATCH 05/12] fmt::Debug --- src/buf/uninit_slice.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 1fbd9ee81..f8d1f7040 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -1,3 +1,4 @@ +use core::fmt; use core::mem::MaybeUninit; use core::ops::{ Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, @@ -8,7 +9,6 @@ use core::ops::{ /// Returned by `BufMut::bytes_mut()`, the referenced byte slice may be /// uninitialized. The wrapper provides safe access without introducing /// undefined behavior. -#[derive(Debug)] #[repr(transparent)] pub struct UninitSlice([MaybeUninit]); @@ -85,6 +85,13 @@ impl UninitSlice { } } +impl fmt::Debug for UninitSlice { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("UninitSlice[...]") + .finish() + } +} + macro_rules! impl_index { ($($t:ty),*) => { $( From 00b6d89f656b08fd3a2bfd5f4a7cdcfdef10d5ec Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Fri, 16 Oct 2020 22:15:18 -0700 Subject: [PATCH 06/12] fmt --- src/buf/uninit_slice.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index f8d1f7040..dc9335993 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -87,8 +87,7 @@ impl UninitSlice { impl fmt::Debug for UninitSlice { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("UninitSlice[...]") - .finish() + fmt.debug_struct("UninitSlice[...]").finish() } } From 885315182693793b76ee80fc36a5561461607112 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 17 Oct 2020 13:04:48 -0700 Subject: [PATCH 07/12] add additional helpers --- src/buf/buf_mut.rs | 17 +++++-------- src/buf/uninit_slice.rs | 56 +++++++++++++++++++++++++++++++++++------ tests/test_buf_mut.rs | 18 +++++++++++++ tests/test_bytes.rs | 4 +-- 4 files changed, 75 insertions(+), 20 deletions(-) diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 005f405fe..0018e6137 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -69,19 +69,14 @@ pub unsafe trait BufMut { /// /// let mut buf = Vec::with_capacity(16); /// - /// unsafe { - /// // MaybeUninit::as_mut_ptr - /// buf.bytes_mut()[0..].as_mut_ptr().write(b'h'); - /// buf.bytes_mut()[1..].as_mut_ptr().write(b'e'); + /// // Write some data + /// buf.bytes_mut()[0..2].write_slice(b"he"); + /// unsafe { buf.advance_mut(2) }; /// - /// buf.advance_mut(2); + /// // write more bytes + /// buf.bytes_mut()[0..3].write_slice(b"llo"); /// - /// buf.bytes_mut()[0..].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[1..].as_mut_ptr().write(b'l'); - /// buf.bytes_mut()[2..].as_mut_ptr().write(b'o'); - /// - /// buf.advance_mut(3); - /// } + /// unsafe { buf.advance_mut(3); } /// /// assert_eq!(5, buf.len()); /// assert_eq!(buf, b"hello"); diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index dc9335993..b6ecd7a3d 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -37,23 +37,65 @@ impl UninitSlice { &mut *(maybe_init as *mut [MaybeUninit] as *mut UninitSlice) } - /// Return a raw pointer to the slice's buffer. + /// Write a single byte at the specified offset. + /// + /// # Panics + /// + /// The function panics if `index` is out of bounds. /// /// # Examples /// /// ``` - /// use bytes::BufMut; + /// use bytes::buf::UninitSlice; /// - /// let mut data = [0, 1, 2]; - /// let mut slice = &mut data[..]; - /// let ptr = BufMut::bytes_mut(&mut slice).as_ptr(); + /// let mut data = [b'f', b'o', b'o']; + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + /// + /// slice.write_byte(0, b'b'); + /// + /// assert_eq!(b"boo", &data[..]); + /// ``` + pub fn write_byte(&mut self, index: usize, byte: u8) { + assert!(index < self.len()); + + unsafe { self.as_mut_ptr().offset(index as isize).write(byte) }; + } + + /// Writes the contents of `src` into `self. + /// + /// # Panics + /// + /// The function panics if `self` has a different length than `src`. + /// + /// # Examples + /// + /// ``` + /// use bytes::buf::UninitSlice; + /// + /// let mut data = [b'f', b'o', b'o']; + /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + /// + /// slice.write_slice(b"bar"); + /// + /// assert_eq!(b"bar", &data[..]); /// ``` - pub fn as_ptr(&self) -> *const u8 { - self.0.as_ptr() as *const _ + pub fn write_slice(&mut self, src: &[u8]) { + use std::ptr; + + assert_eq!(self.len(), src.len()); + + unsafe { + ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len()); + } } /// Return a raw pointer to the slice's buffer. /// + /// # Safety + /// + /// The caller **must not** read from the referenced memory and **must not** + /// write uninitialized bytes to the slice either. + /// /// # Examples /// /// ``` diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index b1b903115..7ce3405b7 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -100,3 +100,21 @@ fn test_deref_bufmut_forwards() { (Box::new(Special) as Box).put_u8(b'x'); Box::new(Special).put_u8(b'x'); } + +#[test] +#[should_panic] +fn write_byte_panics_if_out_of_bounds() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.write_byte(4, b'f'); +} + +#[test] +#[should_panic] +fn write_slice_panics_if_different_length() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.write_slice(b"a"); +} diff --git a/tests/test_bytes.rs b/tests/test_bytes.rs index 6b106a6bc..b97cce6cb 100644 --- a/tests/test_bytes.rs +++ b/tests/test_bytes.rs @@ -912,12 +912,12 @@ fn bytes_buf_mut_advance() { let mut bytes = BytesMut::with_capacity(1024); unsafe { - let ptr = bytes.bytes_mut().as_ptr(); + let ptr = bytes.bytes_mut().as_mut_ptr(); assert_eq!(1024, bytes.bytes_mut().len()); bytes.advance_mut(10); - let next = bytes.bytes_mut().as_ptr(); + let next = bytes.bytes_mut().as_mut_ptr(); assert_eq!(1024 - 10, bytes.bytes_mut().len()); assert_eq!(ptr.offset(10), next); From e7ae35c6745f72b5a84468dd7a92c12abb6e924d Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Sat, 17 Oct 2020 14:59:40 -0700 Subject: [PATCH 08/12] fix core --- src/buf/uninit_slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index b6ecd7a3d..45f015e8e 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -80,7 +80,7 @@ impl UninitSlice { /// assert_eq!(b"bar", &data[..]); /// ``` pub fn write_slice(&mut self, src: &[u8]) { - use std::ptr; + use core::ptr; assert_eq!(self.len(), src.len()); From a8fdfd199e86660b89457332484fa51deb7b111b Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 19 Oct 2020 15:22:21 -0700 Subject: [PATCH 09/12] Update src/buf/uninit_slice.rs Co-authored-by: Alice Ryhl --- src/buf/uninit_slice.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 45f015e8e..79de6c9b5 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -4,11 +4,20 @@ use core::ops::{ Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -/// Uninititialized byte slice. +/// Uninitialized byte slice. /// /// Returned by `BufMut::bytes_mut()`, the referenced byte slice may be /// uninitialized. The wrapper provides safe access without introducing /// undefined behavior. +/// +/// The safety invariants of this wrapper are: +/// +/// 1. Reading from an `UninitSlice` is undefined behavior. +/// 2. Writing uninitialized bytes to an `UninitSlice` is undefined behavior. +/// +/// The difference between `&mut UninitSlice` and `&mut [MaybeUninit]` is +/// that it is possible in safe code to write uninitialized bytes to an +/// `&mut [MaybeUninit]`, which this type prohibits. #[repr(transparent)] pub struct UninitSlice([MaybeUninit]); From 200ed46852533c236d5fc8cb2513e8424041eb3d Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 19 Oct 2020 15:23:12 -0700 Subject: [PATCH 10/12] Update src/buf/uninit_slice.rs Co-authored-by: Alice Ryhl --- src/buf/uninit_slice.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 79de6c9b5..190223de7 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -149,14 +149,14 @@ macro_rules! impl_index { type Output = UninitSlice; fn index(&self, index: $t) -> &UninitSlice { - let maybe_uninit = &self.0[index]; + let maybe_uninit: &[MaybeUninit] = &self.0[index]; unsafe { &*(maybe_uninit as *const [MaybeUninit] as *const UninitSlice) } } } impl IndexMut<$t> for UninitSlice { fn index_mut(&mut self, index: $t) -> &mut UninitSlice { - let maybe_uninit = &mut self.0[index]; + let maybe_uninit: &mut [MaybeUninit] = &mut self.0[index]; unsafe { &mut *(maybe_uninit as *mut [MaybeUninit] as *mut UninitSlice) } } } From 38e2fe1d2aaaa7e2589ef0b17f63081222040653 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 19 Oct 2020 15:23:45 -0700 Subject: [PATCH 11/12] Update src/buf/uninit_slice.rs Co-authored-by: Alice Ryhl --- src/buf/uninit_slice.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 190223de7..9d99fd1fc 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -70,7 +70,7 @@ impl UninitSlice { unsafe { self.as_mut_ptr().offset(index as isize).write(byte) }; } - /// Writes the contents of `src` into `self. + /// Writes the contents of `src` into `self`. /// /// # Panics /// From 1a87a33a6beac253175cfbdec10c36abb6b94543 Mon Sep 17 00:00:00 2001 From: Carl Lerche Date: Mon, 19 Oct 2020 15:34:32 -0700 Subject: [PATCH 12/12] apply feedback --- src/buf/buf_mut.rs | 4 ++-- src/buf/uninit_slice.rs | 14 ++++++++------ tests/test_buf_mut.rs | 13 +++++++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/buf/buf_mut.rs b/src/buf/buf_mut.rs index 0018e6137..fb3623d25 100644 --- a/src/buf/buf_mut.rs +++ b/src/buf/buf_mut.rs @@ -70,11 +70,11 @@ pub unsafe trait BufMut { /// let mut buf = Vec::with_capacity(16); /// /// // Write some data - /// buf.bytes_mut()[0..2].write_slice(b"he"); + /// buf.bytes_mut()[0..2].copy_from_slice(b"he"); /// unsafe { buf.advance_mut(2) }; /// /// // write more bytes - /// buf.bytes_mut()[0..3].write_slice(b"llo"); + /// buf.bytes_mut()[0..3].copy_from_slice(b"llo"); /// /// unsafe { buf.advance_mut(3); } /// diff --git a/src/buf/uninit_slice.rs b/src/buf/uninit_slice.rs index 9d99fd1fc..32ebde4c5 100644 --- a/src/buf/uninit_slice.rs +++ b/src/buf/uninit_slice.rs @@ -67,14 +67,16 @@ impl UninitSlice { pub fn write_byte(&mut self, index: usize, byte: u8) { assert!(index < self.len()); - unsafe { self.as_mut_ptr().offset(index as isize).write(byte) }; + unsafe { self[index..].as_mut_ptr().write(byte) } } - /// Writes the contents of `src` into `self`. + /// Copies bytes from `src` into `self`. + /// + /// The length of `src` must be the same as `self`. /// /// # Panics /// - /// The function panics if `self` has a different length than `src`. + /// The function panics if `src` has a different length than `self`. /// /// # Examples /// @@ -84,11 +86,11 @@ impl UninitSlice { /// let mut data = [b'f', b'o', b'o']; /// let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; /// - /// slice.write_slice(b"bar"); + /// slice.copy_from_slice(b"bar"); /// /// assert_eq!(b"bar", &data[..]); /// ``` - pub fn write_slice(&mut self, src: &[u8]) { + pub fn copy_from_slice(&mut self, src: &[u8]) { use core::ptr; assert_eq!(self.len(), src.len()); @@ -103,7 +105,7 @@ impl UninitSlice { /// # Safety /// /// The caller **must not** read from the referenced memory and **must not** - /// write uninitialized bytes to the slice either. + /// write **uninitialized** bytes to the slice either. /// /// # Examples /// diff --git a/tests/test_buf_mut.rs b/tests/test_buf_mut.rs index 7ce3405b7..406ec510c 100644 --- a/tests/test_buf_mut.rs +++ b/tests/test_buf_mut.rs @@ -112,9 +112,18 @@ fn write_byte_panics_if_out_of_bounds() { #[test] #[should_panic] -fn write_slice_panics_if_different_length() { +fn copy_from_slice_panics_if_different_length_1() { let mut data = [b'b', b'a', b'r']; let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; - slice.write_slice(b"a"); + slice.copy_from_slice(b"a"); +} + +#[test] +#[should_panic] +fn copy_from_slice_panics_if_different_length_2() { + let mut data = [b'b', b'a', b'r']; + + let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), 3) }; + slice.copy_from_slice(b"abcd"); }