Skip to content

Commit db1c3e0

Browse files
committed
[derive] TryFromBytes on unions w/o Immutable
TODO: - Add tests in zerocopy-derive/tests for unions with UnsafeCells - Add tests (location TBD) for calling &mut methods on TryFromBytes on unions with UnsafeCells gherrit-pr-id: If86f182f8e3fda5d12d680c400c7a0a7f7095ce4
1 parent 525336d commit db1c3e0

File tree

9 files changed

+203
-107
lines changed

9 files changed

+203
-107
lines changed

src/impls.rs

Lines changed: 54 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use super::*;
2525
//
2626
// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout
2727
const _: () = unsafe {
28-
unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
28+
unsafe_impl!((): Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
2929
assert_unaligned!(());
3030
};
3131

@@ -60,25 +60,31 @@ const _: () = unsafe {
6060
// FIXME(#278): Once we've updated the trait docs to refer to `u8`s rather than
6161
// bits or bytes, update this comment, especially the reference to [1].
6262
const _: () = unsafe {
63-
unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
64-
unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
63+
unsafe_impl!(u8: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
64+
unsafe_impl!(i8: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
6565
assert_unaligned!(u8, i8);
66-
unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
67-
unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
68-
unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
69-
unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
70-
unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
71-
unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
72-
unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
73-
unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
74-
unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
75-
unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
76-
unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
77-
unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
66+
unsafe_impl!(u16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
67+
unsafe_impl!(i16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
68+
unsafe_impl!(u32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
69+
unsafe_impl!(i32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
70+
unsafe_impl!(u64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
71+
unsafe_impl!(i64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
72+
unsafe_impl!(u128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
73+
unsafe_impl!(i128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
74+
unsafe_impl!(usize: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
75+
unsafe_impl!(isize: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
76+
unsafe_impl!(f32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
77+
unsafe_impl!(f64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
7878
#[cfg(feature = "float-nightly")]
79-
unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
79+
unsafe_impl!(
80+
#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))]
81+
f16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes
82+
);
8083
#[cfg(feature = "float-nightly")]
81-
unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
84+
unsafe_impl!(
85+
#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))]
86+
f128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes
87+
);
8288
};
8389

8490
// SAFETY:
@@ -107,7 +113,7 @@ const _: () = unsafe {
107113
unsafe_impl!(=> TryFromBytes for bool; |byte| {
108114
let byte = byte.transmute::<u8, invariant::Valid, _>();
109115
*byte.unaligned_as_ref() < 2
110-
})
116+
}; IS_IMMUTABLE = true)
111117
};
112118
impl_size_eq!(bool, u8);
113119

@@ -137,7 +143,7 @@ const _: () = unsafe {
137143
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
138144
let c = c.read_unaligned().into_inner();
139145
char::from_u32(c).is_some()
140-
});
146+
}; IS_IMMUTABLE = true);
141147
};
142148

143149
impl_size_eq!(char, Unalign<u32>);
@@ -170,7 +176,7 @@ const _: () = unsafe {
170176
let c = c.transmute::<[u8], invariant::Valid, _>();
171177
let c = c.unaligned_as_ref();
172178
core::str::from_utf8(c).is_ok()
173-
})
179+
}; IS_IMMUTABLE = true)
174180
};
175181

176182
// SAFETY: `str` and `[u8]` have the same layout [1].
@@ -210,7 +216,7 @@ macro_rules! unsafe_impl_try_from_bytes_for_nonzero {
210216

211217
let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
212218
$nonzero::new(n.read_unaligned().into_inner()).is_some()
213-
});
219+
}; IS_IMMUTABLE = true);
214220
)*
215221
}
216222
}
@@ -296,19 +302,19 @@ const _: () = unsafe {
296302
// FIXME(https://github.com/rust-lang/rust/pull/104082): Cite documentation for
297303
// layout guarantees.
298304
const _: () = unsafe {
299-
unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
300-
unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
305+
unsafe_impl!(Option<NonZeroU8>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
306+
unsafe_impl!(Option<NonZeroI8>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
301307
assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
302-
unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
303-
unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
304-
unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
305-
unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
306-
unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
307-
unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
308-
unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
309-
unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
310-
unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
311-
unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
308+
unsafe_impl!(Option<NonZeroU16>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
309+
unsafe_impl!(Option<NonZeroI16>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
310+
unsafe_impl!(Option<NonZeroU32>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
311+
unsafe_impl!(Option<NonZeroI32>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
312+
unsafe_impl!(Option<NonZeroU64>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
313+
unsafe_impl!(Option<NonZeroI64>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
314+
unsafe_impl!(Option<NonZeroU128>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
315+
unsafe_impl!(Option<NonZeroI128>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
316+
unsafe_impl!(Option<NonZeroUsize>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
317+
unsafe_impl!(Option<NonZeroIsize>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
312318
};
313319

314320
// SAFETY: While it's not fully documented, the consensus is that `Box<T>` does
@@ -348,34 +354,34 @@ const _: () = unsafe {
348354
#[cfg(feature = "alloc")]
349355
unsafe_impl!(
350356
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
351-
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
357+
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
352358
);
353359
#[cfg(feature = "alloc")]
354360
unsafe_impl!(
355361
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
356362
T => FromZeros for Option<Box<T>>
357363
);
358364
unsafe_impl!(
359-
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c)
365+
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
360366
);
361367
unsafe_impl!(T => FromZeros for Option<&'_ T>);
362368
unsafe_impl!(
363-
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c)
369+
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
364370
);
365371
unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
366372
unsafe_impl!(
367-
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c)
373+
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
368374
);
369375
unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
370376
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
371377
unsafe_impl_for_power_set!(
372378
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
373-
|c| pointer::is_zeroed(c)
379+
|c| pointer::is_zeroed(c); IS_IMMUTABLE = true
374380
);
375381
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
376382
unsafe_impl_for_power_set!(
377383
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
378-
|c| pointer::is_zeroed(c)
384+
|c| pointer::is_zeroed(c); IS_IMMUTABLE = true
379385
);
380386
};
381387

@@ -679,7 +685,7 @@ mod atomics {
679685
// [1] https://doc.rust-lang.org/1.81.0/std/marker/struct.PhantomData.html#layout-1
680686
const _: () = unsafe {
681687
unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
682-
unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
688+
unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>; IS_IMMUTABLE = true);
683689
unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
684690
unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
685691
unsafe_impl!(T: ?Sized => IntoBytes for PhantomData<T>);
@@ -712,7 +718,7 @@ const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>) }
712718
// SAFETY: `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
713719
// `MaybeUninit<T>` has no restrictions on its contents.
714720
const _: () = unsafe {
715-
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
721+
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>; IS_IMMUTABLE = T::IS_IMMUTABLE);
716722
unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
717723
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
718724
};
@@ -808,6 +814,8 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
808814
{
809815
}
810816

817+
const IS_IMMUTABLE: bool = false;
818+
811819
#[inline]
812820
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool {
813821
// The only way to implement this function is using an exclusive-aliased
@@ -864,7 +872,7 @@ const _: () = unsafe {
864872
// it explicitly warns that it's a possibility), and we have not
865873
// violated any safety invariants that we must fix before returning.
866874
<[T] as TryFromBytes>::is_bit_valid(c.as_slice())
867-
});
875+
}; IS_IMMUTABLE = T::IS_IMMUTABLE);
868876
unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
869877
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
870878
unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
@@ -893,7 +901,7 @@ const _: () = unsafe {
893901
// we have not violated any safety invariants that we must fix before
894902
// returning.
895903
c.iter().all(<T as TryFromBytes>::is_bit_valid)
896-
});
904+
}; IS_IMMUTABLE = T::IS_IMMUTABLE);
897905
unsafe_impl!(T: FromZeros => FromZeros for [T]);
898906
unsafe_impl!(T: FromBytes => FromBytes for [T]);
899907
unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
@@ -919,9 +927,9 @@ const _: () = unsafe {
919927
const _: () = unsafe {
920928
unsafe_impl!(T: ?Sized => Immutable for *const T);
921929
unsafe_impl!(T: ?Sized => Immutable for *mut T);
922-
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c));
930+
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true);
923931
unsafe_impl!(T => FromZeros for *const T);
924-
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c));
932+
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true);
925933
unsafe_impl!(T => FromZeros for *mut T);
926934
};
927935

