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> {}