facet_core/impls_core/
pointer.rs

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
86// *const pointers
87impl_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                // https://github.com/rust-lang/rust/issues/141510
108                #[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
123// *mut pointers
124impl_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                // https://github.com/rust-lang/rust/issues/141510
145                #[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
160// &T references
161impl_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
245// &mut T references
246impl_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}