dynode/
opaque.rs

1use core::{
2    marker::PhantomData,
3    ptr::{NonNull, Pointee},
4};
5
6use crate::NodePtr;
7
8#[repr(transparent)]
9/// A pointer to a node with an abstracted header type and a possibly unsized value.
10///
11/// These must be allocated and deallocated as [`NodePtr`]s.
12/// ```rust
13/// # use dynode::{NodePtr, HeaderOpaqueNodePtr};
14/// # type Header = ();
15/// # type T = ();
16/// let node: NodePtr<Header, T> = NodePtr::allocate_sized();
17/// let opaque: HeaderOpaqueNodePtr<T> = node.to_header_opaque();
18/// let node: NodePtr<Header, T> = unsafe { opaque.to_transparent() };
19/// unsafe { node.deallocate_global() };
20/// ```
21pub struct HeaderOpaqueNodePtr<U>
22where
23    U: ?Sized,
24{
25    mid: NonNull<()>,
26    _phantom: PhantomData<*mut U>,
27}
28
29impl<U> Clone for HeaderOpaqueNodePtr<U>
30where
31    U: ?Sized,
32{
33    fn clone(&self) -> Self {
34        *self
35    }
36}
37impl<U> Copy for HeaderOpaqueNodePtr<U> where U: ?Sized {}
38
39impl<U> HeaderOpaqueNodePtr<U>
40where
41    U: ?Sized,
42{
43    #[must_use]
44    #[inline]
45    /// Add a header type back into a node.
46    ///
47    /// # Safety
48    /// `Header` must be the same header type that the node was allocated with.
49    pub const unsafe fn to_transparent<Header>(self) -> NodePtr<Header, U> {
50        unsafe { NodePtr::from_value_ptr(self.mid) }
51    }
52
53    #[must_use]
54    /// Get the metadata of the node's data.
55    ///
56    /// # Safety
57    /// The node must have not been deallocated.
58    pub const unsafe fn metadata(self) -> <U as Pointee>::Metadata {
59        // SAFETY:
60        // `self.mid` is a pointer immediately after the metadata and in the same allocation, so
61        // subtracting the metadata's size will stay in the same allocation.
62        let ptr = unsafe { self.mid.byte_sub(size_of::<<U as Pointee>::Metadata>()) }.cast();
63        // SAFETY:
64        // For the same reasons as above, `ptr` is a pointer to the metadata.
65        // The allocation has not been deallocated (safety condition) and is therefore valid for
66        // reads.
67        unsafe { ptr.read() }
68    }
69
70    #[must_use]
71    #[inline]
72    /// Get the pointer to the node's value.
73    ///
74    /// This does not include any metadata.
75    /// See [`Self::data_ptr`] for a pointer with metadata.
76    pub const fn value_ptr(self) -> NonNull<()> {
77        self.mid
78    }
79
80    #[must_use]
81    #[inline]
82    /// Get a node back from its value pointer.
83    ///
84    /// # Safety
85    /// The value pointer must have come from a call to [`Self::value_ptr`].
86    pub const unsafe fn from_value_ptr(ptr: NonNull<()>) -> Self {
87        Self {
88            mid: ptr,
89            _phantom: PhantomData,
90        }
91    }
92
93    #[must_use]
94    #[inline]
95    /// Get the pointer to the node's data.
96    ///
97    /// # Safety
98    /// The node must not have been deallocated.
99    pub const unsafe fn data_ptr(self) -> NonNull<U> {
100        NonNull::from_raw_parts(
101            self.value_ptr(),
102            // SAFETY:
103            // The node has not been deallocated (safety condition).
104            unsafe { self.metadata() },
105        )
106    }
107}
108
109impl<Header, U> From<NodePtr<Header, U>> for HeaderOpaqueNodePtr<U>
110where
111    U: ?Sized,
112{
113    #[inline]
114    fn from(value: NodePtr<Header, U>) -> Self {
115        value.to_header_opaque()
116    }
117}