Skip to content

Commit 7460ab3

Browse files
committed
[WIP] Introduce TryFromBytes::Uninit
gherrit-pr-id: Geec83fc8d47be6b2e51a15b84a2735bbc909ce68
1 parent b0b7c9a commit 7460ab3

File tree

4 files changed

+161
-82
lines changed

4 files changed

+161
-82
lines changed

src/impls.rs

Lines changed: 126 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,14 @@ assert_unaligned!(bool);
108108
// The value false has the bit pattern 0x00 and the value true has the bit
109109
// pattern 0x01.
110110
const _: () = unsafe {
111-
unsafe_impl!(=> TryFromBytes for bool; |byte| {
112-
let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>();
113-
*byte.unaligned_as_ref() < 2
114-
})
111+
unsafe_impl!(=> TryFromBytes for bool;
112+
// FIXME(#2749): Justify this `Uninit`.
113+
type Uninit = crate::invariant::Uninit;
114+
|byte| {
115+
let byte = byte.transmute_with::<u8, invariant::Valid, CastSizedExact, BecauseImmutable>();
116+
*byte.unaligned_as_ref() < 2
117+
}
118+
)
115119
};
116120

117121
// SAFETY:
@@ -137,11 +141,15 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
137141
// `from_u32()` will return `None` if the input is not a valid value for a
138142
// `char`.
139143
const _: () = unsafe {
140-
unsafe_impl!(=> TryFromBytes for char; |c| {
141-
let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>();
142-
let c = c.read().into_inner();
143-
char::from_u32(c).is_some()
144-
});
144+
unsafe_impl!(=> TryFromBytes for char;
145+
// FIXME(#2749): Justify this `Uninit`.
146+
type Uninit = crate::invariant::Uninit;
147+
|c| {
148+
let c = c.transmute_with::<Unalign<u32>, invariant::Valid, CastSizedExact, BecauseImmutable>();
149+
let c = c.read().into_inner();
150+
char::from_u32(c).is_some()
151+
}
152+
);
145153
};
146154

147155
// SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`.
@@ -170,20 +178,28 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig
170178
//
171179
// Returns `Err` if the slice is not UTF-8.
172180
const _: () = unsafe {
173-
unsafe_impl!(=> TryFromBytes for str; |c| {
174-
let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>();
175-
let c = c.unaligned_as_ref();
176-
core::str::from_utf8(c).is_ok()
177-
})
181+
unsafe_impl!(=> TryFromBytes for str;
182+
// FIXME(#2749): Justify this `Uninit`.
183+
type Uninit = crate::invariant::Uninit;
184+
|c| {
185+
let c = c.transmute_with::<[u8], invariant::Valid, CastUnsized, BecauseImmutable>();
186+
let c = c.unaligned_as_ref();
187+
core::str::from_utf8(c).is_ok()
188+
}
189+
)
178190
};
179191

