Skip to content

Commit 1260132

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 e2ae4f8 commit 1260132

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
@@ -1009,6 +1009,94 @@ pub unsafe trait FromBytes: FromZeroes {
10091009
where
10101010
Self: Sized;
10111011

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

10241111
/// Reads a copy of `Self` from the prefix of `bytes`.
@@ -1031,8 +1118,8 @@ pub unsafe trait FromBytes: FromZeroes {
10311118
where
10321119
Self: Sized,
10331120
{
1034-
let (r, _suffix) = Ref::<_, Unalign<Self>>::new_unaligned_from_prefix(bytes)?;
1035-
Some(r.read().into_inner())
1121+
Ref::<_, Unalign<Self>>::new_unaligned_from_prefix(bytes)
1122+
.map(|(r, _)| r.read().into_inner())
10361123
}
10371124

10381125
/// Reads a copy of `Self` from the suffix of `bytes`.
@@ -1045,8 +1132,8 @@ pub unsafe trait FromBytes: FromZeroes {
10451132
where
10461133
Self: Sized,
10471134
{
1048-
let (_prefix, r) = Ref::<_, Unalign<Self>>::new_unaligned_from_suffix(bytes)?;
1049-
Some(r.read().into_inner())
1135+
Ref::<_, Unalign<Self>>::new_unaligned_from_suffix(bytes)
1136+
.map(|(_, r)| r.read().into_inner())
10501137
}
10511138
}
10521139

@@ -4453,6 +4540,69 @@ mod tests {
44534540
}
44544541
}
44554542

4543+
#[test]
4544+
fn test_ref_from_mut_from() {
4545+
// Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` success cases
4546+
// Exhaustive coverage for these methods is covered by the `Ref` tests above,
4547+
// which these helper methods defer to.
4548+
4549+
let mut buf =
4550+
Align::<[u8; 16], AU64>::new([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
4551+
4552+
assert_eq!(
4553+
AU64::ref_from(&buf.t[8..]).unwrap().0.to_ne_bytes(),
4554+
[8, 9, 10, 11, 12, 13, 14, 15]
4555+
);
4556+
let suffix = AU64::mut_from(&mut buf.t[8..]).unwrap();
4557+
suffix.0 = 0x0101010101010101;
4558+
assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]);
4559+
let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap();
4560+
suffix.0 = 0x0202020202020202;
4561+
<[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42;
4562+
assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]);
4563+
<[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30;
4564+
assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]);
4565+
}
4566+
4567+
#[test]
4568+
fn test_ref_from_mut_from_error() {
4569+
// Test `FromBytes::{ref_from, mut_from}{,_prefix,_suffix}` error cases.
4570+
4571+
// Fail because the buffer is too large.
4572+
let mut buf = Align::<[u8; 16], AU64>::default();
4573+
// `buf.t` should be aligned to 8, so only the length check should fail.
4574+
assert!(AU64::ref_from(&buf.t[..]).is_none());
4575+
assert!(AU64::mut_from(&mut buf.t[..]).is_none());
4576+
assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
4577+
assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
4578+
4579+
// Fail because the buffer is too small.
4580+
let mut buf = Align::<[u8; 4], AU64>::default();
4581+
assert!(AU64::ref_from(&buf.t[..]).is_none());
4582+
assert!(AU64::mut_from(&mut buf.t[..]).is_none());
4583+
assert!(<[u8; 8]>::ref_from(&buf.t[..]).is_none());
4584+
assert!(<[u8; 8]>::mut_from(&mut buf.t[..]).is_none());
4585+
assert!(AU64::ref_from_prefix(&buf.t[..]).is_none());
4586+
assert!(AU64::mut_from_prefix(&mut buf.t[..]).is_none());
4587+
assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
4588+
assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
4589+
assert!(<[u8; 8]>::ref_from_prefix(&buf.t[..]).is_none());
4590+
assert!(<[u8; 8]>::mut_from_prefix(&mut buf.t[..]).is_none());
4591+
assert!(<[u8; 8]>::ref_from_suffix(&buf.t[..]).is_none());
4592+
assert!(<[u8; 8]>::mut_from_suffix(&mut buf.t[..]).is_none());
4593+
4594+
// Fail because the alignment is insufficient.
4595+
let mut buf = Align::<[u8; 13], AU64>::default();
4596+
assert!(AU64::ref_from(&buf.t[1..]).is_none());
4597+
assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
4598+
assert!(AU64::ref_from(&buf.t[1..]).is_none());
4599+
assert!(AU64::mut_from(&mut buf.t[1..]).is_none());
4600+
assert!(AU64::ref_from_prefix(&buf.t[1..]).is_none());
4601+
assert!(AU64::mut_from_prefix(&mut buf.t[1..]).is_none());
4602+
assert!(AU64::ref_from_suffix(&buf.t[..]).is_none());
4603+
assert!(AU64::mut_from_suffix(&mut buf.t[..]).is_none());
4604+
}
4605+
44564606
#[test]
44574607
#[allow(clippy::cognitive_complexity)]
44584608
fn test_new_error() {

0 commit comments

Comments
 (0)