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                parse_bytes: None,
132                try_from: None,
133                try_into_inner: None,
134                try_borrow_inner: None,
135                partial_eq: Some(const_ptr_partial_eq::<T>),
136                partial_cmp: Some(const_ptr_partial_cmp::<T>),
137                cmp: Some(const_ptr_cmp::<T>),
138            }
139        }
140
141        const fn build_const_ptr_type_ops<T: ?Sized>() -> TypeOpsIndirect {
142            TypeOpsIndirect {
143                drop_in_place: const_ptr_drop::<T>,
144                default_in_place: None,
145                clone_into: Some(const_ptr_clone::<T>),
146                is_truthy: None,
147            }
148        }
149
150        ShapeBuilder::for_sized::<*const T>("*const T")
151            .ty({
152                let is_wide = ::core::mem::size_of::<Self>() != ::core::mem::size_of::<*const ()>();
153                let vpt = ValuePointerType {
154                    mutable: false,
155                    wide: is_wide,
156                    target: T::SHAPE,
157                };
158                Type::Pointer(PointerType::Raw(vpt))
159            })
160            .def(Def::Scalar)
161            .type_params(&[TypeParam {
162                name: "T",
163                shape: T::SHAPE,
164            }])
165            .inner(T::SHAPE)
166            .vtable_indirect(&const { build_const_ptr_vtable::<T>() })
167            .type_ops_indirect(&const { build_const_ptr_type_ops::<T>() })
168            .eq()
169            .copy()
170            .build()
171    };
172}
173
174// *mut pointers
175unsafe impl<'a, T: Facet<'a> + ?Sized> Facet<'a> for *mut T {
176    const SHAPE: &'static Shape = &const {
177        const fn build_mut_ptr_vtable<'a, T: Facet<'a> + ?Sized>() -> VTableIndirect {
178            VTableIndirect {
179                display: None,
180                debug: Some(mut_ptr_debug::<T>),
181                hash: Some(mut_ptr_hash::<T>),
182                invariants: None,
183                parse: None,
184                parse_bytes: None,
185                try_from: None,
186                try_into_inner: None,
187                try_borrow_inner: None,
188                partial_eq: Some(mut_ptr_partial_eq::<T>),
189                partial_cmp: Some(mut_ptr_partial_cmp::<T>),
190                cmp: Some(mut_ptr_cmp::<T>),
191            }
192        }
193
194        const fn build_mut_ptr_type_ops<T: ?Sized>() -> TypeOpsIndirect {
195            TypeOpsIndirect {
196                drop_in_place: mut_ptr_drop::<T>,
197                default_in_place: None,
198                clone_into: Some(mut_ptr_clone::<T>),
199                is_truthy: None,
200            }
201        }
202
203        ShapeBuilder::for_sized::<*mut T>("*mut T")
204            .ty({
205                let is_wide = ::core::mem::size_of::<Self>() != ::core::mem::size_of::<*const ()>();
206                let vpt = ValuePointerType {
207                    mutable: true,
208                    wide: is_wide,
209                    target: T::SHAPE,
210                };
211                Type::Pointer(PointerType::Raw(vpt))
212            })
213            .def(Def::Scalar)
214            .type_params(&[TypeParam {
215                name: "T",
216                shape: T::SHAPE,
217            }])
218            .inner(T::SHAPE)
219            .vtable_indirect(&const { build_mut_ptr_vtable::<T>() })
220            .type_ops_indirect(&const { build_mut_ptr_type_ops::<T>() })
221            // *mut T is invariant in T
222            .variance(Variance::INVARIANT)
223            .eq()
224            .copy()
225            .build()
226    };
227}
228
229#[cfg(test)]
230mod test {
231    use core::panic::{RefUnwindSafe, UnwindSafe};
232
233    #[cfg(feature = "auto-traits")]
234    use impls::impls;
235
236    #[allow(unused)]
237    const fn assert_impls_unwind_safe<T: UnwindSafe>() {}
238    #[allow(unused)]
239    const fn assert_impls_ref_unwind_safe<T: RefUnwindSafe>() {}
240
241    #[allow(unused)]
242    const fn ref_unwind_safe<T: RefUnwindSafe>() {
243        assert_impls_unwind_safe::<&T>();
244        assert_impls_ref_unwind_safe::<&T>();
245
246        assert_impls_ref_unwind_safe::<&mut T>();
247
248        assert_impls_unwind_safe::<*const T>();
249        assert_impls_ref_unwind_safe::<*const T>();
250
251        assert_impls_unwind_safe::<*mut T>();
252        assert_impls_ref_unwind_safe::<*mut T>();
253    }
254
255    #[test]
256    #[cfg(feature = "auto-traits")]
257    fn mut_ref_not_unwind_safe() {
258        assert!(impls!(&mut (): !UnwindSafe));
259    }
260}