cordyceps/
lib.rs

1#![cfg_attr(docsrs, doc = include_str!("../README.md"))]
2#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg, doc_cfg_hide))]
3#![cfg_attr(docsrs, deny(missing_docs))]
4#![cfg_attr(not(any(feature = "std", test)), no_std)]
5#![allow(unused_unsafe)]
6//!
7//! ## data structures
8//!
9//! `cordyceps` provides implementations of the following data structures:
10//!
11//! - **[`List`]: a mutable, doubly-linked list.**
12//!
13//!   A [`List`] provides *O*(1) insertion and removal at both the head and
14//!   tail of the list. In addition, parts of a [`List`] may be split off to
15//!   form new [`List`]s, and two [`List`]s may be spliced together to form a
16//!   single [`List`], all in *O*(1) time. The [`list`] module also provides
17//!   [`list::Cursor`] and [`list::CursorMut`] types, which allow traversal and
18//!   modification of elements in a list. Finally, elements can remove themselves
19//!   from arbitrary positions in a [`List`], provided that they have mutable
20//!   access to the [`List`] itself. This makes the [`List`] type suitable for
21//!   use in cases where elements must be able to drop themselves while linked
22//!   into a list.
23//!
24//!   The [`List`] type is **not** a lock-free data structure, and can only be
25//!   modified through `&mut` references.
26//!
27//! - **[`MpscQueue`]: a multi-producer, single-consumer (MPSC) lock-free
28//!   last-in, first-out (LIFO) queue.**
29//!
30//!   A [`MpscQueue`] is a *lock-free* concurrent data structure that allows
31//!   multiple producers to concurrently push elements onto the queue, and a
32//!   single consumer to dequeue elements in the order that they were pushed.
33//!
34//!   [`MpscQueue`]s can be used to efficiently share data from multiple
35//!   concurrent producers with a consumer.
36//!
37//!   This structure is only available if the target supports CAS (Compare and
38//!   Swap) atomics.
39//!
40//! - **[`SortedList`]: a mutable, singly-linked list, with elements stored
41//!   in sorted order.**
42//!
43//!   This is a simple, singly-linked list with *O*(*n*) insertion and *O*(1)
44//!   pop operations. The push operation performs an insertion sort, while the
45//!   pop operation removes the item at the front of the list. The front/back
46//!   sorting order is based on [`Ordering`][core::cmp::Ordering] and can be
47//!   min- or max-oriented, or a custom ordering function can be provided.
48//!
49//!   The [`SortedList`] type is **not** a lock-free data structure, and can
50//!   only be modified through `&mut` references.
51//!
52//! - **[`Stack`]: a mutable, singly-linked first-in, first-out (FIFO)
53//!   stack.**
54//!
55//!   This is a simple, singly-linked stack with *O*(1) push and pop
56//!   operations. The pop operation returns the *last* element pushed to the
57//!   stack. A [`Stack`] also implements the [`Iterator`] trait; iterating over
58//!   a stack pops elements from the end of the list.
59//!
60//!   The [`Stack`] type is **not** a lock-free data structure, and can only be
61//!   modified through `&mut` references.
62//!
63//! - **[`TransferStack`]: a lock-free, multi-producer FIFO stack, where
64//!   all elements currently in the stack are popped in a single atomic operation.**
65//!
66//!   A [`TransferStack`] is a lock-free data structure where multiple producers
67//!   can [concurrently push elements](stack::TransferStack::push) to the end of
68//!   the stack through immutable `&` references. A consumer can [pop all
69//!   elements currently in the `TransferStack`](stack::TransferStack::take_all)
70//!   in a single atomic operation, returning a new [`Stack`]. Pushing an
71//!   element, and taking all elements in the [`TransferStack`] are both *O*(1)
72//!   operations.
73//!
74//!   A [`TransferStack`] can be used to efficiently transfer ownership of
75//!   resources from multiple producers to a consumer, such as for reuse or
76//!   cleanup.
77//!
78//!   This structure is only available if the target supports CAS (Compare and
79//!   Swap) atomics.
80#[cfg(feature = "alloc")]
81extern crate alloc;
82#[cfg(test)]
83extern crate std;
84
85#[macro_use]
86pub(crate) mod util;
87
88pub mod list;
89pub mod sorted_list;
90pub mod stack;
91
92#[doc(inline)]
93pub use list::List;
94#[doc(inline)]
95pub use sorted_list::{SortedList, SortedListIter};
96#[doc(inline)]
97pub use stack::Stack;
98
99//
100// The following items are only available if we have atomics
101//
102#[cfg(target_has_atomic = "ptr")]
103pub mod mpsc_queue;
104
105#[cfg(target_has_atomic = "ptr")]
106pub use has_cas_atomics::*;
107
108#[cfg(target_has_atomic = "ptr")]
109mod has_cas_atomics {
110    #[doc(inline)]
111    pub use crate::mpsc_queue::MpscQueue;
112
113    #[doc(inline)]
114    pub use crate::stack::TransferStack;
115}
116
117pub(crate) mod loom;
118
119use core::ptr::NonNull;
120
121/// Trait implemented by types which can be members of an [intrusive collection].
122///
123/// In order to be part of an intrusive collection, a type must contain a
124/// `Links` type that stores the pointers to other nodes in that collection. For
125/// example, to be part of a [doubly-linked list], a type must contain the
126/// [`list::Links`] struct, or to be part of a [MPSC queue], a type must contain
127/// the [`mpsc_queue::Links`] struct.
128///
129/// # Safety
130///
131/// This is unsafe to implement because it's the implementation's responsibility
132/// to ensure that types implementing this trait are valid intrusive collection
133/// nodes. In particular:
134///
135/// - Implementations **must** ensure that implementors are pinned in memory while they
136///   are in an intrusive collection. While a given `Linked` type is in an intrusive
137///   data structure, it may not be deallocated or moved to a different memory
138///   location.
139/// - The type implementing this trait **must not** implement [`Unpin`].
140/// - Additional safety requirements for individual methods on this trait are
141///   documented on those methods.
142///
143/// Failure to uphold these invariants will result in corruption of the
144/// intrusive data structure, including dangling pointers.
145///
146/// # Implementing `Linked::links`
147///
148/// The [`Linked::links`] method provides access to a `Linked` type's `Links`
149/// field through a [`NonNull`] pointer. This is necessary for a type to
150/// participate in an intrusive structure, as it tells the intrusive structure
151/// how to access the links to other parts of that data structure. However, this
152/// method is somewhat difficult to implement correctly.
153///
154/// Suppose we have an entry type like this:
155/// ```rust
156/// use cordyceps::list;
157///
158/// struct Entry {
159///     links: list::Links<Self>,
160///     data: usize,
161/// }
162/// ```
163///
164/// The naive implementation of [`links`](Linked::links) for this `Entry` type
165/// might look like this:
166///
167/// ```
168/// use cordyceps::Linked;
169/// use core::ptr::NonNull;
170///
171/// # use cordyceps::list;
172/// # struct Entry {
173/// #    links: list::Links<Self>,
174/// # }
175///
176/// unsafe impl Linked<list::Links<Self>> for Entry {
177///     # type Handle = NonNull<Self>;
178///     # fn into_ptr(r: Self::Handle) -> NonNull<Self> { r }
179///     # unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle { ptr }
180///     // ...
181///
182///     unsafe fn links(mut target: NonNull<Self>) -> NonNull<list::Links<Self>> {
183///         // Borrow the target's `links` field.
184///         let links = &mut target.as_mut().links;
185///         // Convert that reference into a pointer.
186///         NonNull::from(links)
187///     }
188/// }
189/// ```
190///
191/// However, this implementation **is not sound** under [Stacked Borrows]! It
192/// creates a temporary reference from the original raw pointer, and then
193/// creates a new raw pointer from that temporary reference. Stacked Borrows
194/// will reject this reborrow as unsound.[^1]
195///
196/// There are two ways we can implement [`Linked::links`] without creating a
197/// temporary reference in this manner. The recommended one is to use the
198/// [`core::ptr::addr_of_mut!`] macro, as follows:
199///
200/// ```
201/// use core::ptr::{self, NonNull};
202/// # use cordyceps::{Linked, list};
203/// # struct Entry {
204/// #    links: list::Links<Self>,
205/// # }
206///
207/// unsafe impl Linked<list::Links<Self>> for Entry {
208///     # type Handle = NonNull<Self>;
209///     # fn into_ptr(r: Self::Handle) -> NonNull<Self> { r }
210///     # unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle { ptr }
211///     // ...
212///
213///     unsafe fn links(target: NonNull<Self>) -> NonNull<list::Links<Self>> {
214///         let target = target.as_ptr();
215///
216///         // Using the `ptr::addr_of_mut!` macro, we can offset a raw pointer to a
217///         // raw pointer to a field *without* creating a temporary reference.
218///         let links = ptr::addr_of_mut!((*target).links);
219///
220///         // `NonNull::new_unchecked` is safe to use here, because the pointer that
221///         // we offset was not null, implying that the pointer produced by offsetting
222///         // it will also not be null.
223///         NonNull::new_unchecked(links)
224///     }
225/// }
226/// ```
227///
228/// It is also possible to ensure that the struct implementing `Linked` is laid
229/// out so that the `Links` field is the first member of the struct, and then
230/// cast the pointer to a `Links`. Since [Rust's native type representation][repr]
231/// does not guarantee the layout of struct members, it is **necessary** to ensure
232/// that any struct that implements the `Linked::links` method in this manner has a
233/// [`#[repr(C)]` attribute][repr-c], ensuring that its fields are laid out in the
234/// order that they are defined.
235///
236/// For example:
237///
238/// ```
239/// use core::ptr::NonNull;
240/// use cordyceps::{Linked, list};
241///
242/// // This `repr(C)` attribute is *mandatory* here, as it ensures that the
243/// // `links` field will *always* be the first field in the struct's in-memory
244/// // representation.
245/// #[repr(C)]
246/// struct Entry {
247///     links: list::Links<Self>,
248///     data: usize,
249/// }
250///
251/// unsafe impl Linked<list::Links<Self>> for Entry {
252///     # type Handle = NonNull<Self>;
253///     # fn into_ptr(r: Self::Handle) -> NonNull<Self> { r }
254///     # unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle { ptr }
255///     // ...
256///
257///     unsafe fn links(target: NonNull<Self>) -> NonNull<list::Links<Self>> {
258///         // Safety: this performs a layout-dependent cast! it is only sound
259///         // if the `Entry` type has a `#[repr(C)]` attribute!
260///         target.cast::<list::Links<Self>>()
261///     }
262/// }
263/// ```
264///
265/// In general, this approach is not recommended, and using
266/// [`core::ptr::addr_of_mut!`] should be preferred in almost all cases. In
267/// particular, the layout-dependent cast is more error-prone, as it requires a
268/// `#[repr(C)]` attribute to avoid soundness issues. Additionally, the
269/// layout-based cast does not permit a single struct to contain `Links` fields
270/// for multiple intrusive data structures, as the `Links` type *must* be the
271/// struct's first field.[^2] Therefore, [`Linked::links`] should generally be
272/// implemented using [`addr_of_mut!`](core::ptr::addr_of_mut).
273///
274/// [^1]: Note that code like this is not *currently* known to result in
275///     miscompiles, but it is rejected by tools like Miri as being unsound.
276///     Like all undefined behavior, there is no guarantee that future Rust
277///     compilers will not miscompile code like this, with disastrous results.
278///
279/// [^2]: And two different fields cannot both be the first field at the same
280///      time...by definition.
281///
282/// [intrusive collection]: crate#intrusive-data-structures
283/// [`Unpin`]: core::marker::Unpin
284/// [doubly-linked list]: crate::list
285/// [MSPC queue]: crate::mpsc_queue
286/// [Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md
287/// [repr]: https://doc.rust-lang.org/nomicon/repr-rust.html
288/// [repr-c]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprc
289pub unsafe trait Linked<L> {
290    /// The handle owning nodes in the linked list.
291    ///
292    /// This type must have ownership over a `Self`-typed value. When a `Handle`
293    /// is dropped, it should drop the corresponding `Linked` type.
294    ///
295    /// A quintessential example of a `Handle` is [`Box`].
296    ///
297    /// [`Box`]: alloc::boxed::Box
298    type Handle;
299
300    /// Convert a [`Self::Handle`] to a raw pointer to `Self`, taking ownership
301    /// of it in the process.
302    fn into_ptr(r: Self::Handle) -> NonNull<Self>;
303
304    /// Convert a raw pointer to `Self` into an owning [`Self::Handle`].
305    ///
306    /// # Safety
307    ///
308    /// This function is safe to call when:
309    /// - It is valid to construct a [`Self::Handle`] from a`raw pointer
310    /// - The pointer points to a valid instance of `Self` (e.g. it does not
311    ///   dangle).
312    unsafe fn from_ptr(ptr: NonNull<Self>) -> Self::Handle;
313
314    /// Return the links of the node pointed to by `ptr`.
315    ///
316    /// # Safety
317    ///
318    /// This function is safe to call when:
319    /// - It is valid to construct a [`Self::Handle`] from a`raw pointer
320    /// - The pointer points to a valid instance of `Self` (e.g. it does not
321    ///   dangle).
322    ///
323    /// See [the trait-level documentation](#implementing-linkedlinks) for
324    /// details on how to correctly implement this method.
325    unsafe fn links(ptr: NonNull<Self>) -> NonNull<L>;
326}