1use core::{fmt, hash::Hash, mem::transmute};
2
3use crate::{
4 CmpFn, CmpFnTyped, DebugFn, DebugFnTyped, DisplayFn, DisplayFnTyped, Facet, HashFn,
5 HashFnTyped, HasherProxy, MarkerTraits, PartialEqFn, PartialEqFnTyped, PartialOrdFn,
6 PartialOrdFnTyped, PointerType, Shape, Type, TypeParam, ValuePointerType, ValueVTable,
7};
8
9macro_rules! impl_facet_for_pointer {
10 ($variant:ident: $type:ty => $shape:expr => $vtable_builder:expr => $ptr_type:ident, $mutable:expr) => {
11 unsafe impl<'a, T: Facet<'a> + ?Sized> Facet<'a> for $type {
12 const VTABLE: &'static ValueVTable = &const {
13 $vtable_builder
14 .type_name(|f, opts| {
15 if let Some(opts) = opts.for_children() {
16 if stringify!($ptr_type) == "Raw" {
17 if $mutable {
18 write!(f, "*mut ")?;
19 } else {
20 write!(f, "*const ")?;
21 }
22 } else {
23 write!(f, "&")?;
24 if $mutable {
25 write!(f, "mut ")?;
26 }
27 }
28 (T::VTABLE.type_name)(f, opts)
29 } else {
30 if stringify!($ptr_type) == "Raw" {
31 if $mutable {
32 write!(f, "*mut ⋯")
33 } else {
34 write!(f, "*const ⋯")
35 }
36 } else {
37 write!(f, "&")?;
38 if $mutable {
39 write!(f, "mut ⋯")
40 } else {
41 write!(f, "⋯")
42 }
43 }
44 }
45 })
46 .build()
47 };
48
49 const SHAPE: &'static Shape<'static> = &const {
50 $shape
51 .type_identifier(
52 const {
53 let ptr_type = stringify!($ptr_type);
54 let is_raw = ptr_type.len() == 3
55 && ptr_type.as_bytes()[0] == b'R'
56 && ptr_type.as_bytes()[1] == b'a'
57 && ptr_type.as_bytes()[2] == b'w';
58 if is_raw {
59 if $mutable { "*mut _" } else { "*const _" }
60 } else {
61 if $mutable { "&mut _" } else { "&_" }
62 }
63 },
64 )
65 .type_params(&[TypeParam {
66 name: "T",
67 shape: || T::SHAPE,
68 }])
69 .ty({
70 let is_wide =
71 ::core::mem::size_of::<$type>() != ::core::mem::size_of::<*const ()>();
72 let vpt = ValuePointerType {
73 mutable: $mutable,
74 wide: is_wide,
75 target: || T::SHAPE,
76 };
77
78 Type::Pointer(PointerType::$ptr_type(vpt))
79 })
80 .build()
81 };
82 }
83 };
84}
85
86impl_facet_for_pointer!(
88 Raw: *const T
89 => Shape::builder_for_sized::<Self>()
90 .inner(|| T::SHAPE)
91 => ValueVTable::builder::<Self>()
92 .marker_traits(|| {
93 let mut marker_traits = MarkerTraits::EQ
94 .union(MarkerTraits::COPY)
95 .union(MarkerTraits::UNPIN);
96
97 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::REF_UNWIND_SAFE) {
98 marker_traits = marker_traits.union(MarkerTraits::UNWIND_SAFE).union(MarkerTraits::REF_UNWIND_SAFE);
99 }
100
101 marker_traits
102 })
103 .debug(|| Some(fmt::Debug::fmt))
104 .clone_into(|| Some(|src, dst| unsafe { dst.put(*src) }))
105 .partial_eq(|| Some(|&left, &right| core::ptr::eq(left, right)))
106 .partial_ord(|| Some(|&left, &right| {
107 #[allow(ambiguous_wide_pointer_comparisons)]
109 left.partial_cmp(&right)
110 }))
111 .ord(|| Some(|&left, &right| {
112 #[allow(ambiguous_wide_pointer_comparisons)]
113 left.cmp(&right)
114 }))
115 .hash(|| Some(|value, hasher_this, hasher_write_fn| {
116 value.hash(&mut unsafe {
117 HasherProxy::new(hasher_this, hasher_write_fn)
118 })
119 }))
120 => Raw, false
121);
122
123impl_facet_for_pointer!(
125 Raw: *mut T
126 => Shape::builder_for_sized::<Self>()
127 .inner(|| T::SHAPE)
128 => ValueVTable::builder::<Self>()
129 .marker_traits(|| {
130 let mut marker_traits = MarkerTraits::EQ
131 .union(MarkerTraits::COPY)
132 .union(MarkerTraits::UNPIN);
133
134 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::REF_UNWIND_SAFE) {
135 marker_traits = marker_traits.union(MarkerTraits::UNWIND_SAFE).union(MarkerTraits::REF_UNWIND_SAFE);
136 }
137
138 marker_traits
139 })
140 .debug(|| Some(fmt::Debug::fmt))
141 .clone_into(|| Some(|src, dst| unsafe { dst.put(*src) }))
142 .partial_eq(|| Some(|&left, &right| core::ptr::eq(left, right)))
143 .partial_ord(|| Some(|&left, &right| {
144 #[allow(ambiguous_wide_pointer_comparisons)]
146 left.partial_cmp(&right)
147 }))
148 .ord(|| Some(|&left, &right| {
149 #[allow(ambiguous_wide_pointer_comparisons)]
150 left.cmp(&right)
151 }))
152 .hash(|| Some(|value, hasher_this, hasher_write_fn| {
153 value.hash(&mut unsafe {
154 HasherProxy::new(hasher_this, hasher_write_fn)
155 })
156 }))
157 => Raw, true
158);
159
160impl_facet_for_pointer!(
162 Reference: &'a T
163 => Shape::builder_for_sized::<Self>()
164 => {
165 ValueVTable::builder::<Self>()
166 .marker_traits(|| {
167 let mut marker_traits = MarkerTraits::COPY.union(MarkerTraits::UNPIN);
168 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::EQ) {
169 marker_traits = marker_traits.union(MarkerTraits::EQ);
170 }
171 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::SYNC) {
172 marker_traits = marker_traits.union(MarkerTraits::SEND).union(MarkerTraits::SYNC);
173 }
174 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::REF_UNWIND_SAFE) {
175 marker_traits = marker_traits.union(MarkerTraits::UNWIND_SAFE).union(MarkerTraits::REF_UNWIND_SAFE);
176 }
177
178 marker_traits
179 })
180 .clone_into(|| Some(|src, dst| unsafe { dst.put(core::ptr::read(src)) }))
181 .debug(|| {
182 if (T::VTABLE.debug)().is_some() {
183 Some(|value, f| {
184 let debug_fn = unsafe { transmute::<DebugFn, DebugFnTyped<T>>((T::VTABLE.debug)().unwrap()) };
185 debug_fn(*value, f)
186 })
187 } else {
188 None
189 }
190 })
191 .display(|| {
192 if (T::VTABLE.display)().is_some() {
193 Some(|value, f| {
194 let display_fn = unsafe { transmute::<DisplayFn, DisplayFnTyped<T>>((T::VTABLE.display)().unwrap()) };
195 display_fn(*value, f)
196 })
197 } else {
198 None
199 }
200 })
201 .partial_eq(|| {
202 if (T::VTABLE.partial_eq)().is_some() {
203 Some(|a, b| {
204 let eq_fn = unsafe { transmute::<PartialEqFn, PartialEqFnTyped<T>>((T::VTABLE.partial_eq)().unwrap()) };
205 eq_fn(*a, *b)
206 })
207 } else {
208 None
209 }
210 })
211 .partial_ord(|| {
212 if (T::VTABLE.partial_ord)().is_some() {
213 Some(|a, b| {
214 let partial_ord_fn = unsafe { transmute::<PartialOrdFn, PartialOrdFnTyped<T>>((T::VTABLE.partial_ord)().unwrap()) };
215 partial_ord_fn(*a, *b)
216 })
217 } else {
218 None
219 }
220 })
221 .ord(|| {
222 if (T::VTABLE.ord)().is_some() {
223 Some(|a, b| {
224 let ord_fn = unsafe { transmute::<CmpFn, CmpFnTyped<T>>((T::VTABLE.ord)().unwrap()) };
225 ord_fn(*a, *b)
226 })
227 } else {
228 None
229 }
230 })
231 .hash(|| {
232 if (T::VTABLE.hash)().is_some() {
233 Some(|value, hasher_this, hasher_write_fn| {
234 let hash_fn = unsafe { transmute::<HashFn, HashFnTyped<T>>((T::VTABLE.hash)().unwrap()) };
235 hash_fn(*value, hasher_this, hasher_write_fn)
236 })
237 } else {
238 None
239 }
240 })
241 }
242 => Reference, false
243);
244
245impl_facet_for_pointer!(
247 Reference: &'a mut T
248 => Shape::builder_for_sized::<Self>()
249 => {
250 ValueVTable::builder::<Self>()
251 .marker_traits(|| {
252 let mut marker_traits = MarkerTraits::UNPIN;
253 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::EQ) {
254 marker_traits = marker_traits.union(MarkerTraits::EQ);
255 }
256 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::SEND) {
257 marker_traits = marker_traits.union(MarkerTraits::SEND);
258 }
259 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::SYNC) {
260 marker_traits = marker_traits.union(MarkerTraits::SYNC);
261 }
262 if T::SHAPE.vtable.marker_traits().contains(MarkerTraits::REF_UNWIND_SAFE) {
263 marker_traits = marker_traits.union(MarkerTraits::REF_UNWIND_SAFE);
264 }
265
266 marker_traits
267 })
268 .debug(|| {
269 if (T::VTABLE.debug)().is_some() {
270 Some(|value, f| {
271 let debug_fn = unsafe { transmute::<DebugFn, DebugFnTyped<T>>((T::VTABLE.debug)().unwrap()) };
272 debug_fn(*value, f)
273 })
274 } else {
275 None
276 }
277 })
278 .display(|| {
279 if (T::VTABLE.display)().is_some() {
280 Some(|value, f| {
281 let display_fn = unsafe { transmute::<DisplayFn, DisplayFnTyped<T>>((T::VTABLE.display)().unwrap()) };
282 display_fn(*value, f)
283 })
284 } else {
285 None
286 }
287 })
288 .partial_eq(|| {
289 if (T::VTABLE.partial_eq)().is_some() {
290 Some(|a, b| {
291 let eq_fn = unsafe { transmute::<PartialEqFn, PartialEqFnTyped<T>>((T::VTABLE.partial_eq)().unwrap()) };
292 eq_fn(*a, *b)
293 })
294 } else {
295 None
296 }
297 })
298 .partial_ord(|| {
299 if (T::VTABLE.partial_ord)().is_some() {
300 Some(|a, b| {
301 let partial_ord_fn = unsafe { transmute::<PartialOrdFn, PartialOrdFnTyped<T>>((T::VTABLE.partial_ord)().unwrap()) };
302 partial_ord_fn(*a, *b)
303 })
304 } else {
305 None
306 }
307 })
308 .ord(|| {
309 if (T::VTABLE.ord)().is_some() {
310 Some(|a, b| {
311 let ord_fn = unsafe { transmute::<CmpFn, CmpFnTyped<T>>((T::VTABLE.ord)().unwrap()) };
312 ord_fn(*a, *b)
313 })
314 } else {
315 None
316 }
317 })
318 .hash(|| {
319 if (T::VTABLE.hash)().is_some() {
320 Some(|value, hasher_this, hasher_write_fn| {
321 let hash_fn = unsafe { transmute::<HashFn, HashFnTyped<T>>((T::VTABLE.hash)().unwrap()) };
322 hash_fn(*value, hasher_this, hasher_write_fn)
323 })
324 } else {
325 None
326 }
327 })
328 }
329 => Reference, true
330);
331
332#[cfg(test)]
333mod test {
334 use core::panic::{RefUnwindSafe, UnwindSafe};
335 use impls::impls;
336
337 #[allow(unused)]
338 const fn assert_impls_unwind_safe<T: UnwindSafe>() {}
339 #[allow(unused)]
340 const fn assert_impls_ref_unwind_safe<T: RefUnwindSafe>() {}
341
342 #[allow(unused)]
343 const fn ref_unwind_safe<T: RefUnwindSafe>() {
344 assert_impls_unwind_safe::<&T>();
345 assert_impls_ref_unwind_safe::<&T>();
346
347 assert_impls_ref_unwind_safe::<&mut T>();
348
349 assert_impls_unwind_safe::<*const T>();
350 assert_impls_ref_unwind_safe::<*const T>();
351
352 assert_impls_unwind_safe::<*mut T>();
353 assert_impls_ref_unwind_safe::<*mut T>();
354 }
355
356 #[test]
357 fn mut_ref_not_unwind_safe() {
358 assert!(impls!(&mut (): !UnwindSafe));
359 }
360}