1 // Copyright 2023 The Fuchsia Authors
2 //
3 // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
4 // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
6 // This file may not be copied, modified, or distributed except according to
7 // those terms.
8
9 // See comment in `include.rs` for why we disable the prelude.
10 #![no_implicit_prelude]
11 #![allow(warnings)]
12
13 include!("include.rs");
14
15 // A struct is `imp::TryFromBytes` if:
16 // - any of its fields are `imp::TryFromBytes`
17
18 #[derive(imp::Immutable, imp::TryFromBytes)]
19 union One {
20 a: u8,
21 }
22
23 util_assert_impl_all!(One: imp::TryFromBytes);
24
25 #[test]
one()26 fn one() {
27 // TODO(#5): Use `try_transmute` in this test once it's available.
28 let candidate = ::zerocopy::Ptr::from_ref(&One { a: 42 });
29 let candidate = candidate.forget_aligned();
30 // SAFETY: `&One` consists entirely of initialized bytes.
31 let candidate = unsafe { candidate.assume_initialized() };
32 let is_bit_valid = <One as imp::TryFromBytes>::is_bit_valid(candidate);
33 assert!(is_bit_valid);
34 }
35
36 #[derive(imp::Immutable, imp::TryFromBytes)]
37 #[repr(C)]
38 union Two {
39 a: bool,
40 b: bool,
41 }
42
43 util_assert_impl_all!(Two: imp::TryFromBytes);
44
45 #[test]
two()46 fn two() {
47 // TODO(#5): Use `try_transmute` in this test once it's available.
48 let candidate_a = ::zerocopy::Ptr::from_ref(&Two { a: false });
49 let candidate_a = candidate_a.forget_aligned();
50 // SAFETY: `&Two` consists entirely of initialized bytes.
51 let candidate_a = unsafe { candidate_a.assume_initialized() };
52 let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate_a);
53 assert!(is_bit_valid);
54
55 let candidate_b = ::zerocopy::Ptr::from_ref(&Two { b: true });
56 let candidate_b = candidate_b.forget_aligned();
57 // SAFETY: `&Two` consists entirely of initialized bytes.
58 let candidate_b = unsafe { candidate_b.assume_initialized() };
59 let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate_b);
60 assert!(is_bit_valid);
61 }
62
63 #[test]
two_bad()64 fn two_bad() {
65 // TODO(#5): Use `try_transmute` in this test once it's available.
66 let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
67 let candidate = candidate.forget_aligned();
68 // SAFETY: `&[u8]` consists entirely of initialized bytes.
69 let candidate = unsafe { candidate.assume_initialized() };
70
71 // SAFETY:
72 // - The cast preserves address and size. As a result, the cast will address
73 // the same bytes as `c`.
74 // - The cast preserves provenance.
75 // - Neither the input nor output types contain any `UnsafeCell`s.
76 let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) };
77
78 // SAFETY: `candidate`'s referent is as-initialized as `Two`.
79 let candidate = unsafe { candidate.assume_initialized() };
80
81 let is_bit_valid = <Two as imp::TryFromBytes>::is_bit_valid(candidate);
82 assert!(!is_bit_valid);
83 }
84
85 #[derive(imp::Immutable, imp::TryFromBytes)]
86 #[repr(C)]
87 union BoolAndZst {
88 a: bool,
89 b: (),
90 }
91
92 #[test]
bool_and_zst()93 fn bool_and_zst() {
94 // TODO(#5): Use `try_transmute` in this test once it's available.
95 let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
96 let candidate = candidate.forget_aligned();
97 // SAFETY: `&[u8]` consists entirely of initialized bytes.
98 let candidate = unsafe { candidate.assume_initialized() };
99
100 // SAFETY:
101 // - The cast preserves address and size. As a result, the cast will address
102 // the same bytes as `c`.
103 // - The cast preserves provenance.
104 // - Neither the input nor output types contain any `UnsafeCell`s.
105 let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut BoolAndZst) };
106
107 // SAFETY: `candidate`'s referent is fully initialized.
108 let candidate = unsafe { candidate.assume_initialized() };
109
110 let is_bit_valid = <BoolAndZst as imp::TryFromBytes>::is_bit_valid(candidate);
111 assert!(is_bit_valid);
112 }
113
114 #[derive(imp::FromBytes)]
115 #[repr(C)]
116 union MaybeFromBytes<T: imp::Copy> {
117 t: T,
118 }
119
120 #[test]
test_maybe_from_bytes()121 fn test_maybe_from_bytes() {
122 // When deriving `FromBytes` on a type with no generic parameters, we emit a
123 // trivial `is_bit_valid` impl that always returns true. This test confirms
124 // that we *don't* spuriously do that when generic parameters are present.
125
126 let candidate = ::zerocopy::Ptr::from_ref(&[2u8][..]);
127 let candidate = candidate.bikeshed_recall_initialized_from_bytes();
128
129 // SAFETY:
130 // - The cast preserves address and size. As a result, the cast will address
131 // the same bytes as `c`.
132 // - The cast preserves provenance.
133 // - Neither the input nor output types contain any `UnsafeCell`s.
134 let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes<bool>) };
135
136 // SAFETY: `[u8]` consists entirely of initialized bytes.
137 let candidate = unsafe { candidate.assume_initialized() };
138 let is_bit_valid = <MaybeFromBytes<bool> as imp::TryFromBytes>::is_bit_valid(candidate);
139 imp::assert!(!is_bit_valid);
140 }
141
142 #[derive(imp::Immutable, imp::TryFromBytes)]
143 #[repr(C)]
144 union TypeParams<'a, T: imp::Copy, I: imp::Iterator>
145 where
146 I::Item: imp::Copy,
147 {
148 a: I::Item,
149 b: u8,
150 c: imp::PhantomData<&'a [u8]>,
151 d: imp::PhantomData<&'static str>,
152 e: imp::PhantomData<imp::String>,
153 f: T,
154 }
155
156 util_assert_impl_all!(TypeParams<'static, (), imp::IntoIter<()>>: imp::TryFromBytes);
157 util_assert_impl_all!(TypeParams<'static, util::AU16, imp::IntoIter<()>>: imp::TryFromBytes);
158 util_assert_impl_all!(TypeParams<'static, [util::AU16; 2], imp::IntoIter<()>>: imp::TryFromBytes);
159
160 // Deriving `imp::TryFromBytes` should work if the union has bounded parameters.
161
162 #[derive(imp::Immutable, imp::TryFromBytes)]
163 #[repr(C)]
164 union WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::TryFromBytes, const N: usize>
165 where
166 'a: 'b,
167 'b: 'a,
168 T: 'a + 'b + imp::TryFromBytes + imp::Copy,
169 {
170 a: imp::PhantomData<&'a &'b ()>,
171 b: T,
172 }
173
174 util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::TryFromBytes);
175
176 #[derive(Clone, Copy, imp::TryFromBytes, imp::Immutable)]
177 struct A;
178
179 #[derive(imp::TryFromBytes)]
180 union B {
181 a: A,
182 }
183