Skip to content

Commit

Permalink
Make BlobReader a slice newtype
Browse files Browse the repository at this point in the history
  • Loading branch information
kornelski committed Jul 30, 2024
1 parent 5283648 commit 345ccbd
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 42 deletions.
19 changes: 5 additions & 14 deletions recapn/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,7 @@ impl<'a> Reader<'a> {
/// If the slice is too large to be in a message, this function panics.
#[inline]
pub const fn from_slice(slice: &'a [u8]) -> Self {
let len = slice.len();
if len > ElementCount::MAX_VALUE as usize {
panic!("slice is too large to be contained within a cap'n proto message")
}

let count = ElementCount::new(len as u32).unwrap();
unsafe {
let ptr = NonNull::new_unchecked(slice.as_ptr().cast_mut());
Self(ptr::Reader::new(ptr, count))
}
Self(ptr::Reader::new(slice).expect("slice is too large to be contained within a cap'n proto message"))
}

#[inline]
Expand All @@ -83,9 +74,7 @@ impl<'a> Reader<'a> {

#[inline]
pub const fn as_slice(&self) -> &'a [u8] {
let data = self.0.data().as_ptr().cast_const();
let len = self.len() as usize;
unsafe { core::slice::from_raw_parts(data, len) }
self.0.as_slice()
}
}

Expand Down Expand Up @@ -164,7 +153,9 @@ impl<'a> Builder<'a> {

#[inline]
pub fn as_reader<'b>(&'b self) -> Reader<'b> {
Data(ptr::Reader::new(self.0.data(), self.0.len()))
Data(unsafe {
ptr::Reader::new_unchecked(self.0.data(), self.0.len())
})
}

#[inline]
Expand Down
11 changes: 9 additions & 2 deletions recapn/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use core::cmp;
use core::fmt;
use core::hint::unreachable_unchecked;
use core::num::NonZeroU32;

/// A simple macro to implement cmp traits using the inner type gotten through a get() function
Expand Down Expand Up @@ -93,15 +94,21 @@ impl u29 {
#[inline]
pub const fn new(n: u32) -> Option<Self> {
if n >= Self::MIN_VALUE && n <= Self::MAX_VALUE {
Some(unsafe { Self::new_unchecked(n) })
Some(Self(n))
} else {
None
}
}

#[inline]
pub const unsafe fn new_unchecked(n: u32) -> Self {
Self(n)
match Self::new(n) {
Some(n) => n,
_ => {
// actually checked with debug_assertions on
unreachable_unchecked()
}
}
}

#[inline]
Expand Down
48 changes: 31 additions & 17 deletions recapn/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2256,7 +2256,9 @@ impl<'a, T: Table> PtrReader<'a, T> {
}
}?;

Ok(BlobReader::new(ptr.as_inner().cast(), element_count))
Ok(unsafe {
BlobReader::new_unchecked(ptr.as_inner().cast(), element_count)
})
}

#[inline]
Expand Down Expand Up @@ -2915,32 +2917,43 @@ impl<'a, T: Table> Capable for ListReader<'a, T> {

#[derive(Clone, Copy)]
pub struct BlobReader<'a> {
a: PhantomData<&'a [u8]>,
ptr: NonNull<u8>,
len: ElementCount,
slice: &'a [u8],
}

impl<'a> BlobReader<'a> {
pub(crate) const fn new(ptr: NonNull<u8>, len: ElementCount) -> Self {
Self { a: PhantomData, ptr, len }
#[inline]
pub(crate) const fn new(slice: &'a [u8]) -> Option<Self> {
if slice.len() < ElementCount::MAX_VALUE as usize {
Some(Self { slice })
} else {
None
}
}

pub(crate) const unsafe fn new_unchecked(ptr: NonNull<u8>, len: ElementCount) -> Self {
Self {
slice: std::slice::from_raw_parts(ptr.as_ptr(), len.get() as usize),
}
}

pub const fn empty() -> Self {
Self::new(NonNull::dangling(), ElementCount::ZERO)
Self { slice: &[] }
}

pub const fn data(&self) -> NonNull<u8> {
self.ptr
unsafe {
NonNull::new_unchecked(self.slice.as_ptr().cast_mut())
}
}

pub const fn len(&self) -> ElementCount {
self.len
unsafe {
ElementCount::new_unchecked(self.slice.len() as _)
}
}

pub const fn as_slice(&self) -> &'a [u8] {
unsafe {
core::slice::from_raw_parts(self.ptr.as_ptr().cast_const(), self.len.get() as usize)
}
self.slice
}
}

Expand Down Expand Up @@ -5268,18 +5281,19 @@ impl BlobBuilder<'_> {

#[inline]
pub const fn as_reader(&self) -> BlobReader {
BlobReader::new(self.ptr, self.len)
unsafe {
BlobReader::new_unchecked(self.ptr, self.len)
}
}

#[inline]
pub(crate) fn copy_from(&mut self, other: BlobReader) {
assert_eq!(self.len, other.len);
assert_eq!(self.len, other.len());

let dst = self.ptr.as_ptr();
let src = other.ptr.as_ptr().cast_const();
let len = other.len.get() as usize;
let src = other.as_slice();
unsafe {
ptr::copy_nonoverlapping(src, dst, len)
ptr::copy_nonoverlapping(src.as_ptr(), dst, src.len())
}
}

Expand Down
25 changes: 16 additions & 9 deletions recapn/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ impl<'a> Reader<'a> {
#[inline]
pub const fn from_slice(s: &'a [u8]) -> Self {
match s {
[.., 0] if s.len() <= ByteCount::MAX_VALUE as usize => {
let ptr = unsafe { NonNull::new_unchecked(s.as_ptr().cast_mut()) };
let len = ElementCount::new(s.len() as u32).unwrap();
Self(ptr::Reader::new(ptr, len))
[.., 0] => {
match ptr::Reader::new(s) {
Some(r) => Some(Self(r)),
None => None,
}
},
_ => panic!("attempted to make invalid text blob from slice"),
_ => None,
}
.expect("attempted to make invalid text blob from slice")
}

pub const fn byte_count(&self) -> ByteCount {
Expand All @@ -99,14 +101,19 @@ impl<'a> Reader<'a> {
/// Returns the bytes of the text field without the null terminator
#[inline]
pub const fn as_bytes(&self) -> &'a [u8] {
let (_, remainder) = self.as_bytes_with_nul().split_last().unwrap();
remainder
match self.as_bytes_with_nul().split_last() {
Some((_, remainder)) => remainder,
_ => {
debug_assert!(false, "this shouldn't happen, it's to avoid panic code in release");
EMPTY_SLICE
},
}
}

/// Returns the bytes of the text field with the null terminator
#[inline]
pub const fn as_bytes_with_nul(&self) -> &'a [u8] {
unsafe { slice::from_raw_parts(self.0.data().as_ptr().cast_const(), self.len() as usize) }
self.0.as_slice()
}

#[inline]
Expand Down Expand Up @@ -254,4 +261,4 @@ impl PartialEq<Builder<'_>> for str {
fn eq(&self, other: &Builder<'_>) -> bool {
self.as_bytes() == other.as_bytes()
}
}
}

0 comments on commit 345ccbd

Please sign in to comment.