Skip to main content

ptrait/
lib.rs

1#![no_std]
2#![cfg_attr(feature = "meta", feature(ptr_metadata))]
3#![warn(clippy::pedantic)]
4
5use core::ptr::NonNull;
6
7#[cfg(feature = "non_null_const")]
8use non_null_const::NonNullConst;
9
10#[cfg(feature = "meta")]
11use core::ptr::Pointee;
12
13mod non_null;
14mod null;
15pub use null::*;
16#[cfg(feature = "alloc")]
17mod alloc;
18mod other;
19mod raw;
20mod r#ref;
21
22#[inline]
23#[must_use]
24fn is_valid_ref<P: Ptr + ?Sized>(ptr: &P) -> bool
25where
26    P::Target: Sized,
27{
28    !ptr.is_null() && ptr.is_aligned()
29}
30
31cfg_tt::cfg_tt! {
32    /// Common abstraction for pointer-like types.
33    pub trait Ptr {
34        /// The type of the value pointed to by this pointer.
35        type Target: ?Sized #[cfg(feature = "meta")](+ Pointee);
36
37        /// Returns a raw const pointer to the pointee.
38        #[must_use]
39        fn as_ptr(&self) -> *const Self::Target;
40
41        /// Returns the address of the pointer as a [`usize`].
42        #[inline]
43        #[must_use]
44        fn addr(&self) -> usize {
45            self.as_ptr().addr()
46        }
47
48        /// Returns `true` if the pointer is null.
49        #[inline]
50        #[must_use]
51        fn is_null(&self) -> bool {
52            self.as_ptr().is_null()
53        }
54
55        /// Returns `true` if the pointer is properly aligned for its pointee type.
56        #[inline]
57        #[must_use]
58        fn is_aligned(&self) -> bool
59        where
60            Self::Target: Sized,
61        {
62            self.as_ptr().is_aligned()
63        }
64
65        /// Converts to [`Option<&Target>`].
66        /// Returns [`None`] if the pointer is null or unaligned.
67        ///
68        /// # Safety
69        /// The pointer must be valid for the lifetime `'a`.
70        #[inline]
71        #[must_use]
72        unsafe fn as_ref<'a>(&self) -> Option<&'a Self::Target>
73        where
74            Self::Target: Sized,
75        {
76            is_valid_ref(self).then(|| unsafe { self.as_ref_unchecked() })
77        }
78
79        /// Converts to [`Option<&Target>`].
80        ///
81        /// # Safety
82        /// The pointer must be non-null, properly aligned and valid for the lifetime `'a`.
83        #[inline]
84        #[must_use]
85        unsafe fn as_ref_unchecked<'a>(&self) -> &'a Self::Target {
86            unsafe { &*self.as_ptr() }
87        }
88    }
89}
90
91/// Pointer-like types that permit mutable access.
92pub trait PtrMut: Ptr {
93    /// Returns a raw mutable pointer to the pointee.
94    #[must_use]
95    fn as_mut_ptr(&mut self) -> *mut Self::Target;
96
97    /// Converts to [`Option<&mut Target>`].
98    /// Returns [`None`] if the pointer is null or unaligned.
99    ///
100    /// # Safety
101    /// The pointer must be valid for the lifetime `'a`.
102    #[inline]
103    #[must_use]
104    unsafe fn as_mut<'a>(&mut self) -> Option<&'a mut Self::Target>
105    where
106        Self::Target: Sized,
107    {
108        is_valid_ref(self).then(|| unsafe { self.as_mut_unchecked() })
109    }
110
111    /// Converts to [`Option<&mut Target>`].
112    ///
113    /// # Safety
114    /// The pointer must be non-null, properly aligned and valid for the lifetime `'a`.
115    #[inline]
116    #[must_use]
117    unsafe fn as_mut_unchecked<'a>(&mut self) -> &'a mut Self::Target {
118        unsafe { &mut *self.as_mut_ptr() }
119    }
120}
121
122/// Marker trait identifying raw pointers.
123pub trait RawPtr: Ptr + Sized + Copy {
124    #[inline]
125    #[must_use]
126    fn cast<U>(self) -> *const U {
127        self.as_ptr().cast()
128    }
129
130    #[inline]
131    #[must_use]
132    fn cast_mut(self) -> *mut Self::Target {
133        self.as_ptr().cast_mut()
134    }
135}
136
137/// Marker trait identifying raw mut pointers.
138pub trait RawMutPtr: PtrMut + Sized + Copy {
139    #[inline]
140    #[must_use]
141    fn cast<U>(mut self) -> *mut U {
142        self.as_mut_ptr().cast()
143    }
144
145    #[inline]
146    #[must_use]
147    fn cast_const(mut self) -> *const Self::Target {
148        self.as_mut_ptr().cast_const()
149    }
150}
151
152/// Marker trait identifying pointer-like types that are non-null by construction.
153///
154/// # Safety
155/// Implementors must guarantee that [`as_ptr()`](Ptr::as_ptr) always returns a non-null pointer.
156pub unsafe trait NonNullPtr: Ptr {
157    #[cfg(feature = "non_null_const")]
158    #[inline]
159    #[must_use]
160    /// Returns the pointer value as a [`NonNullConst`].
161    fn as_non_null_const(&self) -> NonNullConst<Self::Target> {
162        let ptr = self.as_ptr();
163        unsafe { NonNullConst::new_unchecked(ptr) }
164    }
165}
166
167/// Non-null pointer-like types with mutable access.
168///
169/// # Safety
170/// Implementors must guarantee that [`as_ptr()`](Ptr::as_ptr) always returns a non-null pointer.
171pub unsafe trait NonNullMutPtr: PtrMut + NonNullPtr {
172    /// Returns the pointer value as a [`NonNull`].
173    #[inline]
174    #[must_use]
175    fn as_non_null(&mut self) -> NonNull<Self::Target> {
176        let ptr = self.as_mut_ptr();
177        unsafe { NonNull::new_unchecked(ptr) }
178    }
179}