Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Ref more with_elems Ref constructors #1258

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/deprecated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ where
#[must_use = "has no side effects"]
#[inline]
pub fn new(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> {
Self::from(bytes)
Self::from_bytes(bytes)
}
}

Expand Down Expand Up @@ -63,7 +63,7 @@ where
#[doc(hidden)]
#[inline]
pub fn new_slice(bytes: B) -> Option<Ref<B, [T]>> {
Self::from(bytes).ok()
Self::from_bytes(bytes).ok()
}
}

Expand Down
94 changes: 69 additions & 25 deletions src/ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ where
{
/// Constructs a new `Ref` from a byte slice.
///
/// `from` verifies that `bytes.len() == size_of::<T>()` and that `bytes` is
/// aligned to `align_of::<T>()`, and constructs a new `Ref`. If either of
/// these checks fail, it returns `None`.
/// `from_bytes` verifies that `bytes.len() == size_of::<T>()` and that
/// `bytes` is aligned to `align_of::<T>()`, and constructs a new `Ref`. If
/// either of these checks fail, it returns `None`.
///
/// # Compile-Time Assertions
///
Expand All @@ -296,11 +296,11 @@ where
/// trailing_dst: [()],
/// }
///
/// let _ = Ref::<_, ZSTy>::from(&b"UU"[..]); // ⚠ Compile Error!
/// let _ = Ref::<_, ZSTy>::from_bytes(&b"UU"[..]); // ⚠ Compile Error!
/// ```
#[must_use = "has no side effects"]
#[inline]
pub fn from(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> {
pub fn from_bytes(bytes: B) -> Result<Ref<B, T>, CastError<B, T>> {
util::assert_dst_is_not_zst::<T>();
if let Err(e) =
Ptr::from_ref(bytes.deref()).try_cast_into_no_leftover::<T, BecauseImmutable>(None)
Expand Down Expand Up @@ -429,6 +429,28 @@ where
}
}

impl<B, T> Ref<B, T>
where
B: ByteSlice,
T: KnownLayout<PointerMetadata = usize> + Immutable + ?Sized,
{
// TODO(#29), TODO(#871): Pick a name and make this public. Make sure to
// update references to this name in `#[deprecated]` attributes elsewhere.
#[doc(hidden)]
#[inline]
pub fn from_bytes_with_elems(bytes: B, count: usize) -> Result<Ref<B, T>, CastError<B, T>> {
util::assert_dst_is_not_zst::<T>();
let expected_len = match count.size_for_metadata(T::LAYOUT) {
Some(len) => len,
None => return Err(SizeError::new(bytes).into()),
};
if bytes.len() != expected_len {
return Err(SizeError::new(bytes).into());
}
Self::from_bytes(bytes)
}
}

impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
Expand All @@ -451,7 +473,7 @@ where
return Err(SizeError::new(bytes).into());
}
let (prefix, bytes) = bytes.split_at(expected_len);
Self::from(prefix).map(move |l| (l, bytes))
Self::from_bytes(prefix).map(move |l| (l, bytes))
}
}

Expand Down Expand Up @@ -479,7 +501,7 @@ where
return Err(SizeError::new(bytes).into());
};
let (bytes, suffix) = bytes.split_at(split_at);
Self::from(suffix).map(move |l| (bytes, l))
Self::from_bytes(suffix).map(move |l| (bytes, l))
}
}

