pin_list/node.rs
1//! The `Node` type and its related APIs.
2
3use crate::list::NodeLinked;
4use crate::list::NodeProtected;
5use crate::list::NodeRemoved;
6use crate::list::NodeShared;
7use crate::list::OptionNodeShared;
8use crate::util::abort;
9use crate::util::debug_unreachable;
10use crate::util::unwrap_unchecked;
11use crate::util::ConstFnBounds;
12use crate::Cursor;
13use crate::CursorMut;
14use crate::PinList;
15use crate::Types;
16use core::cell::UnsafeCell;
17use core::fmt;
18use core::fmt::Debug;
19use core::fmt::Formatter;
20use core::marker::PhantomData;
21use core::mem;
22use core::ops::Deref;
23use core::pin::Pin;
24use core::ptr::NonNull;
25use pin_project_lite::pin_project;
26use pinned_aliasable::Aliasable;
27
28pin_project! {
29 /// A node in a [`PinList`].
30 ///
31 /// This type is a state machine between three states:
32 /// 1. **Initial:**
33 /// The initial state; the node is not registered in any list. This is the only state that
34 /// can be dropped without aborting the process.
35 /// 2. **Linked:**
36 /// The node has been linked into a [`PinList`]. It holds a `Protected` and an
37 /// `Unprotected`, of which the former can only be accessed when access to the [`PinList`]
38 /// can be proven. Dropping a node in this state will abort.
39 /// 3. **Removed:**
40 /// The node has been removed from a [`PinList`]. It holds a `Removed` and an
41 /// `Unprotected`. Similar to the "linked" state, proof of access to the [`PinList`] is
42 /// required for most operations. Dropping a node in this state will abort.
43 pub struct Node<T>
44 where
45 T: ?Sized,
46 T: Types,
47 {
48 // `None` if initial, `Some` if initialized
49 #[pin]
50 inner: Option<NodeInner<T>>,
51 }
52
53 impl<T> PinnedDrop for Node<T>
54 where
55 T: ?Sized,
56 T: Types,
57 {
58 fn drop(this: Pin<&mut Self>) {
59 // If we might be linked into a list at this point in time, we have no choice but to
60 // abort in order to preserve soundness and prevent use-after-frees.
61 if this.inner.is_some() {
62 abort();
63 }
64 }
65 }
66}
67
68pin_project! {
69 struct NodeInner<T>
70 where
71 T: ?Sized,
72 T: Types,
73 {
74 // The ID of the list this node is/was registered in, used for checking whether access to
75 // the inner state is valid.
76 list_id: T::Id,
77
78 // State that is also accessible by a walker of the list (cursors).
79 #[pin]
80 shared: Aliasable<NodeShared<T>>,
81 }
82}
83
84unsafe impl<T: ?Sized + Types> Send for Node<T>
85where
86 // Required because it is owned by this type and will be dropped by it.
87 T::Id: Send,
88
89 // (SAFETY) Not required because the ownership of IDs are not shared.
90 /* T::Id: ?Sync, */
91 // Required because we can take and return instances of this type by value.
92 T::Protected: Send,
93
94 // (SAFETY) Not required because multiple `&PinList`s on different threads are required to
95 // access this type in a `Sync`-requiring way, which would need `PinList: Sync` (which does
96 // require `T::Protected: Sync`). In other words, `Self: Send` alone only allows exclusive or
97 // reentrant access which is OK by `Send + !Sync`.
98 /* T::Protected: ?Sync, */
99 // Required because we can take and return this type by value.
100 T::Removed: Send,
101
102 // (SAFETY) Not required because we never deal in `&T::Removed` — it's always passed by
103 // ownership.
104 /* T::Removed: ?Sync, */
105 // Required because we can take and return this type by value.
106 T::Unprotected: Send,
107
108 // Required because values of this type can be shared between this node and its list.
109 T::Unprotected: Sync,
110{
111}
112
113unsafe impl<T: ?Sized + Types> Sync for Node<T>
114where
115 // (SAFETY) Not required because ownership of IDs can't be obtained from a shared reference.
116 /* T::Id: ?Send, */
117 // Required because ID comparison code uses its `PartialEq` implementation, which accesses it
118 // by shared reference.
119 T::Id: Sync,
120
121 // (SAFETY) Not required to be `Send` or `Sync` because the only methods that access it that
122 // take `&self` would require the `PinList` to be `Sync` to be called on two threads, which it
123 // isn't if `T::Protected: !Send` or `T::Protected: !Sync`.
124 /* T::Protected: ?Send + ?Sync, */
125
126 // (SAFETY) Not required because ownership of this type is only passed around when a
127 // `Pin<&mut Node<T>>` is the receiver.
128 /* T::Removed: ?Send, */
129
130 // (SAFETY) Not required because we never deal in `&T::Removed` — it's always passed by
131 // ownership.
132 /* T::Removed: ?Sync, */
133
134 // (SAFETY) Not required because ownership of this type is only passed around when a
135 // `Pin<&mut Node<T>` is the receiver.
136 /* T::Unprotected: ?Send, */
137 // Required because shared references to values of this type can be accessed from a shared
138 // reference to the node.
139 T::Unprotected: Sync,
140{
141}
142
143impl<T: ?Sized> Node<T>
144where
145 <T as ConstFnBounds>::Type: Types,
146{
147 /// Create a new node in its initial state.
148 ///
149 /// You can move this node into other states by functions like [`PinList::push_front`].
150 #[must_use]
151 pub const fn new() -> Self {
152 Self { inner: None }
153 }
154}
155
156impl<T: ?Sized + Types> Default for Node<T> {
157 fn default() -> Self {
158 Self::new()
159 }
160}
161
162impl<T: ?Sized + Types> Node<T> {
163 /// Check whether the node is in its initial state.
164 #[must_use]
165 pub fn is_initial(&self) -> bool {
166 self.inner.is_none()
167 }
168
169 /// Insert this node into the linked list before the given cursor.
170 ///
171 /// # Panics
172 ///
173 /// Panics if the node is not in its initial state.
174 pub fn insert_before(
175 self: Pin<&mut Self>,
176 cursor: &mut CursorMut<'_, T>,
177 protected: T::Protected,
178 unprotected: T::Unprotected,
179 ) -> Pin<&mut InitializedNode<'_, T>> {
180 let prev = *cursor.prev_mut();
181
182 // Store our own state as linked.
183 let node = self.init(NodeInner {
184 list_id: cursor.list().id,
185 shared: Aliasable::new(NodeShared {
186 protected: UnsafeCell::new(NodeProtected::Linked(NodeLinked {
187 prev,
188 next: cursor.current,
189 data: protected,
190 })),
191 unprotected,
192 }),
193 });
194
195 // Update the previous node's `next` pointer and the next node's `prev` pointer to both
196 // point to us.
197 *unsafe { cursor.list.cursor_mut(prev) }.next_mut() =
198 OptionNodeShared::some(node.shared_ptr());
199 *cursor.prev_mut() = OptionNodeShared::some(node.shared_ptr());
200
201 node
202 }
203
204 /// Insert this node into the linked list after the given cursor.
205 ///
206 /// # Panics
207 ///
208 /// Panics if the node is not in its initial state.
209 pub fn insert_after(
210 self: Pin<&mut Self>,
211 cursor: &mut CursorMut<'_, T>,
212 protected: T::Protected,
213 unprotected: T::Unprotected,
214 ) -> Pin<&mut InitializedNode<'_, T>> {
215 let next = *cursor.next_mut();
216
217 // Store our own state as linked.
218 let node = self.init(NodeInner {
219 list_id: cursor.list().id,
220 shared: Aliasable::new(NodeShared {
221 protected: UnsafeCell::new(NodeProtected::Linked(NodeLinked {
222 prev: cursor.current,
223 next,
224 data: protected,
225 })),
226 unprotected,
227 }),
228 });
229
230 // Update the previous node's `next` pointer and the next node's `prev` pointer to both
231 // point to us.
232 *cursor.next_mut() = OptionNodeShared::some(node.shared_ptr());
233 *unsafe { cursor.list.cursor_mut(next) }.prev_mut() =
234 OptionNodeShared::some(node.shared_ptr());
235
236 node
237 }
238
239 fn init(mut self: Pin<&mut Self>, new_inner: NodeInner<T>) -> Pin<&mut InitializedNode<'_, T>> {
240 let mut inner = self.as_mut().project().inner;
241
242 assert!(inner.is_none(), "attempted to link an already-linked node");
243
244 inner.set(Some(new_inner));
245
246 // SAFETY: We just set the inner to `Some`.
247 unsafe { InitializedNode::new_mut_unchecked(self) }
248 }
249
250 /// Borrow the node, if it is initialized (linked or removed).
251 ///
252 /// Returns [`None`] if the node is in the initial state.
253 #[must_use]
254 pub fn initialized(&self) -> Option<&InitializedNode<'_, T>> {
255 InitializedNode::new_ref(self)
256 }
257
258 /// Borrow uniquely the node, if it is initialized (linked or removed).
259 ///
260 /// Returns [`None`] if the node is in the initial state.
261 #[must_use]
262 pub fn initialized_mut(self: Pin<&mut Self>) -> Option<Pin<&mut InitializedNode<'_, T>>> {
263 InitializedNode::new_mut(self)
264 }
265}
266
267impl<T: ?Sized + Types> Debug for Node<T>
268where
269 T::Unprotected: Debug,
270{
271 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
272 if let Some(initialized) = &self.initialized() {
273 f.debug_struct("Node::Initialized")
274 .field("list_id", &initialized.inner().list_id)
275 .field("unprotected", initialized.unprotected())
276 .finish()
277 } else {
278 f.pad("Node::Initial")
279 }
280 }
281}
282
283/// A [`Node`] which is guaranteed to be initialized, accessed by [`Node::initialized`] and
284/// [`Node::initialized_mut`].
285///
286/// You can never create and will never interact with owned or `&mut` instances of this type — it
287/// is accessed solely as `&InitializedNode<'_, T>` or `Pin<&mut InitializedNode<'_, T>>`.
288#[repr(transparent)]
289pub struct InitializedNode<'node, T: ?Sized + Types> {
290 // Hold a `Node<T>` and not a `NodeInner<T>` so we can set its value to `None`.
291 node: Node<T>,
292 // This `'node` lifetime is used to allow "owned references" to the `InitializedNode`:
293 // `Pin<&'node mut InitializedNode<'node, T>>`. Because the unique reference makes the `'node`
294 // lifetime invariant, such a type enforces that the reference is not used after that call.
295 _lifetime: PhantomData<&'node ()>,
296}
297
298impl<T: ?Sized + Types> Deref for InitializedNode<'_, T> {
299 type Target = Node<T>;
300 fn deref(&self) -> &Self::Target {
301 &self.node
302 }
303}
304
305impl<'node, T: ?Sized + Types> InitializedNode<'node, T> {
306 fn new_ref(node: &'node Node<T>) -> Option<&'node Self> {
307 node.inner.as_ref()?;
308 // SAFETY: We have just asserted that `inner` is `Some` and we are `#[repr(transparent)]`
309 // over `Node<T>`.
310 Some(unsafe { mem::transmute::<&'node Node<T>, &'node InitializedNode<'node, T>>(node) })
311 }
312
313 fn new_mut(node: Pin<&'node mut Node<T>>) -> Option<Pin<&'node mut Self>> {
314 node.inner.as_ref()?;
315 // SAFETY: We have just asserted that `inner` is `Some`.
316 Some(unsafe { Self::new_mut_unchecked(node) })
317 }
318
319 unsafe fn new_mut_unchecked(node: Pin<&'node mut Node<T>>) -> Pin<&'node mut Self> {
320 // SAFETY: Caller ensures that `inner` is `Some`, and we are `#[repr(transparent)]`
321 // over `Node<T>`.
322 unsafe {
323 mem::transmute::<Pin<&'node mut Node<T>>, Pin<&'node mut InitializedNode<'node, T>>>(
324 node,
325 )
326 }
327 }
328
329 fn inner(&self) -> Pin<&NodeInner<T>> {
330 // SAFETY: In order for this type to exist, the node must be initialized.
331 let inner = unsafe { unwrap_unchecked(self.node.inner.as_ref()) };
332
333 // SAFETY: In order for this state to be created, we must already have been pinned.
334 unsafe { Pin::new_unchecked(inner) }
335 }
336
337 fn shared(&self) -> &NodeShared<T> {
338 self.inner().project_ref().shared.get()
339 }
340
341 fn shared_ptr(&self) -> NonNull<NodeShared<T>> {
342 NonNull::from(self.shared())
343 }
344
345 /// Get a shared reference to the unprotected data of this node.
346 #[must_use]
347 pub fn unprotected(&self) -> &T::Unprotected {
348 &self.shared().unprotected
349 }
350
351 /// Get a shared reference to the protected data of this node.
352 ///
353 /// Returns [`None`] if the node is in its removed state (has been removed from the list).
354 ///
355 /// # Panics
356 ///
357 /// Panics if the given list is a different one than this node was registered with.
358 #[must_use]
359 pub fn protected<'list>(&self, list: &'list PinList<T>) -> Option<&'list T::Protected> {
360 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
361
362 // SAFETY: We have shared access to both `self` and our `PinList`, as guaranteed above.
363 match unsafe { &*self.shared().protected.get() } {
364 NodeProtected::Linked(linked) => Some(&linked.data),
365 NodeProtected::Removed(..) => None,
366 }
367 }
368
369 /// Get a unique reference to the protected data of this node.
370 ///
371 /// Returns [`None`] if the node is in its removed state (has been removed from the list).
372 ///
373 /// # Panics
374 ///
375 /// Panics if the given list is a different one than this node was registered with.
376 #[must_use]
377 pub fn protected_mut<'list>(
378 &self,
379 list: &'list mut PinList<T>,
380 ) -> Option<&'list mut T::Protected> {
381 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
382
383 // Only create a shared reference because we only have a shared reference to `self`. In the
384 // `Linked` branch this doesn't end up mattering, but in the `Removed` branch it's possible
385 // that a `&NodeRemoved` existed at the time of calling this function.
386 match unsafe { &*self.shared().protected.get() } {
387 NodeProtected::Linked(..) => {
388 // SAFETY: We have unique access to the list, and we have asserted that the node
389 // isn't removed.
390 Some(match unsafe { &mut *self.shared().protected.get() } {
391 NodeProtected::Linked(linked) => &mut linked.data,
392 NodeProtected::Removed(..) => unsafe { debug_unreachable!() },
393 })
394 }
395 NodeProtected::Removed(..) => None,
396 }
397 }
398
399 /// Obtain a shared cursor pointing to this node.
400 ///
401 /// Returns [`None`] if the node was in its removed state (it was removed from the list).
402 ///
403 /// # Panics
404 ///
405 /// Panics if the given list is a different one than this node was registered with.
406 #[must_use]
407 pub fn cursor<'list>(&self, list: &'list PinList<T>) -> Option<Cursor<'list, T>> {
408 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
409
410 // SAFETY: We have shared access to both this node and the list.
411 match unsafe { &*self.shared().protected.get() } {
412 NodeProtected::Linked(..) => {}
413 NodeProtected::Removed(..) => return None,
414 }
415
416 // SAFETY: We have shared access to the list, and this node is not removed from the list.
417 Some(unsafe { list.cursor(OptionNodeShared::some(self.shared_ptr())) })
418 }
419
420 /// Obtain a unique cursor pointing to this node.
421 ///
422 /// Returns [`None`] if the node was in its removed state (it was removed from the list).
423 ///
424 /// # Panics
425 ///
426 /// Panics if the given list is a different one than this node was registered with.
427 #[must_use]
428 pub fn cursor_mut<'list>(&self, list: &'list mut PinList<T>) -> Option<CursorMut<'list, T>> {
429 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
430
431 // Only create a shared reference because we only have a shared reference to `self`. In the
432 // `Linked` branch this doesn't end up mattering, but in the `Removed` branch it's possible
433 // that a `&NodeRemoved` existed at the time of calling this function.
434 match unsafe { &*self.shared().protected.get() } {
435 NodeProtected::Linked(..) => {}
436 NodeProtected::Removed(..) => return None,
437 }
438
439 // SAFETY: We have exclusive access to the list, and this node is not removed from the
440 // list.
441 Some(unsafe { list.cursor_mut(OptionNodeShared::some(self.shared_ptr())) })
442 }
443
444 /// Remove this node from its containing list and take its data, leaving the node in its
445 /// initial state.
446 ///
447 /// # Errors
448 ///
449 /// Fails if the node is in its removed state — use [`take_removed`](Self::take_removed) to
450 /// handle that case, or call [`reset`](Self::reset) instead.
451 ///
452 /// # Panics
453 ///
454 /// Panics if the given list is a different one than this node was registered with.
455 // Take `&'node mut Self` instead of `&mut Self` to ensure that this reference is not used
456 // after this point.
457 pub fn unlink(
458 self: Pin<&'node mut Self>,
459 list: &mut PinList<T>,
460 ) -> Result<(T::Protected, T::Unprotected), Pin<&'node mut Self>> {
461 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
462
463 // SAFETY: We have exclusive access to both the node and the list.
464 let linked = match unsafe { &mut *self.shared().protected.get() } {
465 NodeProtected::Linked(linked) => linked,
466 NodeProtected::Removed(..) => return Err(self),
467 };
468
469 // Link up the nodes around us to remove ourselves from the list.
470 *unsafe { list.cursor_mut(linked.prev) }.next_mut() = linked.next;
471 *unsafe { list.cursor_mut(linked.next) }.prev_mut() = linked.prev;
472
473 // SAFETY: We just unlinked ourselves from the list.
474 match unsafe { self.take_unchecked() } {
475 (NodeData::Linked(linked), unprotected) => Ok((linked, unprotected)),
476 // SAFETY: We asserted at the beginning of this function that we were in the linked
477 // state.
478 (NodeData::Removed(_), _) => unsafe { debug_unreachable!() },
479 }
480 }
481
482 /// Take the data out of this node if it has been removed from the list, leaving the node in
483 /// its initial state.
484 ///
485 /// # Errors
486 ///
487 /// Errors if the node was in its "linked" state (it was still part of the list) — use
488 /// [`unlink`](Self::unlink) in this case, or call [`reset`](Self::reset) instead.
489 ///
490 /// # Panics
491 ///
492 /// Panics if the given list is a different one than this node was registered with.
493 // Take `&'node mut Self` instead of `&mut Self` to ensure that this reference is not used
494 // after this point.
495 pub fn take_removed(
496 self: Pin<&'node mut Self>,
497 list: &PinList<T>,
498 ) -> Result<(T::Removed, T::Unprotected), Pin<&'node mut Self>> {
499 assert_eq!(self.inner().list_id, list.id, "incorrect `PinList`");
500
501 // Only create a shared reference because we only have shared access to the `PinList`. In
502 // the `Removed` branch this doesn't end up mattering, but in the `Linked` branch it's
503 // possible a `&T::Unprotected` existed at the time of calling this function.
504 match unsafe { &*self.shared().protected.get() } {
505 NodeProtected::Removed(..) => {}
506 NodeProtected::Linked(..) => return Err(self),
507 }
508
509 // SAFETY: We just asserted that we are in the removed state.
510 Ok(unsafe { self.take_removed_unchecked() })
511 }
512
513 /// Take the data out of this node, assuming that it has been removed from the list, leaving
514 /// the node in its initial state.
515 ///
516 /// In contrast to [`take_removed`](Self::take_removed), this does not require access to the
517 /// [`PinList`].
518 ///
519 /// # Safety
520 ///
521 /// The node must not be in its linked state.
522 #[must_use]
523 // Take `&'node mut Self` instead of `&mut Self` to ensure that this reference is not used
524 // after this point.
525 pub unsafe fn take_removed_unchecked(
526 self: Pin<&'node mut Self>,
527 ) -> (T::Removed, T::Unprotected) {
528 // SAFETY: Ensured by caller.
529 match unsafe { self.take_unchecked() } {
530 (NodeData::Linked(_), _) => {
531 // oops! the caller has violated the safety invariants of this function. we may
532 // have even already caused UB in `take_unchecked`.
533 // SAFETY: Ensured by caller.
534 unsafe {
535 debug_unreachable!(
536 "called `take_remove_unchecked` on a linked node: this is Undefined Behaviour"
537 )
538 }
539 }
540 (NodeData::Removed(removed), unprotected) => (removed, unprotected),
541 }
542 }
543
544 /// Take the inner data from this node, leaving it in the initial state.
545 ///
546 /// # Safety
547 ///
548 /// The node must have been removed from the list. It can be in either of the `Removed` and
549 /// `Linked` states.
550 // Take `&'node mut Self` instead of `&mut Self` to ensure that this reference is not used
551 // after this point.
552 unsafe fn take_unchecked(self: Pin<&'node mut Self>) -> (NodeData<T>, T::Unprotected) {
553 // SAFETY: Since the caller asserts that we have been removed, we no longer need to be
554 // pinned.
555 let this = unsafe { &mut Pin::into_inner_unchecked(self).node };
556
557 let old_node = this.inner.take();
558 // SAFETY: In order for this type to exist, the node must be initialized.
559 let old_inner = unsafe { unwrap_unchecked(old_node) };
560 let old_shared = old_inner.shared.into_inner();
561 let data = match old_shared.protected.into_inner() {
562 NodeProtected::Linked(NodeLinked { data, .. }) => NodeData::Linked(data),
563 NodeProtected::Removed(NodeRemoved { data }) => NodeData::Removed(data),
564 };
565 (data, old_shared.unprotected)
566 }
567
568 /// Reset the node back to its initial state.
569 ///
570 /// If the node is linked, this will unlink it, and then the node will be moved to the initial
571 /// state.
572 ///
573 /// This can be thought of as a combination of [`unlink`] and [`take_removed`].
574 ///
575 /// [`unlink`]: Self::unlink
576 /// [`take_removed`]: Self::take_removed
577 ///
578 /// # Panics
579 ///
580 /// Panics if the given list is a different one than this node was registered with.
581 pub fn reset(
582 self: Pin<&'node mut Self>,
583 list: &mut PinList<T>,
584 ) -> (NodeData<T>, T::Unprotected) {
585 match self.unlink(list) {
586 Ok((protected, unprotected)) => (NodeData::Linked(protected), unprotected),
587 Err(this) => {
588 // SAFETY: `unlink` only returns `Err` if we have been removed.
589 let (removed, unprotected) = unsafe { this.take_removed_unchecked() };
590 (NodeData::Removed(removed), unprotected)
591 }
592 }
593 }
594}
595
596impl<T: ?Sized + Types> Debug for InitializedNode<'_, T>
597where
598 T::Unprotected: Debug,
599{
600 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
601 f.debug_struct("InitializedNode")
602 .field("list_id", &self.inner().list_id)
603 .field("unprotected", self.unprotected())
604 .finish()
605 }
606}
607
608/// The data stored by a node; either `Protected` or `Removed`. This type is returned by
609/// [`InitializedNode::reset`].
610pub enum NodeData<T: ?Sized + Types> {
611 /// The node was linked in a list.
612 Linked(T::Protected),
613
614 /// The node was removed from the list.
615 Removed(T::Removed),
616}
617
618impl<T: ?Sized + Types> Debug for NodeData<T>
619where
620 T::Protected: Debug,
621 T::Removed: Debug,
622{
623 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
624 match self {
625 Self::Linked(protected) => f.debug_tuple("NodeData::Linked").field(protected).finish(),
626 Self::Removed(removed) => f.debug_tuple("NodeData::Removed").field(removed).finish(),
627 }
628 }
629}