@@ -173,7 +173,7 @@ use core::{
173173 fmt:: { self , Debug , Display , Formatter } ,
174174 hash:: { Hash , Hasher } ,
175175 marker:: PhantomData ,
176- mem:: { self , ManuallyDrop , MaybeUninit } ,
176+ mem:: { self , ManuallyDrop } ,
177177 num:: {
178178 NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
179179 NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -1004,17 +1004,16 @@ safety_comment! {
10041004 /// - `Unaligned`: `MaybeUninit<T>` is guaranteed by its documentation [1]
10051005 /// to have the same alignment as `T`.
10061006 ///
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
10091008 ///
10101009 /// TODO(https://github.com/google/zerocopy/issues/251): If we split
10111010 /// `FromBytes` and `RefFromBytes`, or if we introduce a separate
10121011 /// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
10131012 /// 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 >) ;
10181017}
10191018safety_comment ! {
10201019 /// SAFETY:
@@ -1201,6 +1200,279 @@ mod simd {
12011200 simd_arch_mod ! ( arm, int8x4_t, uint8x4_t) ;
12021201}
12031202
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+
12041476/// A type with no alignment requirement.
12051477///
12061478/// An `Unalign` wraps a `T`, removing any alignment requirement. `Unalign<T>`
@@ -4068,8 +4340,15 @@ mod tests {
40684340 assert_impls ! ( ManuallyDrop <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
40694341 assert_impls ! ( ManuallyDrop <[ NotZerocopy ] >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
40704342
4343+ assert_impls ! ( mem:: MaybeUninit <u8 >: FromZeroes , FromBytes , Unaligned , !AsBytes ) ;
4344+ assert_impls ! ( mem:: MaybeUninit <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4345+
40714346 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 ) ;
40724350 assert_impls ! ( MaybeUninit <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
4351+ assert_impls ! ( MaybeUninit <MaybeUninit <NotZerocopy >>: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
40734352
40744353 assert_impls ! ( Wrapping <u8 >: FromZeroes , FromBytes , AsBytes , Unaligned ) ;
40754354 assert_impls ! ( Wrapping <NotZerocopy >: !FromZeroes , !FromBytes , !AsBytes , !Unaligned ) ;
0 commit comments