Skip to main content

clack_common/factory/
raw.rs

1use std::any::type_name;
2use std::fmt::Debug;
3use std::marker::PhantomData;
4use std::ptr::NonNull;
5
6/// A low-level utility used to implement custom [`Factory`] pointer types.
7///
8/// This is a pointer type that allows read-only access to the pointed data, except that it does
9/// not deal with references or borrows. You cannot get a reference to the factory structure this
10/// points to, only [`get`] a copy of the factory structure.
11///
12/// This allows to more easily avoid violating Rust's strict [reference rules]. Instead, this type
13/// only needs the pointer to adhere to the [`ptr::read`] function's safety rules.
14///
15/// [`Factory`]: crate::factory::Factory
16/// [`get`]: Self::get
17/// [reference rules]: https://doc.rust-lang.org/std/ptr/index.html#pointer-to-reference-conversion
18/// [`ptr::read`]: core::ptr::read
19#[derive(Copy, Clone, Eq, PartialEq, Hash)]
20pub struct RawFactoryPointer<'a, T> {
21    inner: NonNull<T>,
22    _marker: PhantomData<&'a T>,
23}
24
25impl<'a, T> RawFactoryPointer<'a, T> {
26    /// Creates a new [`RawFactoryPointer`] from a shared reference to the factory data structure.
27    ///
28    /// The lifetime of this new pointer is tied to the lifetime of the given reference.
29    #[inline]
30    pub fn new(inner: &'a T) -> Self {
31        Self {
32            inner: inner.into(),
33            _marker: PhantomData,
34        }
35    }
36
37    /// Creates a new [`RawFactoryPointer`] from a [non-null](NonNull) pointer to the factory data
38    /// structure.
39    ///
40    /// # Safety
41    ///
42    /// Behavior is undefined if any of the following conditions are violated for the duration of
43    /// the `'a` lifetime:
44    ///
45    /// * `raw` must be [valid] for reads;
46    /// * `raw` must be properly aligned (even if `T` has size `0`);
47    /// * `raw` must point to a properly initialized value of type `T`;
48    /// * the memory `raw` points to must not be written to, it can only be read from.
49    ///
50    /// These requirements are similar to those of the [`ptr::read`] function, except this function
51    /// cannot cause UB if `T` is not [`Copy`].
52    /// This is because the only method on this type that actually performs a read,
53    /// [`get`](Self::get), checks this statically via a [`Copy`] bound.
54    ///
55    /// [valid]: core::ptr#safety
56    /// [`ptr::read`]: core::ptr::read
57    #[inline]
58    pub const unsafe fn from_raw(raw: NonNull<T>) -> Self {
59        Self {
60            inner: raw,
61            _marker: PhantomData,
62        }
63    }
64
65    /// Returns a [non-null](NonNull) pointer to the factory structure this pointer points to.
66    #[inline]
67    pub const fn as_raw(&self) -> NonNull<T> {
68        self.inner
69    }
70
71    /// Returns a raw pointer to the factory structure this pointer points to.
72    #[inline]
73    pub const fn as_ptr(&self) -> *mut T {
74        self.inner.as_ptr()
75    }
76}
77
78impl<T: Copy> RawFactoryPointer<'_, T> {
79    /// Reads this pointer to return a copy of the factory structure.
80    ///
81    /// This function is always safe to use.
82    #[inline]
83    pub fn get(&self) -> T {
84        // SAFETY: T is Copy, and this type guarantees the pointer is valid for reads for 'a
85        unsafe { self.inner.read() }
86    }
87}
88
89impl<T> Debug for RawFactoryPointer<'_, T> {
90    #[inline]
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        write!(f, "{} ({:p})", type_name::<T>(), self.inner)
93    }
94}
95
96// SAFETY: We are only using this pointer for reads, and the memory it points to should be read-only.
97unsafe impl<T: Send> Send for RawFactoryPointer<'_, T> {}
98// SAFETY: We are only using this pointer for reads, and the memory it points to should be read-only.
99unsafe impl<T: Sync> Sync for RawFactoryPointer<'_, T> {}