@@ -1032,7 +1040,7 @@ mod simd {
10321040
impl_known_layout!($($typ),*);
10331041
// SAFETY: See comment on module definition for justification.
10341042
const _: () = unsafe {
1035-
$( unsafe_impl!($typ: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); )*
1043+
$( unsafe_impl!($typ: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes); )*
10361044
};
10371045
}
10381046
};

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,9 @@ pub unsafe trait TryFromBytes {
14481448
where
14491449
Self: Sized;
14501450

1451+
#[doc(hidden)]
1452+
const IS_IMMUTABLE: bool;
1453+
14511454
/// Does a given memory range contain a valid instance of `Self`?
14521455
///
14531456
/// # Safety

src/macros.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,10 @@ macro_rules! cryptocorrosion_derive_traits {
780780
$($field_ty: $crate::FromBytes,)*
781781
)?
782782
{
783+
const IS_IMMUTABLE: bool = true $(
784+
&& <$field_ty as $crate::TryFromBytes>::IS_IMMUTABLE
785+
)*;
786+
783787
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
784788
where
785789
A: $crate::pointer::invariant::Reference
@@ -923,6 +927,10 @@ macro_rules! cryptocorrosion_derive_traits {
923927
$field_ty: $crate::FromBytes,
924928
)*
925929
{
930+
const IS_IMMUTABLE: bool = true $(
931+
&& <$field_ty as $crate::TryFromBytes>::IS_IMMUTABLE
932+
)*;
933+
926934
fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
927935
where
928936
A: $crate::pointer::invariant::Reference

0 commit comments

Comments
 (0)