@@ -350,13 +350,15 @@ mod macros;
350
350
#[ doc( hidden) ]
351
351
pub mod pointer;
352
352
mod r#ref;
353
+ mod split_at;
353
354
// TODO(#252): If we make this pub, come up with a better name.
354
355
mod wrappers;
355
356
356
357
pub use crate :: byte_slice:: * ;
357
358
pub use crate :: byteorder:: * ;
358
359
pub use crate :: error:: * ;
359
360
pub use crate :: r#ref:: * ;
361
+ pub use crate :: split_at:: SplitAt ;
360
362
pub use crate :: wrappers:: * ;
361
363
362
364
use core:: {
@@ -1048,348 +1050,6 @@ safety_comment! {
1048
1050
unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T :: MaybeUninit ) ] MaybeUninit <T >) ;
1049
1051
}
1050
1052
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
-
1393
1053
/// Analyzes whether a type is [`FromZeros`].
1394
1054
///
1395
1055
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -5941,7 +5601,7 @@ pub use zerocopy_derive::ByteHash;
5941
5601
#[ cfg_attr( doc_cfg, doc( cfg( feature = "derive" ) ) ) ]
5942
5602
pub use zerocopy_derive:: ByteEq ;
5943
5603
5944
- /// Derives [`SplitAt`].
5604
+ /// Implements [`SplitAt`].
5945
5605
///
5946
5606
/// This derive can be applied to structs; e.g.:
5947
5607
///
0 commit comments