180192
macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
181193
($($nonzero:ident[$prim:ty]),*) => {
182194
$(
183-
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
184-
let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>();
185-
$nonzero::new(n.read().into_inner()).is_some()
186-
});
195+
unsafe_impl!(=> TryFromBytes for $nonzero;
196+
// FIXME(#2749): Justify this `Uninit`.
197+
type Uninit = crate::invariant::Uninit;
198+
|n| {
199+
let n = n.transmute_with::<Unalign<$prim>, invariant::Valid, CastSizedExact, BecauseImmutable>();
200+
$nonzero::new(n.read().into_inner()).is_some()
201+
}
202+
);
187203
)*
188204
}
189205
}
@@ -331,43 +347,63 @@ const _: () = unsafe {
331347
#[cfg(feature = "alloc")]
332348
unsafe_impl!(
333349
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
334-
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
350+
T => TryFromBytes for Option<Box<T>>;
351+
// FIXME(#2749): Justify this `Uninit`.
352+
type Uninit = crate::invariant::Uninit;
353+
|c| pointer::is_zeroed(c)
335354
);
336355
#[cfg(feature = "alloc")]
337356
unsafe_impl!(
338357
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
339358
T => FromZeros for Option<Box<T>>
340359
);
341360
unsafe_impl!(
342-
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c)
361+
T => TryFromBytes for Option<&'_ T>;
362+
// FIXME(#2749): Justify this `Uninit`.
363+
type Uninit = crate::invariant::Uninit;
364+
|c| pointer::is_zeroed(c)
343365
);
344366
unsafe_impl!(T => FromZeros for Option<&'_ T>);
345367
unsafe_impl!(
346-
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c)
368+
T => TryFromBytes for Option<&'_ mut T>;
369+
// FIXME(#2749): Justify this `Uninit`.
370+
type Uninit = crate::invariant::Uninit;
371+
|c| pointer::is_zeroed(c)
347372
);
348373
unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
349374
unsafe_impl!(
350-
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c)
375+
T => TryFromBytes for Option<NonNull<T>>;
376+
// FIXME(#2749): Justify this `Uninit`.
377+
type Uninit = crate::invariant::Uninit;
378+
|c| pointer::is_zeroed(c)
351379
);
352380
unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
353381
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
354382
unsafe_impl_for_power_set!(
355383
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
384+
// FIXME(#2749): Justify this `Uninit`.
385+
type Uninit = crate::invariant::Uninit;
356386
|c| pointer::is_zeroed(c)
357387
);
358388
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_fn!(...));
359389
unsafe_impl_for_power_set!(
360390
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_fn!(...);
391+
// FIXME(#2749): Justify this `Uninit`.
392+
type Uninit = crate::invariant::Uninit;
361393
|c| pointer::is_zeroed(c)
362394
);
363395
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
364396
unsafe_impl_for_power_set!(
365397
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
398+
// FIXME(#2749): Justify this `Uninit`.
399+
type Uninit = crate::invariant::Uninit;
366400
|c| pointer::is_zeroed(c)
367401
);
368402
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_extern_c_fn!(...));
369403
unsafe_impl_for_power_set!(
370404
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...);
405+
// FIXME(#2749): Justify this `Uninit`.
406+
type Uninit = crate::invariant::Uninit;
371407
|c| pointer::is_zeroed(c)
372408
);
373409
};
@@ -650,6 +686,7 @@ mod atomics {
650686
#[allow(clippy::multiple_unsafe_ops_per_block)]
651687
const _: () = unsafe {
652688
unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
689+
// FIXME(#2749): Justify this `Uninit`.
653690
unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
654691
unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
655692
unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
@@ -684,6 +721,7 @@ const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>) }
684721
// `MaybeUninit<T>` has no restrictions on its contents.
685722
#[allow(clippy::multiple_unsafe_ops_per_block)]
686723
const _: () = unsafe {
724+
// FIXME(#2749): Justify this `Uninit`.
687725
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
688726
unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
689727
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
@@ -856,6 +894,9 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
856894
{
857895
}
858896

897+
// FIXME(#2749): Justify this `Uninit`.
898+
type Uninit = crate::invariant::Uninit;
899+
859900
#[inline(always)]
860901
fn is_bit_valid<A>(candidate: Maybe<'_, Self, A>) -> bool
861902
where
@@ -889,48 +930,56 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
889930
#[allow(clippy::multiple_unsafe_ops_per_block)]
890931
const _: () = unsafe {
891932
unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]);
892-
unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c| {
893-
let c: Ptr<'_, [ReadOnly<T>; N], _> = c.cast::<_, crate::pointer::cast::CastSized, _>();
894-
let c: Ptr<'_, [ReadOnly<T>], _> = c.as_slice();
895-
let c: Ptr<'_, ReadOnly<[T]>, _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
896-
897-
// Note that this call may panic, but it would still be sound even if it
898-
// did. `is_bit_valid` does not promise that it will not panic (in fact,
899-
// it explicitly warns that it's a possibility), and we have not
900-
// violated any safety invariants that we must fix before returning.
901-
<[T] as TryFromBytes>::is_bit_valid(c)
902-
});
933+
unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N];
934+
// FIXME(#2749): Justify this `Uninit`.
935+
type Uninit = crate::invariant::Uninit;
936+
|c| {
937+
let c: Ptr<'_, [ReadOnly<T>; N], _> = c.cast::<_, crate::pointer::cast::CastSized, _>();
938+
let c: Ptr<'_, [ReadOnly<T>], _> = c.as_slice();
939+
let c: Ptr<'_, ReadOnly<[T]>, _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
940+
941+
// Note that this call may panic, but it would still be sound even if it
942+
// did. `is_bit_valid` does not promise that it will not panic (in fact,
943+
// it explicitly warns that it's a possibility), and we have not
944+
// violated any safety invariants that we must fix before returning.
945+
<[T] as TryFromBytes>::is_bit_valid(c)
946+
}
947+
);
903948
unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
904949
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
905950
unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
906951
unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
907952
assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
908953
unsafe_impl!(T: Immutable => Immutable for [T]);
909-
unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c| {
910-
let c: Ptr<'_, [ReadOnly<T>], _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
954+
unsafe_impl!(T: TryFromBytes => TryFromBytes for [T];
955+
// FIXME(#2749): Justify this `Uninit`.
956+
type Uninit = crate::invariant::Uninit;
957+
|c| {
958+
let c: Ptr<'_, [ReadOnly<T>], _> = c.cast::<_, crate::pointer::cast::CastUnsized, _>();
911959

912-
// SAFETY: Per the reference [1]:
913-
//
914-
// An array of `[T; N]` has a size of `size_of::<T>() * N` and the
915-
// same alignment of `T`. Arrays are laid out so that the zero-based
916-
// `nth` element of the array is offset from the start of the array by
917-
// `n * size_of::<T>()` bytes.
918-
//
919-
// ...
920-
//
921-
// Slices have the same layout as the section of the array they slice.
922-
//
923-
// In other words, the layout of a `[T] is a sequence of `T`s laid out
924-
// back-to-back with no bytes in between. If all elements in `candidate`
925-
// are `is_bit_valid`, so too is `candidate`.
926-
//
927-
// Note that any of the below calls may panic, but it would still be
928-
// sound even if it did. `is_bit_valid` does not promise that it will
929-
// not panic (in fact, it explicitly warns that it's a possibility), and
930-
// we have not violated any safety invariants that we must fix before
931-
// returning.
932-
c.iter().all(<T as TryFromBytes>::is_bit_valid)
933-
});
960+
// SAFETY: Per the reference [1]:
961+
//
962+
// An array of `[T; N]` has a size of `size_of::<T>() * N` and the
963+
// same alignment of `T`. Arrays are laid out so that the zero-based
964+
// `nth` element of the array is offset from the start of the array by
965+
// `n * size_of::<T>()` bytes.
966+
//
967+
// ...
968+
//
969+
// Slices have the same layout as the section of the array they slice.
970+
//
971+
// In other words, the layout of a `[T] is a sequence of `T`s laid out
972+
// back-to-back with no bytes in between. If all elements in `candidate`
973+
// are `is_bit_valid`, so too is `candidate`.
974+
//
975+
// Note that any of the below calls may panic, but it would still be
976+
// sound even if it did. `is_bit_valid` does not promise that it will
977+
// not panic (in fact, it explicitly warns that it's a possibility), and
978+
// we have not violated any safety invariants that we must fix before
979+
// returning.
980+
c.iter().all(<T as TryFromBytes>::is_bit_valid)
981+
}
982+
);
934983
unsafe_impl!(T: FromZeros => FromZeros for [T]);
935984
unsafe_impl!(T: FromBytes => FromBytes for [T]);
936985
unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
@@ -963,9 +1012,17 @@ const _: () = unsafe {
9631012
const _: () = unsafe {
9641013
unsafe_impl!(T: ?Sized => Immutable for *const T);
9651014
unsafe_impl!(T: ?Sized => Immutable for *mut T);
966-
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c));
1015+
unsafe_impl!(T => TryFromBytes for *const T;
1016+
// FIXME(#2749): Justify this `Uninit`.
1017+
type Uninit = crate::invariant::Uninit;
1018+
|c| pointer::is_zeroed(c)
1019+
);
9671020
unsafe_impl!(T => FromZeros for *const T);
968-
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c));
1021+
unsafe_impl!(T => TryFromBytes for *mut T;
1022+
// FIXME(#2749): Justify this `Uninit`.
1023+
type Uninit = crate::invariant::Uninit;
1024+
|c| pointer::is_zeroed(c)
1025+
);
9691026
unsafe_impl!(T => FromZeros for *mut T);
9701027
};
9711028

