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}