Expand Down Expand Up @@ -517,7 +539,7 @@ where
#[inline(always)]
pub fn unaligned_from(bytes: B) -> Result<Ref<B, T>, SizeError<B, T>> {
util::assert_dst_is_not_zst::<T>();
match Ref::from(bytes) {
match Ref::from_bytes(bytes) {
Ok(dst) => Ok(dst),
Err(CastError::Size(e)) => Err(e),
Err(CastError::Alignment(_)) => unreachable!(),
Expand Down Expand Up @@ -608,6 +630,28 @@ where
}
}

impl<B, T> Ref<B, T>
where
B: ByteSlice,
T: KnownLayout<PointerMetadata = usize> + Unaligned + Immutable + ?Sized,
{
// TODO(#29), TODO(#871): Pick a name and make this public. Make sure to
// update references to this name in `#[deprecated]` attributes elsewhere.
#[doc(hidden)]
#[inline]
pub fn unaligned_from_bytes_with_elems(
bytes: B,
count: usize,
) -> Result<Ref<B, T>, SizeError<B, T>> {
util::assert_dst_is_not_zst::<T>();
Self::from_bytes_with_elems(bytes, count).map_err(|e| match e {
CastError::Size(e) => e,
CastError::Alignment(_) => unreachable!(),
CastError::Validity(i) => match i {},
})
}
}

impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
Expand Down Expand Up @@ -917,13 +961,13 @@ mod tests {
// reference which points to the right region of memory.

let buf = [0];
let r = Ref::<_, u8>::from(&buf[..]).unwrap();
let r = Ref::<_, u8>::from_bytes(&buf[..]).unwrap();
let buf_ptr = buf.as_ptr();
let deref_ptr: *const u8 = r.deref();
assert_eq!(buf_ptr, deref_ptr);

let buf = [0];
let r = Ref::<_, [u8]>::from(&buf[..]).unwrap();
let r = Ref::<_, [u8]>::from_bytes(&buf[..]).unwrap();
let buf_ptr = buf.as_ptr();
let deref_ptr = r.deref().as_ptr();
assert_eq!(buf_ptr, deref_ptr);
Expand Down Expand Up @@ -1045,7 +1089,7 @@ mod tests {
// A buffer with an alignment of 8.
let mut buf = Align::<[u8; 8], AU64>::default();
// `buf.t` should be aligned to 8, so this should always succeed.
test_new_helper(Ref::<_, AU64>::from(&mut buf.t[..]).unwrap());
test_new_helper(Ref::<_, AU64>::from_bytes(&mut buf.t[..]).unwrap());
{
// In a block so that `r` and `suffix` don't live too long.
buf.set_default();
Expand All @@ -1068,7 +1112,7 @@ mod tests {
let mut buf = Align::<[u8; 24], AU64>::default();
// `buf.t` should be aligned to 8 and have a length which is a multiple
// of `size_of::<AU64>()`, so this should always succeed.
test_new_helper_slice(Ref::<_, [AU64]>::from(&mut buf.t[..]).unwrap(), 3);
test_new_helper_slice(Ref::<_, [AU64]>::from_bytes(&mut buf.t[..]).unwrap(), 3);
let ascending: [u8; 24] = (0..24).collect::<Vec<_>>().try_into().unwrap();
// 16 ascending bytes followed by 8 zeros.
let mut ascending_prefix = ascending;
Expand Down Expand Up @@ -1224,15 +1268,15 @@ mod tests {
// A buffer with an alignment of 8.
let buf = Align::<[u8; 16], AU64>::default();
// `buf.t` should be aligned to 8, so only the length check should fail.
assert!(Ref::<_, AU64>::from(&buf.t[..]).is_err());
assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err());
assert!(Ref::<_, [u8; 8]>::unaligned_from(&buf.t[..]).is_err());

// Fail because the buffer is too small.

// A buffer with an alignment of 8.
let buf = Align::<[u8; 4], AU64>::default();
// `buf.t` should be aligned to 8, so only the length check should fail.
assert!(Ref::<_, AU64>::from(&buf.t[..]).is_err());
assert!(Ref::<_, AU64>::from_bytes(&buf.t[..]).is_err());
assert!(Ref::<_, [u8; 8]>::unaligned_from(&buf.t[..]).is_err());
assert!(Ref::<_, AU64>::from_prefix(&buf.t[..]).is_err());
assert!(Ref::<_, AU64>::from_suffix(&buf.t[..]).is_err());
Expand All @@ -1243,7 +1287,7 @@ mod tests {

let buf = Align::<[u8; 12], AU64>::default();
// `buf.t` has length 12, but element size is 8.
assert!(Ref::<_, [AU64]>::from(&buf.t[..]).is_err());
assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[..]).is_err());
assert!(Ref::<_, [[u8; 8]]>::unaligned_from(&buf.t[..]).is_err());

// Fail because the buffer is too short.
Expand All @@ -1262,9 +1306,9 @@ mod tests {
let buf = Align::<[u8; 13], AU64>::default();
// Slicing from 1, we get a buffer with size 12 (so the length check
// should succeed) but an alignment of only 1, which is insufficient.
assert!(Ref::<_, AU64>::from(&buf.t[1..]).is_err());
assert!(Ref::<_, AU64>::from_bytes(&buf.t[1..]).is_err());
assert!(Ref::<_, AU64>::from_prefix(&buf.t[1..]).is_err());
assert!(Ref::<_, [AU64]>::from(&buf.t[1..]).is_err());
assert!(Ref::<_, [AU64]>::from_bytes(&buf.t[1..]).is_err());
assert!(Ref::<_, [AU64]>::from_prefix_with_elems(&buf.t[1..], 1).is_err());
assert!(Ref::<_, [AU64]>::from_suffix_with_elems(&buf.t[1..], 1).is_err());
// Slicing is unnecessary here because `new_from_suffix` uses the suffix
Expand Down Expand Up @@ -1292,39 +1336,39 @@ mod tests {
#[test]
fn test_display_debug() {
let buf = Align::<[u8; 8], u64>::default();
let r = Ref::<_, u64>::from(&buf.t[..]).unwrap();
let r = Ref::<_, u64>::from_bytes(&buf.t[..]).unwrap();
assert_eq!(format!("{}", r), "0");
assert_eq!(format!("{:?}", r), "Ref(0)");

let buf = Align::<[u8; 8], u64>::default();
let r = Ref::<_, [u64]>::from(&buf.t[..]).unwrap();
let r = Ref::<_, [u64]>::from_bytes(&buf.t[..]).unwrap();
assert_eq!(format!("{:?}", r), "Ref([0])");
}

#[test]
fn test_eq() {
let buf1 = 0_u64;
let r1 = Ref::<_, u64>::from(buf1.as_bytes()).unwrap();
let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
let buf2 = 0_u64;
let r2 = Ref::<_, u64>::from(buf2.as_bytes()).unwrap();
let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
assert_eq!(r1, r2);
}

#[test]
fn test_ne() {
let buf1 = 0_u64;
let r1 = Ref::<_, u64>::from(buf1.as_bytes()).unwrap();
let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
let buf2 = 1_u64;
let r2 = Ref::<_, u64>::from(buf2.as_bytes()).unwrap();
let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
assert_ne!(r1, r2);
}

#[test]
fn test_ord() {
let buf1 = 0_u64;
let r1 = Ref::<_, u64>::from(buf1.as_bytes()).unwrap();
let r1 = Ref::<_, u64>::from_bytes(buf1.as_bytes()).unwrap();
let buf2 = 1_u64;
let r2 = Ref::<_, u64>::from(buf2.as_bytes()).unwrap();
let r2 = Ref::<_, u64>::from_bytes(buf2.as_bytes()).unwrap();
assert!(r1 < r2);
}
}
Loading