@@ -350,13 +350,15 @@ mod macros;
350350#[ doc( hidden) ]
351351pub mod pointer;
352352mod r#ref;
353+ mod split_at;
353354// TODO(#252): If we make this pub, come up with a better name.
354355mod wrappers;
355356
356357pub use crate :: byte_slice:: * ;
357358pub use crate :: byteorder:: * ;
358359pub use crate :: error:: * ;
359360pub use crate :: r#ref:: * ;
361+ pub use crate :: split_at:: SplitAt ;
360362pub use crate :: wrappers:: * ;
361363
362364use 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" ) ) ) ]
59425602pub 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