@@ -990,6 +1047,8 @@ const _: () = unsafe { unsafe_impl!(T: Immutable => Immutable for Option<T>) };
9901047
mod tuples {
9911048
use super::*;
9921049

1050+
type Uninit<const N: usize> = crate::invariant::Uninit;
1051+
9931052
/// Generates various trait implementations for tuples.
9941053
///
9951054
/// # Safety
@@ -1011,11 +1070,14 @@ mod tuples {
10111070
unsafe_impl!($($head_T: Immutable,)* $next_T: Immutable => Immutable for ($($head_T,)* $next_T,));
10121071

10131072
// SAFETY: If all fields in `c` are `is_bit_valid`, so too is `c`.
1014-
unsafe_impl!($($head_T: TryFromBytes,)* $next_T: TryFromBytes => TryFromBytes for ($($head_T,)* $next_T,); |c| {
1015-
let mut c = c;
1016-
$(TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($head_I) }>())) &&)*
1017-
TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($next_I) }>()))
1018-
});
1073+
unsafe_impl!($($head_T: TryFromBytes,)* $next_T: TryFromBytes => TryFromBytes for ($($head_T,)* $next_T,);
1074+
type Uninit = ($(Uninit<$head_I>,)* Uninit<$next_I>,);
1075+
|c| {
1076+
let mut c = c;
1077+
$(TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($head_I) }>())) &&)*
1078+
TryFromBytes::is_bit_valid(into_inner!(c.reborrow().project::<_, { crate::STRUCT_VARIANT_ID }, { crate::ident_id!($next_I) }>()))
1079+
}
1080+
);
10191081

10201082
// SAFETY: If all fields in `Self` are `FromZeros`, so too is `Self`.
10211083
unsafe_impl!($($head_T: FromZeros,)* $next_T: FromZeros => FromZeros for ($($head_T,)* $next_T,));

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1700,6 +1700,10 @@ pub unsafe trait TryFromBytes {
17001700
where
17011701
Self: Sized;
17021702

1703+
/// The validity of `Self` in an uninitialized state.
1704+
#[doc(hidden)]
1705+
type Uninit;
1706+
17031707
/// Does a given memory range contain a valid instance of `Self`?
17041708
///
17051709
/// # Safety

0 commit comments

Comments
 (0)