Skip to main content

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