Skip to main content

value_box/
borrowed.rs

1use std::any::{Any, type_name};
2use std::ffi::c_void;
3use std::ptr::NonNull;
4
5use crate::erased::ErasedBorrowedPtr;
6use crate::{BoxerError, Result};
7
8#[repr(transparent)]
9pub struct BorrowedPtr<T: Any> {
10    ptr: *mut T,
11}
12
13impl<T: Any> BorrowedPtr<T> {
14    pub fn from_ref(value: &T) -> Self {
15        Self {
16            ptr: (value as *const T).cast_mut(),
17        }
18    }
19
20    pub fn from_mut(value: &mut T) -> Self {
21        Self {
22            ptr: value as *mut T,
23        }
24    }
25
26    /// # Safety
27    ///
28    /// `ptr` must be either null or point to a valid `T` for the duration of
29    /// any borrowing operations performed through this wrapper.
30    pub const unsafe fn from_raw(ptr: *mut T) -> Self {
31        Self { ptr }
32    }
33
34    pub const fn null() -> Self {
35        Self {
36            ptr: std::ptr::null_mut(),
37        }
38    }
39
40    pub const fn as_raw(&self) -> *mut T {
41        self.ptr
42    }
43
44    /// Erase the pointee type while preserving the same borrowed-pointer contract.
45    ///
46    /// The returned [`ErasedBorrowedPtr`] points to the same allocation as this
47    /// `BorrowedPtr<T>`, but without the concrete `T`.
48    ///
49    /// # Invariants
50    ///
51    /// - The erased pointer is valid for at most the same duration as this
52    ///   `BorrowedPtr<T>`.
53    /// - Erasing the type does not extend the lifetime of the underlying value.
54    /// - The erased pointer does not carry ownership and must not be used after
55    ///   the original borrowed pointer would no longer be valid.
56    pub fn erase(&self) -> ErasedBorrowedPtr {
57        unsafe { ErasedBorrowedPtr::from_raw(self.ptr.cast()) }
58    }
59
60    pub fn is_null(&self) -> bool {
61        self.ptr.is_null()
62    }
63
64    pub fn with_ref<R: Any, F>(&self, op: F) -> Result<R>
65    where
66        F: FnOnce(&T) -> Result<R>,
67    {
68        let pointer = self.non_null()?;
69        unsafe { op(pointer.as_ref()) }
70    }
71
72    pub fn with_option_ref<R: Any, F>(&self, op: F) -> Result<R>
73    where
74        F: FnOnce(Option<&T>) -> Result<R>,
75    {
76        if !self.is_null() {
77            self.with_ref(|value| op(Some(value)))
78        } else {
79            op(None)
80        }
81    }
82
83    pub fn with_ref_ok<R: Any, F>(&self, op: F) -> Result<R>
84    where
85        F: FnOnce(&T) -> R,
86    {
87        self.with_ref(|value| Ok(op(value)))
88    }
89
90    pub fn with_mut<R: Any, F>(&mut self, op: F) -> Result<R>
91    where
92        F: FnOnce(&mut T) -> Result<R>,
93    {
94        let mut pointer = self.non_null()?;
95        unsafe { op(pointer.as_mut()) }
96    }
97
98    pub fn with_mut_ok<R: Any, F>(&mut self, op: F) -> Result<R>
99    where
100        F: FnOnce(&mut T) -> R,
101    {
102        self.with_mut(|value| Ok(op(value)))
103    }
104
105    pub fn with_clone<R: Any, F>(&self, op: F) -> Result<R>
106    where
107        F: FnOnce(T) -> Result<R>,
108        T: Clone,
109    {
110        self.with_ref(|value| op(value.clone()))
111    }
112
113    pub fn with_clone_ok<R: Any, F>(&self, op: F) -> Result<R>
114    where
115        F: FnOnce(T) -> R,
116        T: Clone,
117    {
118        self.with_clone(|value| Ok(op(value)))
119    }
120
121    pub fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
122    where
123        F: FnOnce(NonNull<c_void>) -> Result<R>,
124    {
125        let pointer = self.non_null()?.cast::<c_void>();
126        op(pointer)
127    }
128
129    pub fn with_ptr_ok<R: Any, F>(&self, op: F) -> Result<R>
130    where
131        F: FnOnce(NonNull<c_void>) -> R,
132    {
133        self.with_ptr(|pointer| Ok(op(pointer)))
134    }
135
136    pub fn with_ref_ref<R: Any, F, P: Any>(&self, ptr: &BorrowedPtr<P>, op: F) -> Result<R>
137    where
138        F: FnOnce(&T, &P) -> Result<R>,
139    {
140        self.with_ref(|t| ptr.with_ref(|p| op(t, p)))
141    }
142
143    pub fn with_ref_ref_ref<R: Any, F, P1: Any, P2: Any>(
144        &self,
145        ptr1: &BorrowedPtr<P1>,
146        ptr2: &BorrowedPtr<P2>,
147        op: F,
148    ) -> Result<R>
149    where
150        F: FnOnce(&T, &P1, &P2) -> Result<R>,
151    {
152        self.with_ref(|t| ptr1.with_ref(|p1| ptr2.with_ref(|p2| op(t, p1, p2))))
153    }
154
155    pub fn with_ref_ref_ref_ref<R: Any, F, P1: Any, P2: Any, P3: Any>(
156        &self,
157        ptr1: &BorrowedPtr<P1>,
158        ptr2: &BorrowedPtr<P2>,
159        ptr3: &BorrowedPtr<P3>,
160        op: F,
161    ) -> Result<R>
162    where
163        F: FnOnce(&T, &P1, &P2, &P3) -> Result<R>,
164    {
165        self.with_ref(|t| {
166            ptr1.with_ref(|p1| ptr2.with_ref(|p2| ptr3.with_ref(|p3| op(t, p1, p2, p3))))
167        })
168    }
169
170    fn non_null(&self) -> Result<NonNull<T>> {
171        NonNull::new(self.ptr).ok_or_else(|| BoxerError::NullPointer(type_name::<T>().to_string()))
172    }
173}
174
175impl<T: Any> Default for BorrowedPtr<T> {
176    fn default() -> Self {
177        Self::null()
178    }
179}