Skip to content

Commit 7fdec6f

Browse files
authored
Move split_at module to its own file (#2470)
gherrit-pr-id: I797ab16976013a86e8336913109cd4663e021f54
1 parent 3b4cbd6 commit 7fdec6f

File tree

5 files changed

+350
-352
lines changed

5 files changed

+350
-352
lines changed

src/lib.rs

Lines changed: 3 additions & 343 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,15 @@ mod macros;
350350
#[doc(hidden)]
351351
pub mod pointer;
352352
mod r#ref;
353+
mod split_at;
353354
// TODO(#252): If we make this pub, come up with a better name.
354355
mod wrappers;
355356

356357
pub use crate::byte_slice::*;
357358
pub use crate::byteorder::*;
358359
pub use crate::error::*;
359360
pub use crate::r#ref::*;
361+
pub use crate::split_at::SplitAt;
360362
pub use crate::wrappers::*;
361363

362364
use core::{
@@ -1048,348 +1050,6 @@ safety_comment! {
10481050
unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T::MaybeUninit)] MaybeUninit<T>);
10491051
}
10501052

1051-
mod split_at {
1052-
use super::*;
1053-
#[cfg(doc)]
1054-
use invariant::Exclusive;
1055-
1056-
/// Types that can be split in two.
1057-
///
1058-
/// # Implementation
1059-
///
1060-
/// **Do not implement this trait yourself!** Instead, use
1061-
/// [`#[derive(SplitAt)]`][derive]; e.g.:
1062-
///
1063-
/// ```
1064-
/// # use zerocopy_derive::{SplitAt, KnownLayout};
1065-
/// #[derive(SplitAt, KnownLayout)]
1066-
/// #[repr(C)]
1067-
/// struct MyStruct<T: ?Sized> {
1068-
/// # /*
1069-
/// ...,
1070-
/// # */
1071-
/// // `SplitAt` types must have at least one field.
1072-
/// field: T,
1073-
/// }
1074-
/// ```
1075-
///
1076-
/// This derive performs a sophisticated, compile-time safety analysis to
1077-
/// determine whether a type is `SplitAt`.
1078-
///
1079-
/// # Safety
1080-
///
1081-
/// This trait does not convey any safety guarantees to code outside this crate.
1082-
///
1083-
/// You must not rely on the `#[doc(hidden)]` internals of `SplitAt`. Future
1084-
/// releases of zerocopy may make backwards-breaking changes to these items,
1085-
/// including changes that only affect soundness, which may cause code which
1086-
/// uses those items to silently become unsound.
1087-
///
1088-
#[cfg_attr(feature = "derive", doc = "[derive]: zerocopy_derive::SplitAt")]
1089-
#[cfg_attr(
1090-
not(feature = "derive"),
1091-
doc = concat!("[derive]: https://docs.rs/zerocopy/", env!("CARGO_PKG_VERSION"), "/zerocopy/derive.SplitAt.html"),
1092-
)]
1093-
#[cfg_attr(
1094-
zerocopy_diagnostic_on_unimplemented_1_78_0,
1095-
diagnostic::on_unimplemented(note = "Consider adding `#[derive(SplitAt)]` to `{Self}`")
1096-
)]
1097-
// # Safety
1098-
//
1099-
// The trailing slice is well-aligned for its element type.
1100-
pub unsafe trait SplitAt: KnownLayout<PointerMetadata = usize> {
1101-
/// The element type of the trailing slice.
1102-
type Elem;
1103-
1104-
#[doc(hidden)]
1105-
fn only_derive_is_allowed_to_implement_this_trait()
1106-
where
1107-
Self: Sized;
1108-
1109-
/// Unsafely splits `self` in two.
1110-
///
1111-
/// # Safety
1112-
///
1113-
/// The caller promises that `l_len` is not greater than the length of
1114-
/// `self`'s trailing slice.
1115-
#[inline]
1116-
#[must_use]
1117-
unsafe fn split_at_unchecked(&self, l_len: usize) -> (&Self, &[Self::Elem])
1118-
where
1119-
Self: Immutable,
1120-
{
1121-
// SAFETY: `&self` is an instance of `&Self` for which the caller has
1122-
// promised that `l_len` is not greater than the length of `self`'s
1123-
// trailing slice.
1124-
let l_len = unsafe { MetadataOf::new_unchecked(l_len) };
1125-
let ptr = Ptr::from_ref(self);
1126-
// SAFETY:
1127-
// 0. The caller promises that `l_len` is not greater than the length of
1128-
// `self`'s trailing slice.
1129-
// 1. `ptr`'s aliasing is `Shared` and does not permit interior
1130-
// mutation because `Self: Immutable`.
1131-
let (left, right) = unsafe { ptr_split_at_unchecked(ptr, l_len) };
1132-
(left.as_ref(), right.as_ref())
1133-
}
1134-
1135-
/// Attempts to split `self` in two.
1136-
///
1137-
/// Returns `None` if `l_len` is greater than the length of `self`'s
1138-
/// trailing slice.
1139-
///
1140-
/// # Examples
1141-
///
1142-
/// ```
1143-
/// use zerocopy::{SplitAt, FromBytes};
1144-
/// # use zerocopy_derive::*;
1145-
///
1146-
/// #[derive(SplitAt, FromBytes, KnownLayout, Immutable)]
1147-
/// #[repr(C)]
1148-
/// struct Packet {
1149-
/// length: u8,
1150-
/// body: [u8],
1151-
/// }
1152-
///
1153-
/// // These bytes encode a `Packet`.
1154-
/// let bytes = &[4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
1155-
///
1156-
/// let packet = Packet::ref_from_bytes(bytes).unwrap();
1157-
///
1158-
/// assert_eq!(packet.length, 4);
1159-
/// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
1160-
///
1161-
/// let (packet, rest) = packet.split_at(packet.length as usize).unwrap();
1162-
/// assert_eq!(packet.length, 4);
1163-
/// assert_eq!(packet.body, [1, 2, 3, 4]);
1164-
/// assert_eq!(rest, [5, 6, 7, 8, 9]);
1165-
/// ```
1166-
#[inline]
1167-
#[must_use = "has no side effects"]
1168-
fn split_at(&self, l_len: usize) -> Option<(&Self, &[Self::Elem])>
1169-
where
1170-
Self: Immutable,
1171-
{
1172-
if l_len <= Ptr::from_ref(self).len() {
1173-
// SAFETY: We have checked that `l_len` is not greater than the
1174-
// length of `self`'s trailing slice.
1175-
Some(unsafe { self.split_at_unchecked(l_len) })
1176-
} else {
1177-
None
1178-
}
1179-
}
1180-
1181-
/// Unsafely splits `self` in two.
1182-
///
1183-
/// # Safety
1184-
///
1185-
/// The caller promises that:
1186-
/// 0. `l_len` is not greater than the length of `self`'s trailing slice.
1187-
/// 1. The trailing padding bytes of the left portion will not overlap
1188-
/// the right portion. For some dynamically sized types, the padding
1189-
/// that appears after the trailing slice field [is a dynamic
1190-
/// function of the trailing slice
1191-
/// length](KnownLayout#slice-dst-layout). Thus, for some types, this
1192-
/// condition is dependent on the value of `l_len`.
1193-
#[inline]
1194-
#[must_use]
1195-
unsafe fn split_at_mut_unchecked(
1196-
&mut self,
1197-
l_len: usize,
1198-
) -> (&mut Self, &mut [Self::Elem]) {
1199-
// SAFETY: `&mut self` is an instance of `&mut Self` for which the
1200-
// caller has promised that `l_len` is not greater than the length of
1201-
// `self`'s trailing slice.
1202-
let l_len = unsafe { MetadataOf::new_unchecked(l_len) };
1203-
let ptr = Ptr::from_mut(self);
1204-
// SAFETY:
1205-
// 0. The caller promises that `l_len` is not greater than the length of
1206-
// `self`'s trailing slice.
1207-
// 1. `ptr`'s aliasing is `Exclusive`; the caller promises that
1208-
// `l_len.padding_needed_for() == 0`.
1209-
let (left, right) = unsafe { ptr_split_at_unchecked(ptr, l_len) };
1210-
(left.as_mut(), right.as_mut())
1211-
}
1212-
1213-
/// Attempts to split `self` in two.
1214-
///
1215-
/// Returns `None` if `l_len` is greater than the length of `self`'s
1216-
/// trailing slice, or if the given `l_len` would result in [the trailing
1217-
/// padding](KnownLayout#slice-dst-layout) of the left portion overlapping
1218-
/// the right portion.
1219-
///
1220-
///
1221-
/// # Examples
1222-
///
1223-
/// ```
1224-
/// use zerocopy::{SplitAt, FromBytes};
1225-
/// # use zerocopy_derive::*;
1226-
///
1227-
/// #[derive(SplitAt, FromBytes, KnownLayout, Immutable, IntoBytes)]
1228-
/// #[repr(C)]
1229-
/// struct Packet<B: ?Sized> {
1230-
/// length: u8,
1231-
/// body: B,
1232-
/// }
1233-
///
1234-
/// // These bytes encode a `Packet`.
1235-
/// let mut bytes = &mut [4, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
1236-
///
1237-
/// let packet = Packet::<[u8]>::mut_from_bytes(bytes).unwrap();
1238-
///
1239-
/// assert_eq!(packet.length, 4);
1240-
/// assert_eq!(packet.body, [1, 2, 3, 4, 5, 6, 7, 8, 9]);
1241-
///
1242-
/// {
1243-
/// let (packet, rest) = packet.split_at_mut(packet.length as usize).unwrap();
1244-
/// assert_eq!(packet.length, 4);
1245-
/// assert_eq!(packet.body, [1, 2, 3, 4]);
1246-
/// assert_eq!(rest, [5, 6, 7, 8, 9]);
1247-
///
1248-
/// rest.fill(0);
1249-
/// }
1250-
///
1251-
/// assert_eq!(packet.length, 4);
1252-
/// assert_eq!(packet.body, [1, 2, 3, 4, 0, 0, 0, 0, 0]);
1253-
/// ```
1254-
#[inline]
1255-
fn split_at_mut(&mut self, l_len: usize) -> Option<(&mut Self, &mut [Self::Elem])> {
1256-
match MetadataOf::new_in_bounds(self, l_len) {
1257-
Some(l_len) if l_len.padding_needed_for() == 0 => {
1258-
// SAFETY: We have ensured both that:
1259-
// 0. `l_len <= self.len()` (by post-condition on
1260-
// `MetadataOf::new_in_bounds`)
1261-
// 1. `l_len.padding_needed_for() == 0` (by guard on match arm)
1262-
Some(unsafe { self.split_at_mut_unchecked(l_len.get()) })
1263-
}
1264-
_ => None,
1265-
}
1266-
}
1267-
}
1268-
1269-
// SAFETY: `[T]`'s trailing slice is `[T]`, which is trivially aligned.
1270-
unsafe impl<T> SplitAt for [T] {
1271-
type Elem = T;
1272-
1273-
#[inline]
1274-
#[allow(dead_code)]
1275-
fn only_derive_is_allowed_to_implement_this_trait()
1276-
where
1277-
Self: Sized,
1278-
{
1279-
}
1280-
}
1281-
1282-
/// Splits `T` in two.
1283-
///
1284-
/// # Safety
1285-
///
1286-
/// The caller promises that:
1287-
/// 0. `l_len.get()` is not greater than the length of `ptr`'s trailing
1288-
/// slice.
1289-
/// 1. if `I::Aliasing` is [`Exclusive`] or `T` permits interior mutation,
1290-
/// then `l_len.padding_needed_for() == 0`.
1291-
#[inline(always)]
1292-
unsafe fn ptr_split_at_unchecked<'a, T, I, R>(
1293-
ptr: Ptr<'a, T, I>,
1294-
l_len: MetadataOf<T>,
1295-
) -> (Ptr<'a, T, I>, Ptr<'a, [T::Elem], I>)
1296-
where
1297-
I: invariant::Invariants,
1298-
T: ?Sized + pointer::Read<I::Aliasing, R> + SplitAt,
1299-
{
1300-
let inner = ptr.as_inner();
1301-
1302-
// SAFETY: The caller promises that `l_len.get()` is not greater than
1303-
// the length of `self`'s trailing slice.
1304-
let (left, right) = unsafe { inner.split_at_unchecked(l_len) };
1305-
1306-
// Lemma 0: `left` and `right` conform to the aliasing invariant
1307-
// `I::Aliasing`. Proof: If `I::Aliasing` is `Exclusive` or `T` permits
1308-
// interior mutation, the caller promises that
1309-
// `l_len.padding_needed_for() == 0`. Consequently, by post-condition on
1310-
// `PtrInner::split_at_unchecked`, there is no trailing padding after
1311-
// `left`'s final element that would overlap into `right`. If
1312-
// `I::Aliasing` is shared and `T` forbids interior mutation, then
1313-
// overlap between their referents is permissible.
1314-
1315-
// SAFETY:
1316-
// 0. `left` conforms to the aliasing invariant of `I::Aliasing, by
1317-
// Lemma 0.
1318-
// 1. `left` conforms to the alignment invariant of `I::Alignment,
1319-
// because the referents of `left` and `Self` have the same address
1320-
// and type (and, thus, alignment requirement).
1321-
// 2. `left` conforms to the validity invariant of `I::Validity`,
1322-
// neither the type nor bytes of `left`'s referent have been changed.
1323-
let left = unsafe { Ptr::from_inner(left) };
1324-
1325-
// SAFETY:
1326-
// 0. `right` conforms to the aliasing invariant of `I::Aliasing, by
1327-
// Lemma 0.
1328-
// 1. `right` conforms to the alignment invariant of `I::Alignment,
1329-
// because if `ptr` with `I::Alignment = Aligned`, then by invariant
1330-
// on `T: SplitAt`, the trailing slice of `ptr` (from which `right`
1331-
// is derived) will also be well-aligned.
1332-
// 2. `right` conforms to the validity invariant of `I::Validity`,
1333-
// because `right: [T::Elem]` is derived from the trailing slice of
1334-
// `ptr`, which, by contract on `T: SplitAt::Elem`, has type
1335-
// `[T::Elem]`.
1336-
let right = unsafe { Ptr::from_inner(right) };
1337-
1338-
(left, right)
1339-
}
1340-
1341-
#[cfg(test)]
1342-
mod tests {
1343-
#[cfg(feature = "derive")]
1344-
#[test]
1345-
fn test_split_at() {
1346-
use crate::{FromBytes, Immutable, IntoBytes, KnownLayout, SplitAt};
1347-
1348-
#[derive(FromBytes, KnownLayout, SplitAt, IntoBytes, Immutable)]
1349-
#[repr(C)]
1350-
struct SliceDst<const OFFSET: usize> {
1351-
prefix: [u8; OFFSET],
1352-
trailing: [u8],
1353-
}
1354-
1355-
#[allow(clippy::as_conversions)]
1356-
fn test_split_at<const OFFSET: usize, const BUFFER_SIZE: usize>() {
1357-
// Test `split_at`
1358-
let n: usize = BUFFER_SIZE - OFFSET;
1359-
let arr = [1; BUFFER_SIZE];
1360-
let dst = SliceDst::<OFFSET>::ref_from_bytes(&arr[..]).unwrap();
1361-
for i in 0..=n {
1362-
let (l, r) = dst.split_at(i).unwrap();
1363-
let l_sum: u8 = l.trailing.iter().sum();
1364-
let r_sum: u8 = r.iter().sum();
1365-
assert_eq!(l_sum, i as u8);
1366-
assert_eq!(r_sum, (n - i) as u8);
1367-
assert_eq!(l_sum + r_sum, n as u8);
1368-
}
1369-
1370-
// Test `split_at_mut`
1371-
let n: usize = BUFFER_SIZE - OFFSET;
1372-
let mut arr = [1; BUFFER_SIZE];
1373-
let dst = SliceDst::<OFFSET>::mut_from_bytes(&mut arr[..]).unwrap();
1374-
for i in 0..=n {
1375-
let (l, r) = dst.split_at_mut(i).unwrap();
1376-
let l_sum: u8 = l.trailing.iter().sum();
1377-
let r_sum: u8 = r.iter().sum();
1378-
assert_eq!(l_sum, i as u8);
1379-
assert_eq!(r_sum, (n - i) as u8);
1380-
assert_eq!(l_sum + r_sum, n as u8);
1381-
}
1382-
}
1383-
1384-
test_split_at::<0, 16>();
1385-
test_split_at::<1, 17>();
1386-
test_split_at::<2, 18>();
1387-
}
1388-
}
1389-
}
1390-
1391-
pub use split_at::SplitAt;
1392-
13931053
/// Analyzes whether a type is [`FromZeros`].
13941054
///
13951055
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -5941,7 +5601,7 @@ pub use zerocopy_derive::ByteHash;
59415601
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
59425602
pub use zerocopy_derive::ByteEq;
59435603

5944-
/// Derives [`SplitAt`].
5604+
/// Implements [`SplitAt`].
59455605
///
59465606
/// This derive can be applied to structs; e.g.:
59475607
///

0 commit comments

Comments
 (0)