Skip to content

Commit ec6bf00

Browse files
joshlfjswrenn
authored andcommitted
Use HasField machinery to allow init_field to transparently
initialize an enum's variant tag. gherrit-pr-id: I2c9259eb95c6b425c59199f91198481296a727a8
1 parent 32ec354 commit ec6bf00

File tree

11 files changed

+949
-660
lines changed

11 files changed

+949
-660
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
target
1111
Cargo.lock
1212
lcov.info
13+
examples
1314

1415
# VSCode workspace files
1516
*.code-workspace

src/impls.rs

Lines changed: 90 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,13 @@ assert_unaligned!(bool);
104104
// The value false has the bit pattern 0x00 and the value true has the bit
105105
// pattern 0x01.
106106
const _: () = unsafe {
107-
unsafe_impl!(=> TryFromBytes for bool; |byte| {
108-
let byte = byte.transmute::<u8, invariant::Valid, _>();
109-
*byte.unaligned_as_ref() < 2
110-
})
107+
unsafe_impl!(=> TryFromBytes for bool;
108+
type Uninit = crate::init::Uninit;
109+
|byte| {
110+
let byte = byte.transmute::<u8, invariant::Valid, _>();
111+
*byte.unaligned_as_ref() < 2
112+
}
113+
)
111114
};
112115
impl_size_eq!(bool, u8);
113116

@@ -133,11 +136,14 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) };
133136
// `from_u32()` will return `None` if the input is not a valid value for a
134137
// `char`.
135138
const _: () = unsafe {
136-
unsafe_impl!(=> TryFromBytes for char; |c| {
137-
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
138-
let c = c.read_unaligned().into_inner();
139-
char::from_u32(c).is_some()
140-
});
139+
unsafe_impl!(=> TryFromBytes for char;
140+
type Uninit = crate::init::Uninit;
141+
|c| {
142+
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
143+
let c = c.read_unaligned().into_inner();
144+
char::from_u32(c).is_some()
145+
}
146+
);
141147
};
142148

143149
impl_size_eq!(char, Unalign<u32>);
@@ -166,24 +172,31 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig
166172
//
167173
// Returns `Err` if the slice is not UTF-8.
168174
const _: () = unsafe {
169-
unsafe_impl!(=> TryFromBytes for str; |c| {
170-
let c = c.transmute::<[u8], invariant::Valid, _>();
171-
let c = c.unaligned_as_ref();
172-
core::str::from_utf8(c).is_ok()
173-
})
175+
unsafe_impl!(=> TryFromBytes for str;
176+
// TODO: Is this the best we can do?
177+
type Uninit = crate::init::Uninit;
178+
|c| {
179+
let c = c.transmute::<[u8], invariant::Valid, _>();
180+
let c = c.unaligned_as_ref();
181+
core::str::from_utf8(c).is_ok()
182+
}
183+
)
174184
};
175185

176186
impl_size_eq!(str, [u8]);
177187

178188
macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
179189
($($nonzero:ident[$prim:ty]),*) => {
180190
$(
181-
unsafe_impl!(=> TryFromBytes for $nonzero; |n| {
182-
impl_size_eq!($nonzero, Unalign<$prim>);
191+
unsafe_impl!(=> TryFromBytes for $nonzero;
192+
type Uninit = crate::init::Uninit;
193+
|n| {
194+
impl_size_eq!($nonzero, Unalign<$prim>);
183195

184-
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
185-
$nonzero::new(n.read_unaligned().into_inner()).is_some()
186-
});
196+
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
197+
$nonzero::new(n.read_unaligned().into_inner()).is_some()
198+
}
199+
);
187200
)*
188201
}
189202
}
@@ -322,23 +335,31 @@ const _: () = unsafe {
322335
#[cfg(feature = "alloc")]
323336
unsafe_impl!(
324337
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
325-
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
338+
T => TryFromBytes for Option<Box<T>>;
339+
type Uninit = crate::init::Uninit;
340+
|c| pointer::is_zeroed(c)
326341
);
327342
#[cfg(feature = "alloc")]
328343
unsafe_impl!(
329344
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
330345
T => FromZeros for Option<Box<T>>
331346
);
332347
unsafe_impl!(
333-
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c)
348+
T => TryFromBytes for Option<&'_ T>;
349+
type Uninit = crate::init::Uninit;
350+
|c| pointer::is_zeroed(c)
334351
);
335352
unsafe_impl!(T => FromZeros for Option<&'_ T>);
336353
unsafe_impl!(
337-
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c)
354+
T => TryFromBytes for Option<&'_ mut T>;
355+
type Uninit = crate::init::Uninit;
356+
|c| pointer::is_zeroed(c)
338357
);
339358
unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
340359
unsafe_impl!(
341-
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c)
360+
T => TryFromBytes for Option<NonNull<T>>;
361+
type Uninit = crate::init::Uninit;
362+
|c| pointer::is_zeroed(c)
342363
);
343364
unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
344365
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
@@ -796,6 +817,8 @@ assert_unaligned!(UnsafeCell<()>, UnsafeCell<u8>);
796817

