Skip to main content

zr/
ptr.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use core::sync::atomic::{AtomicPtr, Ordering};
6
7/// Extension trait for references to obtain a mutable raw pointer.
8pub trait ToMutPtr {
9    /// The target type of the pointer.
10    type Target: ?Sized;
11
12    /// Casts the reference to a mutable raw pointer.
13    fn to_mut_ptr(&self) -> *mut Self::Target;
14}
15
16impl<T: ?Sized> ToMutPtr for T {
17    type Target = T;
18
19    #[inline(always)]
20    fn to_mut_ptr(&self) -> *mut T {
21        self as *const T as *mut T
22    }
23}
24
25/// An atomic pointer type which operates on `*const T`.
26///
27/// This type provides a typed wrapper around [`AtomicPtr`] that enforces `*const T`
28/// invariants throughout its API, avoiding the need for `cast_mut()` or manual
29/// pointer qualification casts at call sites.
30#[repr(transparent)]
31pub struct AtomicConstPtr<T> {
32    inner: AtomicPtr<T>,
33}
34
35impl<T> AtomicConstPtr<T> {
36    /// Creates a new `AtomicConstPtr` initialized with `ptr`.
37    #[inline]
38    pub const fn new(ptr: *const T) -> Self {
39        Self { inner: AtomicPtr::new(ptr.cast_mut()) }
40    }
41
42    /// Loads a value from the pointer with the specified memory ordering.
43    #[inline]
44    pub fn load(&self, order: Ordering) -> *const T {
45        self.inner.load(order).cast_const()
46    }
47
48    /// Stores a value into the pointer with the specified memory ordering.
49    #[inline]
50    pub fn store(&self, ptr: *const T, order: Ordering) {
51        self.inner.store(ptr.cast_mut(), order);
52    }
53
54    /// Stores a value into the pointer, returning the previous value.
55    #[inline]
56    pub fn swap(&self, ptr: *const T, order: Ordering) -> *const T {
57        self.inner.swap(ptr.cast_mut(), order).cast_const()
58    }
59
60    /// Stores a value into the pointer if the current value is the same as `current`.
61    ///
62    /// The return value is a result indicating whether the new value was written and
63    /// containing the previous value.
64    #[inline]
65    pub fn compare_exchange(
66        &self,
67        current: *const T,
68        new: *const T,
69        success: Ordering,
70        failure: Ordering,
71    ) -> Result<*const T, *const T> {
72        self.inner
73            .compare_exchange(current.cast_mut(), new.cast_mut(), success, failure)
74            .map(|p| p.cast_const())
75            .map_err(|p| p.cast_const())
76    }
77
78    /// Stores a value into the pointer if the current value is the same as `current`.
79    ///
80    /// Unlike [`compare_exchange`], this function is allowed to spuriously fail.
81    #[inline]
82    pub fn compare_exchange_weak(
83        &self,
84        current: *const T,
85        new: *const T,
86        success: Ordering,
87        failure: Ordering,
88    ) -> Result<*const T, *const T> {
89        self.inner
90            .compare_exchange_weak(current.cast_mut(), new.cast_mut(), success, failure)
91            .map(|p| p.cast_const())
92            .map_err(|p| p.cast_const())
93    }
94
95    /// Fetches the value, and applies a function to it that returns an optional new value. Returns
96    /// a `Result` of `Ok(previous_value)` if the function returned `Some(_)`, else
97    /// `Err(previous_value)`.
98    #[inline]
99    pub fn try_update<F>(
100        &self,
101        set_order: Ordering,
102        fetch_order: Ordering,
103        mut f: F,
104    ) -> Result<*const T, *const T>
105    where
106        F: FnMut(*const T) -> Option<*const T>,
107    {
108        self.inner
109            .try_update(set_order, fetch_order, |p| f(p.cast_const()).map(|c| c.cast_mut()))
110            .map(|p| p.cast_const())
111            .map_err(|p| p.cast_const())
112    }
113
114    /// Consumes the atomic pointer, returning the underlying raw pointer.
115    #[inline]
116    pub fn into_inner(self) -> *const T {
117        self.inner.into_inner().cast_const()
118    }
119}
120
121impl<T> core::fmt::Debug for AtomicConstPtr<T> {
122    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
123        f.debug_tuple("AtomicConstPtr").field(&self.load(Ordering::Relaxed)).finish()
124    }
125}
126
127impl<T> core::fmt::Pointer for AtomicConstPtr<T> {
128    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
129        core::fmt::Pointer::fmt(&self.load(Ordering::Relaxed), f)
130    }
131}
132
133impl<T> Default for AtomicConstPtr<T> {
134    #[inline]
135    fn default() -> Self {
136        Self::new(core::ptr::null())
137    }
138}
139
140impl<T> From<*const T> for AtomicConstPtr<T> {
141    #[inline]
142    fn from(ptr: *const T) -> Self {
143        Self::new(ptr)
144    }
145}
146
147/// Forms a slice from an FFI pointer and a length, returning an empty slice `&[]` when `len == 0`
148/// even if `data` is null or misaligned.
149///
150/// # Safety
151///
152/// If `len > 0`, `data` must satisfy the safety requirements of [`core::slice::from_raw_parts`]:
153/// it must be non-null, valid for reads for `len * mem::size_of::<T>()` many bytes, properly
154/// aligned, and point to `len` consecutive properly initialized values of type `T` that are not
155/// mutated for the duration of lifetime `'a`.
156#[inline]
157pub const unsafe fn slice_from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
158    if len == 0 {
159        &[]
160    } else {
161        // SAFETY: `len > 0`, and the caller guarantees `data` is valid for `len` elements.
162        unsafe { core::slice::from_raw_parts(data, len) }
163    }
164}
165
166/// Performs the same functionality as [`slice_from_raw_parts`], except that a mutable slice is
167/// returned.
168///
169/// # Safety
170///
171/// If `len > 0`, `data` must satisfy the safety requirements of
172/// [`core::slice::from_raw_parts_mut`]: it must be non-null, valid for both reads and writes for
173/// `len * mem::size_of::<T>()` many bytes, properly aligned, and point to `len` consecutive
174/// properly initialized values of type `T` not accessed through any other pointer for the duration
175/// of lifetime `'a`.
176#[inline]
177pub const unsafe fn slice_from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
178    if len == 0 {
179        &mut []
180    } else {
181        // SAFETY: `len > 0`, and the caller guarantees `data` is uniquely valid for `len` elements.
182        unsafe { core::slice::from_raw_parts_mut(data, len) }
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[test]
191    fn test_slice_from_raw_parts_zero_length() {
192        let empty: &[u32] = unsafe { slice_from_raw_parts(core::ptr::null(), 0) };
193        assert!(empty.is_empty());
194
195        let empty_mut: &mut [u32] = unsafe { slice_from_raw_parts_mut(core::ptr::null_mut(), 0) };
196        assert!(empty_mut.is_empty());
197    }
198
199    #[test]
200    fn test_slice_from_raw_parts_non_empty() {
201        let mut arr = [10u32, 20, 30];
202        let s = unsafe { slice_from_raw_parts(arr.as_ptr(), arr.len()) };
203        assert_eq!(s, &[10, 20, 30]);
204
205        let s_mut = unsafe { slice_from_raw_parts_mut(arr.as_mut_ptr(), arr.len()) };
206        s_mut[1] = 25;
207        assert_eq!(arr, [10, 25, 30]);
208    }
209
210    #[test]
211    fn test_atomic_const_ptr_basic() {
212        static DUMMY: u32 = 42;
213        static DUMMY2: u32 = 99;
214
215        let ptr = AtomicConstPtr::new(&DUMMY as *const u32);
216        assert_eq!(ptr.load(Ordering::SeqCst), &DUMMY as *const u32);
217
218        ptr.store(&DUMMY2 as *const u32, Ordering::SeqCst);
219        assert_eq!(ptr.load(Ordering::SeqCst), &DUMMY2 as *const u32);
220
221        let old = ptr.swap(&DUMMY as *const u32, Ordering::SeqCst);
222        assert_eq!(old, &DUMMY2 as *const u32);
223        assert_eq!(ptr.load(Ordering::SeqCst), &DUMMY as *const u32);
224
225        let res = ptr.compare_exchange(
226            &DUMMY as *const u32,
227            &DUMMY2 as *const u32,
228            Ordering::SeqCst,
229            Ordering::SeqCst,
230        );
231        assert_eq!(res, Ok(&DUMMY as *const u32));
232        assert_eq!(ptr.load(Ordering::SeqCst), &DUMMY2 as *const u32);
233
234        let update_res = ptr.try_update(Ordering::SeqCst, Ordering::SeqCst, |p| {
235            if p == &DUMMY2 as *const u32 { Some(&DUMMY as *const u32) } else { None }
236        });
237        assert_eq!(update_res, Ok(&DUMMY2 as *const u32));
238        assert_eq!(ptr.load(Ordering::SeqCst), &DUMMY as *const u32);
239
240        let default_ptr: AtomicConstPtr<u32> = AtomicConstPtr::default();
241        assert!(default_ptr.load(Ordering::Relaxed).is_null());
242    }
243}