Skip to content

Commit d16f866

Browse files
committed
Add bytes to type reference helper methods to FromBytes
These helper methods intend to improve the developer experience. They follow the same naming and error handling scheme as `read_from`.
1 parent 2dcec73 commit d16f866

File tree

1 file changed

+156
-6
lines changed

1 file changed

+156
-6
lines changed

src/lib.rs

Lines changed: 156 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,94 @@ pub unsafe trait FromBytes: FromZeroes {
10001000
where
10011001
Self: Sized;
10021002

1003+
/// Interprets the given `bytes` as a `&Self` without copying.
1004+
///
1005+
/// If `bytes.len() != size_of::<T>()` or `bytes` is not aligned to
1006+
/// `align_of::<T>()`, this returns `None`.
1007+
#[inline]
1008+
fn ref_from(bytes: &[u8]) -> Option<&Self>
1009+
where
1010+
Self: Sized,
1011+
{
1012+
Ref::<&[u8], Self>::new(bytes).map(Ref::into_ref)
1013+
}
1014+
1015+
/// Interprets the prefix of the given `bytes` as a `&Self` without copying.
1016+
///
1017+
/// `ref_from_prefix` returns a reference to the first `size_of::<Self>()`
1018+
/// bytes of `bytes`. If `bytes.len() != size_of::<T>()` or `bytes` is not
1019+
/// aligned to `align_of::<T>()`, this returns `None`.
1020+
///
1021+
/// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then,
1022+
/// use [`Ref::into_ref`] to get a `&Self` with the same lifetime.
1023+
#[inline]
1024+
fn ref_from_prefix(bytes: &[u8]) -> Option<&Self>
1025+
where
1026+
Self: Sized,
1027+
{
1028+
Ref::<&[u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_ref())
1029+
}
1030+
1031+
/// Interprets the suffix of the given `bytes` as a `&Self` without copying.
1032+
///
1033+
/// `ref_from_suffix` returns a reference to the last `size_of::<Self>()`
1034+
/// bytes of `bytes`. If `bytes.len() != size_of::<T>()` or the suffix of
1035+
/// `bytes` is not aligned to `align_of::<T>()`, this returns `None`.
1036+
///
1037+
/// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then,
1038+
/// use [`Ref::into_ref`] to get a `&Self` with the same lifetime.
1039+
#[inline]
1040+
fn ref_from_suffix(bytes: &[u8]) -> Option<&Self>
1041+
where
1042+
Self: Sized,
1043+
{
1044+
Ref::<&[u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_ref())
1045+
}
1046+
1047+
/// Interprets the given `bytes` as a `&mut Self` without copying.
1048+
///
1049+
/// If `bytes.len() != size_of::<T>()` or `bytes` is not aligned to
1050+
/// `align_of::<T>()`, this returns `None`.
1051+
#[inline]
1052+
fn mut_from(bytes: &mut [u8]) -> Option<&mut Self>
1053+
where
1054+
Self: Sized + AsBytes,
1055+
{
1056+
Ref::<&mut [u8], Self>::new(bytes).map(Ref::into_mut)
1057+
}
1058+
1059+
/// Interprets the prefix of the given `bytes` as a `&mut Self` without copying.
1060+
///
1061+
/// `mut_from_prefix` returns a reference to the first `size_of::<Self>()`
1062+
/// bytes of `bytes`. If `bytes.len() != size_of::<T>()` or `bytes` is not
1063+
/// aligned to `align_of::<T>()`, this returns `None`.
1064+
///
1065+
/// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then,
1066+
/// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
1067+
#[inline]
1068+
fn mut_from_prefix(bytes: &mut [u8]) -> Option<&mut Self>
1069+
where
1070+
Self: Sized + AsBytes,
1071+
{
1072+
Ref::<&mut [u8], Self>::new_from_prefix(bytes).map(|(r, _)| r.into_mut())
1073+
}
1074+
1075+
/// Interprets the suffix of the given `bytes` as a `&mut Self` without copying.
1076+
///
1077+
/// `mut_from_suffix` returns a reference to the last `size_of::<Self>()`
1078+
/// bytes of `bytes`. If `bytes.len() != size_of::<T>()` or the suffix of
1079+
/// `bytes` is not aligned to `align_of::<T>()`, this returns `None`.
1080+
///
1081+
/// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then,
1082+
/// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
1083+
#[inline]
1084+
fn mut_from_suffix(bytes: &mut [u8]) -> Option<&mut Self>
1085+
where
1086+
Self: Sized + AsBytes,
1087+
{
1088+
Ref::<&mut [u8], Self>::new_from_suffix(bytes).map(|(_, r)| r.into_mut())
1089+
}
1090+
10031091
/// Reads a copy of `Self` from `bytes`.
10041092
///
10051093
/// If `bytes.len() != size_of::<Self>()`, `read_from` returns `None`.
@@ -1008,8 +1096,7 @@ pub unsafe trait FromBytes: FromZeroes {
10081096
where
10091097
Self: Sized,
10101098
{
1011-
let r = Ref::<_, Unalign<Self>>::new_unaligned(bytes)?;
1012-
Some(r.read().into_inner())
1099+
Ref::<_, Unalign<Self>>::new_unaligned(bytes).map(|r| r.read().into_inner())
10131100
}
10141101

10151102
/// Reads a copy of `Self` from the prefix of `bytes`.
@@ -1022,8 +1109,8 @@ pub unsafe trait FromBytes: FromZeroes {
10221109
where
10231110
Self: Sized,
10241111
{
1025-
let (r, _suffix) = Ref::<_, Unalign<Self>>::new_unaligned_from_prefix(bytes)?;
1026-
Some(r.read().into_inner())
1112+
Ref::<_, Unalign<Self>>::new_unaligned_from_prefix(bytes)
1113+
.map(|(r, _)| r.read().into_inner())
10271114
}
10281115

10291116
/// Reads a copy of `Self` from the suffix of `bytes`.
@@ -1036,8 +1123,8 @@ pub unsafe trait FromBytes: FromZeroes {
10361123
where
10371124
Self: Sized,
10381125
{
1039-
let (_prefix, r) = Ref::<_, Unalign<Self>>::new_unaligned_from_suffix(bytes)?;
1040-
Some(r.read().into_inner())
1126+
Ref::<_, Unalign<Self>>::new_unaligned_from_suffix(bytes)
1127+
.map(|(_, r)| r.read().into_inner())
10411128
}
10421129
}
10431130

@@ -4425,6 +4512,69 @@ mod tests {
44254512
}
44264513
}
44274514

4515+
#[test]
4516+
fn test_ref_from_mut_from() {
4517+
// Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` success cases
4518+
// Exhaustive coverage for these methods is covered by the `Ref` tests above,
4519+
// which these helper methods defer to.
4520+
4521+
let mut buf =
4522+
Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
4523+
4524+
assert_eq!(
4525+
AU64::ref_from(&buf.t[8..]).unwrap().0.to_ne_bytes(),
4526+
[8, 9, 10, 11, 12, 13, 14, 15]
4527+
);
4528+
let suffix = AU64::mut_from(&mut buf.t[8..]).unwrap();
4529+
suffix.0 = 0x0101010101010101;
4530+
assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]);
4531+
let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap();
4532+
suffix.0 = 0x0202020202020202;
4533+
<[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42;
4534+
assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]);
4535+
<[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30;
4536+
assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]);
4537+
}
4538+
4539+
#[test]
4540+
fn test_ref_from_mut_from_error() {
4541+
// Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` error cases.
4542+
4543+
// Fail because the buffer is too large.
4544+
let mut buf = Align::<[u8; 16], AU64>::default();
4545+
// `buf.t` should be aligned to 8, so only the length check should fail.
4546+
assert!(AU64::ref_from(&buf.t[..]).is_none());
4547+
assert!(AU64::mut_from(&mut buf.t[..]).is_none());
4548+
assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
4549+
assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
4550+
4551+
// Fail because the buffer is too small.
4552+
let mut buf = Align::<[u8; 4], AU64>::default();
4553+
assert!(AU64::ref_from(&buf.t[..]).is_none());
4554+
assert!(AU64::mut_from(&mut buf.t[..]).is_none());
4555+
assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
4556+
assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
4557+
assert!(AU64::ref_from_prefix(&buf.t[..]).is_none());
4558+
assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_none());
4559+
assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
4560+
assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
4561+
assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_none());
4562+
assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_none());
4563+
assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_none());
4564+
assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_none());
4565+
4566+
// Fail because the alignment is insufficient.
4567+
let mut buf = Align::<[u8; 13], AU64>::default();
4568+
assert!(AU64::ref_from(&buf.t[1..]).is_none());
4569+
assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
4570+
assert!(AU64::ref_from(&buf.t[1..]).is_none());
4571+
assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
4572+
assert!(AU64::ref_from_prefix(&buf.t[1..]).is_none());
4573+
assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_none());
4574+
assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
4575+
assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
4576+
}
4577+
44284578
#[test]
44294579
#[allow(clippy::cognitive_complexity)]
44304580
fn test_new_error() {

0 commit comments

Comments
 (0)