797818
// SAFETY: See safety comment in `is_bit_valid` impl.
798819
unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
820+
type Uninit = T::Uninit;
821+
799822
#[allow(clippy::missing_inline_in_public_items)]
800823
fn only_derive_is_allowed_to_implement_this_trait()
801824
where
@@ -853,42 +876,48 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
853876
// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#array-layout
854877
const _: () = unsafe {
855878
unsafe_impl!(const N: usize, T: Immutable => Immutable for [T; N]);
856-
unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N]; |c| {
857-
// Note that this call may panic, but it would still be sound even if it
858-
// did. `is_bit_valid` does not promise that it will not panic (in fact,
859-
// it explicitly warns that it's a possibility), and we have not
860-
// violated any safety invariants that we must fix before returning.
861-
<[T] as TryFromBytes>::is_bit_valid(c.as_slice())
862-
});
879+
unsafe_impl!(const N: usize, T: TryFromBytes => TryFromBytes for [T; N];
880+
type Uninit = T::Uninit;
881+
|c| {
882+
// Note that this call may panic, but it would still be sound even if it
883+
// did. `is_bit_valid` does not promise that it will not panic (in fact,
884+
// it explicitly warns that it's a possibility), and we have not
885+
// violated any safety invariants that we must fix before returning.
886+
<[T] as TryFromBytes>::is_bit_valid(c.as_slice())
887+
}
888+
);
863889
unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
864890
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
865891
unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
866892
unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
867893
assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
868894
unsafe_impl!(T: Immutable => Immutable for [T]);
869-
unsafe_impl!(T: TryFromBytes => TryFromBytes for [T]; |c| {
870-
// SAFETY: Per the reference [1]:
871-
//
872-
// An array of `[T; N]` has a size of `size_of::<T>() * N` and the
873-
// same alignment of `T`. Arrays are laid out so that the zero-based
874-
// `nth` element of the array is offset from the start of the array by
875-
// `n * size_of::<T>()` bytes.
876-
//
877-
// ...
878-
//
879-
// Slices have the same layout as the section of the array they slice.
880-
//
881-
// In other words, the layout of a `[T] is a sequence of `T`s laid out
882-
// back-to-back with no bytes in between. If all elements in `candidate`
883-
// are `is_bit_valid`, so too is `candidate`.
884-
//
885-
// Note that any of the below calls may panic, but it would still be
886-
// sound even if it did. `is_bit_valid` does not promise that it will
887-
// not panic (in fact, it explicitly warns that it's a possibility), and
888-
// we have not violated any safety invariants that we must fix before
889-
// returning.
890-
c.iter().all(<T as TryFromBytes>::is_bit_valid)
891-
});
895+
unsafe_impl!(T: TryFromBytes => TryFromBytes for [T];
896+
type Uninit = T::Uninit;
897+
|c| {
898+
// SAFETY: Per the reference [1]:
899+
//
900+
// An array of `[T; N]` has a size of `size_of::<T>() * N` and the
901+
// same alignment of `T`. Arrays are laid out so that the zero-based
902+
// `nth` element of the array is offset from the start of the array by
903+
// `n * size_of::<T>()` bytes.
904+
//
905+
// ...
906+
//
907+
// Slices have the same layout as the section of the array they slice.
908+
//
909+
// In other words, the layout of a `[T] is a sequence of `T`s laid out
910+
// back-to-back with no bytes in between. If all elements in `candidate`
911+
// are `is_bit_valid`, so too is `candidate`.
912+
//
913+
// Note that any of the below calls may panic, but it would still be
914+
// sound even if it did. `is_bit_valid` does not promise that it will
915+
// not panic (in fact, it explicitly warns that it's a possibility), and
916+
// we have not violated any safety invariants that we must fix before
917+
// returning.
918+
c.iter().all(<T as TryFromBytes>::is_bit_valid)
919+
}
920+
);
892921
unsafe_impl!(T: FromZeros => FromZeros for [T]);
893922
unsafe_impl!(T: FromBytes => FromBytes for [T]);
894923
unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
@@ -914,9 +943,15 @@ const _: () = unsafe {
914943
const _: () = unsafe {
915944
unsafe_impl!(T: ?Sized => Immutable for *const T);
916945
unsafe_impl!(T: ?Sized => Immutable for *mut T);
917-
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c));
946+
unsafe_impl!(T => TryFromBytes for *const T;
947+
type Uninit = crate::init::Uninit;
948+
|c| pointer::is_zeroed(c)
949+
);
918950
unsafe_impl!(T => FromZeros for *const T);
919-
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c));
951+
unsafe_impl!(T => TryFromBytes for *mut T;
952+
type Uninit = crate::init::Uninit;
953+
|c| pointer::is_zeroed(c)
954+
);
920955
unsafe_impl!(T => FromZeros for *mut T);
921956
};
922957

0 commit comments

Comments
 (0)