@@ -173,7 +173,7 @@ use core::{
173
173
fmt:: { self , Debug , Display , Formatter } ,
174
174
hash:: { Hash , Hasher } ,
175
175
marker:: PhantomData ,
176
- mem:: { self , ManuallyDrop , MaybeUninit } ,
176
+ mem:: { self , ManuallyDrop } ,
177
177
num:: {
178
178
NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
179
179
NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -1004,17 +1004,16 @@ safety_comment! {
1004
1004
/// - `Unaligned`: `MaybeUninit<T>` is guaranteed by its documentation [1]
1005
1005
/// to have the same alignment as `T`.
1006
1006
///
1007
- /// [1]
1008
- /// https://doc.rust-lang.org/nightly/core/mem/union.MaybeUninit.html#layout-1
1007
+ /// [1] https://doc.rust-lang.org/nightly/core/mem/union.MaybeUninit.html#layout-1
1009
1008
///
1010
1009
/// TODO(https://github.com/google/zerocopy/issues/251): If we split
1011
1010
/// `FromBytes` and `RefFromBytes`, or if we introduce a separate
1012
1011
/// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
1013
1012
/// and `FromBytes`.
1014
- unsafe_impl!( T : FromZeroes => FromZeroes for MaybeUninit <T >) ;
1015
- unsafe_impl!( T : FromBytes => FromBytes for MaybeUninit <T >) ;
1016
- unsafe_impl!( T : Unaligned => Unaligned for MaybeUninit <T >) ;
1017
- assert_unaligned!( MaybeUninit <( ) >, MaybeUninit <u8 >) ;
1013
+ unsafe_impl!( T : FromZeroes => FromZeroes for mem :: MaybeUninit <T >) ;
1014
+ unsafe_impl!( T : FromBytes => FromBytes for mem :: MaybeUninit <T >) ;
1015
+ unsafe_impl!( T : Unaligned => Unaligned for mem :: MaybeUninit <T >) ;
1016
+ assert_unaligned!( mem :: MaybeUninit <( ) >, mem :: MaybeUninit <u8 >) ;
1018
1017
}
1019
1018
safety_comment ! {
1020
1019
/// SAFETY:
@@ -1201,6 +1200,279 @@ mod simd {
1201
1200
simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
1202
1201
}
1203
1202
1203
+ /// An alternative to the standard library's [`MaybeUninit`] that supports
1204
+ /// unsized types.
1205
+ ///
1206
+ /// `MaybeUninit<T>` is identical to the standard library's `MaybeUninit` type
1207
+ /// with the exception that it supports wrapping unsized types. Namely,
1208
+ /// `MaybeUninit<T>` has the same layout as `T`, but it has no bit validity
1209
+ /// constraints - any byte of a `MaybeUninit<T>` may have any value, including
1210
+ /// uninitialized.
1211
+ ///
1212
+ /// [`MaybeUninit`]: core::mem::MaybeUninit
1213
+ #[ derive( Copy , Clone ) ]
1214
+ #[ repr( transparent) ]
1215
+ pub struct MaybeUninit < T : AsMaybeUninit + ?Sized > {
1216
+ inner : T :: MaybeUninit ,
1217
+ }
1218
+
1219
+ impl < T : AsMaybeUninit + ?Sized > Debug for MaybeUninit < T > {
1220
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> fmt:: Result {
1221
+ f. pad ( core:: any:: type_name :: < Self > ( ) )
1222
+ }
1223
+ }
1224
+
1225
+ impl < T : AsMaybeUninit + ?Sized > MaybeUninit < T > {
1226
+ /// Gets a shared reference to the contained value.
1227
+ ///
1228
+ /// # Safety
1229
+ ///
1230
+ /// Calling this when the content is not yet fully initialized causes
1231
+ /// undefined behavior. It is up to the caller to guarantee that `self` is
1232
+ /// really in an initialized state.
1233
+ pub unsafe fn assume_init_ref ( & self ) -> & T {
1234
+ let ptr = T :: raw_from_maybe_uninit ( & self . inner ) ;
1235
+ // SAFETY: The caller has promised that `self` contains an initialized
1236
+ // `T`. Since `Self` is `repr(transparent)`, it has the same layout as
1237
+ // `T::MaybeUninit`, which in turn is guaranteed (by safety invariant)
1238
+ // to have the same layout as `T`. Thus, it is sound to treat `ptr` as
1239
+ // pointing to a valid `T` of the correct size and alignment.
1240
+ unsafe { & * ptr }
1241
+ }
1242
+
1243
+ /// Gets a mutable reference to the contained value.
1244
+ ///
1245
+ /// # Safety
1246
+ ///
1247
+ /// Calling this when the content is not yet fully initialized causes
1248
+ /// undefined behavior. It is up to the caller to guarantee that `self` is
1249
+ /// really in an initialized state.
1250
+ pub unsafe fn assume_init_mut ( & mut self ) -> & mut T {
1251
+ let ptr = T :: raw_mut_from_maybe_uninit ( & mut self . inner ) ;
1252
+ // SAFETY: The caller has promised that `self` contains an initialized
1253
+ // `T`. Since `Self` is `repr(transparent)`, it has the same layout as
1254
+ // `T::MaybeUninit`, which in turn is guaranteed (by safety invariant)
1255
+ // to have the same layout as `T`. Thus, it is sound to treat `ptr` as
1256
+ // pointing to a valid `T` of the correct size and alignment.
1257
+ unsafe { & mut * ptr }
1258
+ }
1259
+ }
1260
+
1261
+ impl < T : Sized > MaybeUninit < T > {
1262
+ /// Creates a new `MaybeUninit<T>` in an uninitialized state.
1263
+ pub const fn uninit ( ) -> MaybeUninit < T > {
1264
+ MaybeUninit { inner : mem:: MaybeUninit :: uninit ( ) }
1265
+ }
1266
+
1267
+ /// Extracts the value from the `MaybeUninit<T>` container.
1268
+ ///
1269
+ /// # Safety
1270
+ ///
1271
+ /// `assume_init` has the same safety requirements and guarantees as the
1272
+ /// standard library's [`MaybeUninit::assume_init`] method.
1273
+ ///
1274
+ /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
1275
+ pub const unsafe fn assume_init ( self ) -> T {
1276
+ // SAFETY: The caller has promised to uphold the safety invariants of
1277
+ // the exact function we're calling here. Since, for `T: Sized`,
1278
+ // `MaybeUninit<T>` is a `repr(transparent)` wrapper around
1279
+ // `mem::MaybeUninit<T>`, it is sound to treat `Self` as equivalent to a
1280
+ // `mem::MaybeUninit<T>` for the purposes of
1281
+ // `mem::MaybeUninit::assume_init`'s safety invariants.
1282
+ unsafe { self . inner . assume_init ( ) }
1283
+ }
1284
+ }
1285
+
1286
+ /// A type which can be wrapped in [`MaybeUninit`].
1287
+ ///
1288
+ /// # Safety
1289
+ ///
1290
+ /// The safety invariants on the associated `MaybeUninit` type and on all
1291
+ /// methods must be upheld.
1292
+ pub unsafe trait AsMaybeUninit {
1293
+ /// A type which has the same layout as `Self`, but which has no validity
1294
+ /// constraints.
1295
+ ///
1296
+ /// Roughly speaking, this type is equivalent to what the standard library's
1297
+ /// [`MaybeUninit<Self>`] would be if it supported unsized types.
1298
+ ///
1299
+ /// # Safety
1300
+ ///
1301
+ /// For `T: AsMaybeUninit`, the following must hold:
1302
+ /// - Given `m: T::MaybeUninit`, it is sound to write any byte value,
1303
+ /// including an uninitialized byte, at any byte offset in `m`
1304
+ /// - `T` and `T::MaybeUninit` have the same alignment requirement
1305
+ /// - It is valid to use an `as` cast to convert a `t: *const T` to a `m:
1306
+ /// *const T::MaybeUninit` and vice-versa (and likewise for `*mut T`/`*mut
1307
+ /// T::MaybeUninit`). Regardless of which direction the conversion was
1308
+ /// performed, the sizes of the pointers' referents are always equal (in
1309
+ /// terms of an API which is not yet stable, `size_of_val_raw(t) ==
1310
+ /// size_of_val_raw(m)`).
1311
+ /// - `T::MaybeUninit` contains [`UnsafeCell`]s at exactly the same byte
1312
+ /// ranges that `T` does.
1313
+ ///
1314
+ /// [`MaybeUninit<Self>`]: core::mem::MaybeUninit
1315
+ /// [`UnsafeCell`]: core::cell::UnsafeCell
1316
+ type MaybeUninit : ?Sized ;
1317
+
1318
+ /// Converts a const pointer at the type level.
1319
+ ///
1320
+ /// # Safety
1321
+ ///
1322
+ /// Callers may assume that the memory region addressed by the return value
1323
+ /// is the same as that addressed by the argument, and that both the return
1324
+ /// value and the argument have the same provenance.
1325
+ fn raw_from_maybe_uninit ( maybe_uninit : * const Self :: MaybeUninit ) -> * const Self ;
1326
+
1327
+ /// Converts a mut pointer at the type level.
1328
+ ///
1329
+ /// # Safety
1330
+ ///
1331
+ /// Callers may assume that the memory region addressed by the return value
1332
+ /// is the same as that addressed by the argument, and that both the return
1333
+ /// value and the argument have the same provenance.
1334
+ fn raw_mut_from_maybe_uninit ( maybe_uninit : * mut Self :: MaybeUninit ) -> * mut Self ;
1335
+ }
1336
+
1337
+ // SAFETY: See inline safety comments.
1338
+ unsafe impl < T : Sized > AsMaybeUninit for T {
1339
+ // SAFETY:
1340
+ // - `MaybeUninit` has no validity requirements, so it is sound to write any
1341
+ // byte value, including an uninitialized byte, at any offset.
1342
+ // - `MaybeUninit<T>` has the same layout as `T`, so they have the same
1343
+ // alignment requirement. For the same reason, their sizes are equal.
1344
+ // - Since their sizes are equal, raw pointers to both types are thin
1345
+ // pointers, and thus can be converted using as casts. For the same
1346
+ // reason, the sizes of these pointers' referents are always equal.
1347
+ // - `MaybeUninit<T>` has the same field offsets as `T`, and so it contains
1348
+ // `UnsafeCell`s at exactly the same byte ranges as `T`.
1349
+ type MaybeUninit = mem:: MaybeUninit < T > ;
1350
+
1351
+ // SAFETY: `.cast` preserves pointer address and provenance.
1352
+ fn raw_from_maybe_uninit ( maybe_uninit : * const mem:: MaybeUninit < T > ) -> * const T {
1353
+ maybe_uninit. cast :: < T > ( )
1354
+ }
1355
+
1356
+ // SAFETY: `.cast` preserves pointer address and provenance.
1357
+ fn raw_mut_from_maybe_uninit ( maybe_uninit : * mut mem:: MaybeUninit < T > ) -> * mut T {
1358
+ maybe_uninit. cast :: < T > ( )
1359
+ }
1360
+ }
1361
+
1362
+ // SAFETY: See inline safety comments.
1363
+ unsafe impl < T : Sized > AsMaybeUninit for [ T ] {
1364
+ // SAFETY:
1365
+ // - `MaybeUninit` has no bit validity requirements and `[U]` has the same
1366
+ // bit validity requirements as `U`, so `[MaybeUninit<T>]` has no bit
1367
+ // validity requirements. Thus, it is sound to write any byte value,
1368
+ // including an uninitialized byte, at any byte offset.
1369
+ // - Since `MaybeUninit<T>` has the same layout as `T`, and `[U]` has the
1370
+ // same alignment as `U`, `[MaybeUninit<T>]` has the same alignment as
1371
+ // `[T]`.
1372
+ // - `[T]` and `[MaybeUninit<T>]` are both slice types, and so pointers can
1373
+ // be converted using an `as` cast. Since `T` and `MaybeUninit<T>` have
1374
+ // the same size, and since such a cast preserves the number of elements
1375
+ // in the slice, the referent slices themselves will have the same size.
1376
+ // - `MaybeUninit<T>` has the same field offsets as `[T]`, and so it
1377
+ // contains `UnsafeCell`s at exactly the same byte ranges as `[T]`.
1378
+ type MaybeUninit = [ mem:: MaybeUninit < T > ] ;
1379
+
1380
+ // SAFETY: `as` preserves pointer address and provenance.
1381
+ #[ allow( clippy:: as_conversions) ]
1382
+ fn raw_from_maybe_uninit ( maybe_uninit : * const [ mem:: MaybeUninit < T > ] ) -> * const [ T ] {
1383
+ maybe_uninit as * const [ T ]
1384
+ }
1385
+
1386
+ // SAFETY: `as` preserves pointer address and provenance.
1387
+ #[ allow( clippy:: as_conversions) ]
1388
+ fn raw_mut_from_maybe_uninit ( maybe_uninit : * mut [ mem:: MaybeUninit < T > ] ) -> * mut [ T ] {
1389
+ maybe_uninit as * mut [ T ]
1390
+ }
1391
+ }
1392
+
1393
+ // SAFETY: See inline safety comments.
1394
+ unsafe impl AsMaybeUninit for str {
1395
+ // SAFETY: `str` has the same layout as `[u8]`. Thus, the same safety
1396
+ // argument for `<[u8] as AsMaybeUninit>::MaybeUninit` applies here.
1397
+ type MaybeUninit = <[ u8 ] as AsMaybeUninit >:: MaybeUninit ;
1398
+
1399
+ // SAFETY: `as` preserves pointer address and provenance.
1400
+ #[ allow( clippy:: as_conversions) ]
1401
+ fn raw_from_maybe_uninit (
1402
+ maybe_uninit : * const <[ u8 ] as AsMaybeUninit >:: MaybeUninit ,
1403
+ ) -> * const str {
1404
+ maybe_uninit as * const str
1405
+ }
1406
+
1407
+ // SAFETY: `as` preserves pointer address and provenance.
1408
+ #[ allow( clippy:: as_conversions) ]
1409
+ fn raw_mut_from_maybe_uninit (
1410
+ maybe_uninit : * mut <[ u8 ] as AsMaybeUninit >:: MaybeUninit ,
1411
+ ) -> * mut str {
1412
+ maybe_uninit as * mut str
1413
+ }
1414
+ }
1415
+
1416
+ // SAFETY: See inline safety comments.
1417
+ unsafe impl < T : Sized > AsMaybeUninit for MaybeUninit < [ T ] > {
1418
+ // SAFETY: `MaybeUninit<[T]>` is a `repr(transparent)` wrapper around
1419
+ // `[T::MaybeUninit]`. Thus:
1420
+ // - Given `m: Self::MaybeUninit = [T::MaybeUninit]`, it is sound to write
1421
+ // any byte value, including an uninitialized byte, at any byte offset in
1422
+ // `m` because that is already required of `T::MaybeUninit`, and thus of
1423
+ // [`T::MaybeUninit`]
1424
+ // - `Self` and `[T::MaybeUninit]` have the same representation, and so:
1425
+ // - Alignments are equal
1426
+ // - Pointer casts are valid, and sizes of referents of both pointer types
1427
+ // are equal.
1428
+ // - `Self::MaybeUninit = [T::MaybeUninit]` contains `UnsafeCell`s at
1429
+ // exactly the same byte ranges that `Self` does because `Self` has the
1430
+ // same bit validity as `[T::MaybeUninit]`.
1431
+ type MaybeUninit = [ <T as AsMaybeUninit >:: MaybeUninit ] ;
1432
+
1433
+ // SAFETY: `as` preserves pointer address and provenance.
1434
+ #[ allow( clippy:: as_conversions) ]
1435
+ fn raw_from_maybe_uninit (
1436
+ maybe_uninit : * const [ <T as AsMaybeUninit >:: MaybeUninit ] ,
1437
+ ) -> * const MaybeUninit < [ T ] > {
1438
+ maybe_uninit as * const MaybeUninit < [ T ] >
1439
+ }
1440
+
1441
+ // SAFETY: `as` preserves pointer address and provenance.
1442
+ #[ allow( clippy:: as_conversions) ]
1443
+ fn raw_mut_from_maybe_uninit (
1444
+ maybe_uninit : * mut [ <T as AsMaybeUninit >:: MaybeUninit ] ,
1445
+ ) -> * mut MaybeUninit < [ T ] > {
1446
+ maybe_uninit as * mut MaybeUninit < [ T ] >
1447
+ }
1448
+ }
1449
+
1450
+ safety_comment ! {
1451
+ // `MaybeUninit<T>` is `FromZeroes` and `FromBytes`, but never `AsBytes`
1452
+ // since it may contain uninitialized bytes.
1453
+ //
1454
+ /// SAFETY:
1455
+ /// - `FromZeroes`, `FromBytes`: `MaybeUninit<T>` has no restrictions on its
1456
+ /// contents. Unfortunately, in addition to bit validity, `FromZeroes` and
1457
+ /// `FromBytes` also require that implementers contain no `UnsafeCell`s.
1458
+ /// Thus, we require `T: FromZeroes` and `T: FromBytes` in order to ensure
1459
+ /// that `T` - and thus `MaybeUninit<T>` - contains to `UnsafeCell`s.
1460
+ /// Thus, requiring that `T` implement each of these traits is sufficient
1461
+ /// - `Unaligned`: `MaybeUninit<T>` is guaranteed by its documentation [1]
1462
+ /// to have the same alignment as `T`.
1463
+ ///
1464
+ /// [1] https://doc.rust-lang.org/nightly/core/mem/union.MaybeUninit.html#layout-1
1465
+ ///
1466
+ /// TODO(https://github.com/google/zerocopy/issues/251): If we split
1467
+ /// `FromBytes` and `RefFromBytes`, or if we introduce a separate
1468
+ /// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
1469
+ /// and `FromBytes`.
1470
+ unsafe_impl!( T : ?Sized + AsMaybeUninit + FromZeroes => FromZeroes for MaybeUninit <T >) ;
1471
+ unsafe_impl!( T : ?Sized + AsMaybeUninit + FromBytes => FromBytes for MaybeUninit <T >) ;
1472
+ unsafe_impl!( T : ?Sized + AsMaybeUninit + Unaligned => Unaligned for MaybeUninit <T >) ;
1473
+ assert_unaligned!( mem:: MaybeUninit <( ) >, MaybeUninit <u8 >) ;
1474
+ }
1475
+
1204
1476
/// A type with no alignment requirement.
1205
1477
///
1206
1478
/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign<T>`
@@ -4068,8 +4340,15 @@ mod tests {
4068
4340
assert_impls ! ( ManuallyDrop <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4069
4341
assert_impls ! ( ManuallyDrop <[ NotZerocopy ] >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4070
4342
4343
+ assert_impls ! ( mem:: MaybeUninit <u8 >: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4344
+ assert_impls ! ( mem:: MaybeUninit <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4345
+
4071
4346
assert_impls ! ( MaybeUninit <u8 >: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4347
+ assert_impls ! ( MaybeUninit <MaybeUninit <u8 >>: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4348
+ assert_impls ! ( MaybeUninit <[ u8 ] >: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4349
+ assert_impls ! ( MaybeUninit <MaybeUninit <[ u8 ] >>: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4072
4350
assert_impls ! ( MaybeUninit <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4351
+ assert_impls ! ( MaybeUninit <MaybeUninit <NotZerocopy >>: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4073
4352
4074
4353
assert_impls ! ( Wrapping <u8 >: FromZeroes , FromBytes , AsBytes , Unaligned ) ;
4075
4354
assert_impls ! ( Wrapping <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
0 commit comments