orx_selfref_col/references/node_idx.rs
1use super::NodePtr;
2use crate::{MemoryPolicy, MemoryState, Node, SelfRefCol, Variant};
3use core::fmt::Debug;
4use orx_pinned_vec::PinnedVec;
5
6/// A node index providing safe and constant time access to elements
7/// of the self referential collection.
8pub struct NodeIdx<V: Variant> {
9 ptr: *mut Node<V>,
10 state: MemoryState,
11}
12
13impl<V: Variant> core::hash::Hash for NodeIdx<V> {
14 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
15 self.ptr.hash(state);
16 self.state.hash(state);
17 }
18}
19
20// Only the pointer is copied, so "V" does not need to be copy itself.
21impl<V: Variant> Copy for NodeIdx<V> {}
22
23impl<V: Variant> Clone for NodeIdx<V> {
24 fn clone(&self) -> Self {
25 *self
26 }
27}
28
29// Despite holding pointer to a Node, `NodeIdx` implements `Send` since it does not provide access
30// to the pointer with the safe api. Unsafe api can be used to access the node. Safety of such access
31// can be verified by the `is_valid_for` method.
32unsafe impl<V: Variant> Send for NodeIdx<V> where V::Item: Send {}
33
34// Despite holding pointer to a Node, `NodeIdx` implements `Sync` since it does not provide access
35// to the pointer with the safe api. Unsafe api can be used to access the node. Safety of such access
36// can be verified by the `is_valid_for` method.
37unsafe impl<V: Variant> Sync for NodeIdx<V> where V::Item: Sync {}
38
39impl<V: Variant> Debug for NodeIdx<V> {
40 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
41 f.debug_struct("NodeIdx")
42 .field("ptr", &self.ptr)
43 .field("state", &self.state)
44 .finish()
45 }
46}
47
48impl<V: Variant> PartialEq for NodeIdx<V> {
49 fn eq(&self, other: &Self) -> bool {
50 self.ptr == other.ptr && self.state == other.state
51 }
52}
53
54impl<V: Variant> Eq for NodeIdx<V> {}
55
56impl<V> NodeIdx<V>
57where
58 V: Variant,
59{
60 /// Creates a new index for the element at the given `node_ptr`
61 /// and the collection with the given `state`.
62 #[inline(always)]
63 pub fn new(state: MemoryState, node_ptr: NodePtr<V>) -> Self {
64 Self {
65 // SAFETY: it is safe to create NodeIdx from any state and node-pointer,
66 // since access to the node is provided only by safe methods which checks
67 // both validity of the pointer and memory state.
68 ptr: unsafe { node_ptr.ptr_mut() },
69 state,
70 }
71 }
72
73 /// Checks whether or not the `state` of the index matches that of this index.
74 #[inline(always)]
75 pub fn is_in_state(self, state: MemoryState) -> bool {
76 self.state == state
77 }
78
79 /// Returns the const raw pointer to the node.
80 ///
81 /// # SAFETY
82 ///
83 /// This method is unsafe as `NodeIdx` implements `Send` and `Sync`.
84 ///
85 /// It is safe dereference the received pointer if we know that `is_valid_for(col)` would
86 /// return `true` where `col` is the collection that this pointer is created from.
87 #[inline(always)]
88 pub(crate) unsafe fn ptr(self) -> *const Node<V> {
89 self.ptr
90 }
91
92 /// Returns the mut raw pointer to the node.
93 ///
94 /// # SAFETY
95 ///
96 /// This method is unsafe as `NodeIdx` implements `Send` and `Sync`.
97 ///
98 /// It is safe dereference the received pointer if we know that `is_valid_for(col)` would
99 /// return `true` where `col` is the collection that this pointer is created from.
100 #[inline(always)]
101 pub(crate) unsafe fn ptr_mut(self) -> *mut Node<V> {
102 self.ptr
103 }
104
105 /// Returns the node pointer if the index is in the same state as the `collection_state`,
106 /// None otherwise.
107 ///
108 /// # SAFETY
109 ///
110 /// This method is unsafe as `NodeIdx` implements `Send` and `Sync`.
111 ///
112 /// It is safe dereference the received pointer if we know that `is_valid_for(col)` would
113 /// return `true` where `col` is the collection that this pointer is created from.
114 #[inline(always)]
115 pub unsafe fn get_ptr(self, collection_state: MemoryState) -> Option<*mut Node<V>> {
116 self.state.eq(&collection_state).then_some(self.ptr)
117 }
118
119 /// Converts the node index into a node pointer.
120 #[inline(always)]
121 pub fn node_ptr(self) -> NodePtr<V> {
122 NodePtr::new(self.ptr)
123 }
124
125 /// Returns true only if this index is valid for the given `collection`.
126 ///
127 /// A node index is valid iff it satisfies the following two conditions:
128 ///
129 /// * It is created from the given `collection`.
130 /// * Memory state of the `collection` has not changed since this index was created.
131 ///
132 /// It is safe to use the unsafe methods of `NodeIdx` if `is_valid_for(col)`
133 /// returns true where `col` is the collection that the index is created from.
134 #[inline(always)]
135 pub fn is_valid_for<M, P>(self, collection: &SelfRefCol<V, M, P>) -> bool
136 where
137 M: MemoryPolicy<V>,
138 P: PinnedVec<Node<V>>,
139 {
140 self.state == collection.memory_state()
141 && collection.nodes().contains_ptr(self.ptr)
142 && unsafe { &*self.ptr }.is_active()
143 }
144
145 /// Returns a reference to the node that this `NodeIdx` corresponds to;
146 /// returns None if the index is invalid.
147 ///
148 /// See [`Self::is_valid_for`] for validity conditions.
149 #[inline(always)]
150 pub fn node<M, P>(self, collection: &SelfRefCol<V, M, P>) -> Option<&Node<V>>
151 where
152 M: MemoryPolicy<V>,
153 P: PinnedVec<Node<V>>,
154 {
155 collection.node_from_idx(self)
156 }
157}