facet_core/impls/core/
pointer.rs

1//! Facet implementation for raw pointers (*const T, *mut T)
2
3use core::cmp::Ordering;
4use core::hash::Hash;
5
6use crate::{
7    Def, Facet, HashProxy, OxPtrConst, OxPtrMut, PointerType, Shape, ShapeBuilder, Type,
8    TypeOpsIndirect, TypeParam, VTableIndirect, ValuePointerType, Variance,
9};
10
11// For raw pointers, we use indirect vtable since they're generic over T
12// However, they're scalars so the implementations are simple
13
14/// Debug for *const T
15unsafe fn const_ptr_debug<T: ?Sized>(
16    ox: OxPtrConst,
17    f: &mut core::fmt::Formatter<'_>,
18) -> Option<core::fmt::Result> {
19    let p = unsafe { ox.ptr().get::<*const T>() };
20    Some(core::fmt::Debug::fmt(&p, f))
21}
22
23/// Hash for *const T
24unsafe fn const_ptr_hash<T: ?Sized>(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
25    let p = unsafe { ox.ptr().get::<*const T>() };
26    p.hash(hasher);
27    Some(())
28}
29
30/// PartialEq for *const T
31#[allow(ambiguous_wide_pointer_comparisons)]
32unsafe fn const_ptr_partial_eq<T: ?Sized>(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
33    let a_val = unsafe { a.ptr().get::<*const T>() };
34    let b_val = unsafe { b.ptr().get::<*const T>() };
35    Some(*a_val == *b_val)
36}
37
38/// PartialOrd for *const T
39#[allow(ambiguous_wide_pointer_comparisons)]
40unsafe fn const_ptr_partial_cmp<T: ?Sized>(
41    a: OxPtrConst,
42    b: OxPtrConst,
43) -> Option<Option<Ordering>> {
44    let a_val = unsafe { a.ptr().get::<*const T>() };
45    let b_val = unsafe { b.ptr().get::<*const T>() };
46    Some(a_val.partial_cmp(b_val))
47}
48
49/// Ord for *const T
50#[allow(ambiguous_wide_pointer_comparisons)]
51unsafe fn const_ptr_cmp<T: ?Sized>(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
52    let a_val = unsafe { a.ptr().get::<*const T>() };
53    let b_val = unsafe { b.ptr().get::<*const T>() };
54    Some(a_val.cmp(b_val))
55}
56
57/// Drop for *const T (no-op, pointers don't need dropping)
58unsafe fn const_ptr_drop<T: ?Sized>(_ptr: OxPtrMut) {
59    // Pointers don't need dropping
60}
61
62/// Clone for *const T (Copy types can be cloned by copying)
63unsafe fn const_ptr_clone<T: ?Sized>(src: OxPtrConst, dst: OxPtrMut) {
64    let src_val = unsafe { src.ptr().get::<*const T>() };
65    let dst_ptr = unsafe { dst.ptr().as_mut::<*const T>() };
66    *dst_ptr = *src_val;
67}
68
69/// Debug for *mut T
70unsafe fn mut_ptr_debug<T: ?Sized>(
71    ox: OxPtrConst,
72    f: &mut core::fmt::Formatter<'_>,
73) -> Option<core::fmt::Result> {
74    let p = unsafe { ox.ptr().get::<*mut T>() };
75    Some(core::fmt::Debug::fmt(&p, f))
76}
77
78/// Hash for *mut T
79unsafe fn mut_ptr_hash<T: ?Sized>(ox: OxPtrConst, hasher: &mut HashProxy<'_>) -> Option<()> {
80    let p = unsafe { ox.ptr().get::<*mut T>() };
81    p.hash(hasher);
82    Some(())
83}
84
85/// PartialEq for *mut T
86#[allow(ambiguous_wide_pointer_comparisons)]
87unsafe fn mut_ptr_partial_eq<T: ?Sized>(a: OxPtrConst, b: OxPtrConst) -> Option<bool> {
88    let a_val = unsafe { a.ptr().get::<*mut T>() };
89    let b_val = unsafe { b.ptr().get::<*mut T>() };
90    Some(*a_val == *b_val)
91}
92
93/// PartialOrd for *mut T
94#[allow(ambiguous_wide_pointer_comparisons)]
95unsafe fn mut_ptr_partial_cmp<T: ?Sized>(a: OxPtrConst, b: OxPtrConst) -> Option<Option<Ordering>> {
96    let a_val = unsafe { a.ptr().get::<*mut T>() };
97    let b_val = unsafe { b.ptr().get::<*mut T>() };
98    Some(a_val.partial_cmp(b_val))
99}
100
101/// Ord for *mut T
102#[allow(ambiguous_wide_pointer_comparisons)]
103unsafe fn mut_ptr_cmp<T: ?Sized>(a: OxPtrConst, b: OxPtrConst) -> Option<Ordering> {
104    let a_val = unsafe { a.ptr().get::<*mut T>() };
105    let b_val = unsafe { b.ptr().get::<*mut T>() };
106    Some(a_val.cmp(b_val))
107}
108
109/// Drop for *mut T (no-op, pointers don't need dropping)
110unsafe fn mut_ptr_drop<T: ?Sized>(_ptr: OxPtrMut) {
111    // Pointers don't need dropping
112}
113
114/// Clone for *mut T (Copy types can be cloned by copying)
115unsafe fn mut_ptr_clone<T: ?Sized>(src: OxPtrConst, dst: OxPtrMut) {
116    let src_val = unsafe { src.ptr().get::<*mut T>() };
117    let dst_ptr = unsafe { dst.ptr().as_mut::<*mut T>() };
118    *dst_ptr = *src_val;
119}
120
121// *const pointers
122unsafe impl<'a, T: Facet<'a> + ?Sized> Facet<'a> for *const T {
123    const SHAPE: &'static Shape = &const {
124        const fn build_const_ptr_vtable<'a, T: Facet<'a> + ?Sized>() -> VTableIndirect {
125            VTableIndirect {
126                display: None,
127                debug: Some(const_ptr_debug::<T>),
128                hash: Some(const_ptr_hash::<T>),
129                invariants: None,
130                parse: None,
131                try_from: None,
132                try_into_inner: None,
133                try_borrow_inner: None,
134                partial_eq: Some(const_ptr_partial_eq::<T>),
135                partial_cmp: Some(const_ptr_partial_cmp::<T>),
136                cmp: Some(const_ptr_cmp::<T>),
137            }
138        }
139
140        const fn build_const_ptr_type_ops<T: ?Sized>() -> TypeOpsIndirect {
141            TypeOpsIndirect {
142                drop_in_place: const_ptr_drop::<T>,
143                default_in_place: None,
144                clone_into: Some(const_ptr_clone::<T>),
145                is_truthy: None,
146            }
147        }
148
149        ShapeBuilder::for_sized::<*const T>("*const T")
150            .ty({
151                let is_wide = ::core::mem::size_of::<Self>() != ::core::mem::size_of::<*const ()>();
152                let vpt = ValuePointerType {
153                    mutable: false,
154                    wide: is_wide,
155                    target: T::SHAPE,
156                };
157                Type::Pointer(PointerType::Raw(vpt))
158            })
159            .def(Def::Scalar)
160            .type_params(&[TypeParam {
161                name: "T",
162                shape: T::SHAPE,
163            }])
164            .inner(T::SHAPE)
165            .vtable_indirect(&const { build_const_ptr_vtable::<T>() })
166            .type_ops_indirect(&const { build_const_ptr_type_ops::<T>() })
167            .eq()
168            .copy()
169            .build()
170    };
171}
172
173// *mut pointers
174unsafe impl<'a, T: Facet<'a> + ?Sized> Facet<'a> for *mut T {
175    const SHAPE: &'static Shape = &const {
176        const fn build_mut_ptr_vtable<'a, T: Facet<'a> + ?Sized>() -> VTableIndirect {
177            VTableIndirect {
178                display: None,
179                debug: Some(mut_ptr_debug::<T>),
180                hash: Some(mut_ptr_hash::<T>),
181                invariants: None,
182                parse: None,
183                try_from: None,
184                try_into_inner: None,
185                try_borrow_inner: None,
186                partial_eq: Some(mut_ptr_partial_eq::<T>),
187                partial_cmp: Some(mut_ptr_partial_cmp::<T>),
188                cmp: Some(mut_ptr_cmp::<T>),
189            }
190        }
191
192        const fn build_mut_ptr_type_ops<T: ?Sized>() -> TypeOpsIndirect {
193            TypeOpsIndirect {
194                drop_in_place: mut_ptr_drop::<T>,
195                default_in_place: None,
196                clone_into: Some(mut_ptr_clone::<T>),
197                is_truthy: None,
198            }
199        }
200
201        ShapeBuilder::for_sized::<*mut T>("*mut T")
202            .ty({
203                let is_wide = ::core::mem::size_of::<Self>() != ::core::mem::size_of::<*const ()>();
204                let vpt = ValuePointerType {
205                    mutable: true,
206                    wide: is_wide,
207                    target: T::SHAPE,
208                };
209                Type::Pointer(PointerType::Raw(vpt))
210            })
211            .def(Def::Scalar)
212            .type_params(&[TypeParam {
213                name: "T",
214                shape: T::SHAPE,
215            }])
216            .inner(T::SHAPE)
217            .vtable_indirect(&const { build_mut_ptr_vtable::<T>() })
218            .type_ops_indirect(&const { build_mut_ptr_type_ops::<T>() })
219            // *mut T is invariant in T
220            .variance(Variance::INVARIANT)
221            .eq()
222            .copy()
223            .build()
224    };
225}
226
227#[cfg(test)]
228mod test {
229    use core::panic::{RefUnwindSafe, UnwindSafe};
230
231    #[cfg(feature = "auto-traits")]
232    use impls::impls;
233
234    #[allow(unused)]
235    const fn assert_impls_unwind_safe<T: UnwindSafe>() {}
236    #[allow(unused)]
237    const fn assert_impls_ref_unwind_safe<T: RefUnwindSafe>() {}
238
239    #[allow(unused)]
240    const fn ref_unwind_safe<T: RefUnwindSafe>() {
241        assert_impls_unwind_safe::<&T>();
242        assert_impls_ref_unwind_safe::<&T>();
243
244        assert_impls_ref_unwind_safe::<&mut T>();
245
246        assert_impls_unwind_safe::<*const T>();
247        assert_impls_ref_unwind_safe::<*const T>();
248
249        assert_impls_unwind_safe::<*mut T>();
250        assert_impls_ref_unwind_safe::<*mut T>();
251    }
252
253    #[test]
254    #[cfg(feature = "auto-traits")]
255    fn mut_ref_not_unwind_safe() {
256        assert!(impls!(&mut (): !UnwindSafe));
257    }
258}