facet_core/impls_core/
pointer.rs

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