embed_collections/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(docsrs, allow(unused_attributes))]
3
4//! # Embed Collections
5//!
6//! `embed-collections` provides intrusive data structures for Rust. Unlike standard collections,
7//! intrusive collections require the elements to store the node data (links) themselves.
8//! This allows for:
9//!
10//! - **Memory Efficiency**: No extra allocation for nodes.
11//! - **Deterministic Memory Management**: You control where the node lives.
12//! - **Flexibility**: Works with various pointer types (`Box`, `Arc`, `Rc`, `NonNull`, raw pointers).
13//!
14//! ## Modules
15//!
16//! - [`dlist`]: Intrusive Doubly Linked List.
17//! - [`slist`]: Intrusive Singly Linked List (FIFO Queue).
18//!
19//! ## Example
20//!
21//! ```rust
22//! use embed_collections::{dlist::{DLinkedList, ListItem, ListNode}, Pointer};
23//! use std::cell::UnsafeCell;
24//!
25//! struct MyItem {
26//! val: i32,
27//! link: UnsafeCell<ListNode<MyItem, ()>>,
28//! }
29//!
30//! impl MyItem {
31//! fn new(val: i32) -> Self {
32//! Self {
33//! val,
34//! link: UnsafeCell::new(ListNode::default()),
35//! }
36//! }
37//! }
38//!
39//! unsafe impl ListItem<()> for MyItem {
40//! fn get_node(&self) -> &mut ListNode<Self, ()> {
41//! unsafe { &mut *self.link.get() }
42//! }
43//! }
44//!
45//! let mut list = DLinkedList::<Box<MyItem>, ()>::new();
46//! list.push_back(Box::new(MyItem::new(10)));
47//! list.push_back(Box::new(MyItem::new(20)));
48//!
49//! assert_eq!(list.pop_front().unwrap().val, 10);
50//! assert_eq!(list.pop_front().unwrap().val, 20);
51//! ```
52
53use std::mem;
54use std::ptr::NonNull;
55
56/// Abstract pointer trait to support various pointer types in collections.
57///
58/// This trait allows the collections to work with:
59/// - `Box<T>`: Owned, automatically dropped.
60/// - `Arc<T>`: Shared ownership.
61/// - `Rc<T>`: Single thread ownership.
62/// - `NonNull<T>`: Raw non-null pointers (manual memory management).
63/// - `*const T`: Raw pointers (recommend to use `NonNull<T>` instead)
64pub trait Pointer: Sized {
65 type Target;
66
67 fn as_ref(&self) -> &Self::Target;
68
69 unsafe fn from_raw(p: *const Self::Target) -> Self;
70
71 fn into_raw(self) -> *const Self::Target;
72}
73
74impl<T> Pointer for *const T {
75 type Target = T;
76
77 #[inline]
78 fn as_ref(&self) -> &Self::Target {
79 unsafe { mem::transmute(*self) }
80 }
81
82 unsafe fn from_raw(p: *const Self::Target) -> Self {
83 p as *const T
84 }
85
86 fn into_raw(self) -> *const Self::Target {
87 self as *const T
88 }
89}
90
91impl<T> Pointer for NonNull<T> {
92 type Target = T;
93
94 #[inline]
95 fn as_ref(&self) -> &Self::Target {
96 unsafe { self.as_ref() }
97 }
98
99 unsafe fn from_raw(p: *const Self::Target) -> Self {
100 unsafe { NonNull::new_unchecked(p as *mut T) }
101 }
102
103 fn into_raw(self) -> *const Self::Target {
104 self.as_ptr()
105 }
106}
107
108impl<T> Pointer for Box<T> {
109 type Target = T;
110
111 #[inline]
112 fn as_ref(&self) -> &Self::Target {
113 &**self
114 }
115
116 unsafe fn from_raw(p: *const Self::Target) -> Self {
117 unsafe { Box::from_raw(p as *mut T) }
118 }
119
120 fn into_raw(self) -> *const Self::Target {
121 Box::into_raw(self)
122 }
123}
124
125impl<T> Pointer for std::rc::Rc<T> {
126 type Target = T;
127
128 #[inline]
129 fn as_ref(&self) -> &Self::Target {
130 &**self
131 }
132
133 unsafe fn from_raw(p: *const Self::Target) -> Self {
134 unsafe { std::rc::Rc::from_raw(p) }
135 }
136
137 fn into_raw(self) -> *const Self::Target {
138 std::rc::Rc::into_raw(self)
139 }
140}
141
142impl<T> Pointer for std::sync::Arc<T> {
143 type Target = T;
144
145 #[inline]
146 fn as_ref(&self) -> &Self::Target {
147 &**self
148 }
149
150 unsafe fn from_raw(p: *const Self::Target) -> Self {
151 unsafe { std::sync::Arc::from_raw(p) }
152 }
153
154 fn into_raw(self) -> *const Self::Target {
155 std::sync::Arc::into_raw(self)
156 }
157}
158
159#[cfg(feature = "dlist")]
160pub mod dlist;
161#[cfg(feature = "slist")]
162pub mod slist;