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}