1 // Copyright 2025 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #![allow(dead_code)]
15 use core::cell::UnsafeCell;
16 use core::marker::PhantomData;
17 use core::ptr::NonNull;
18
19 // Intrusive link structures are particularly tricky in Rust because mutable
20 // references are expected to be globally unique. Accessing the data through
21 // other methods is UB. There is a good writeup of Tokio's soundness challenges
22 // at: https://gist.github.com/Darksonn/1567538f56af1a8038ecc3c664a42462.
23 //
24 // Here we adapt the strategy that Tokio uses:
25 // * The link pointer structure is marked with `PhantomPinned`. This does two
26 // things. First it "poisons" the containing structure so that it's
27 // unpinnable (immovable). Second it triggers the heuristic from
28 // https://github.com/rust-lang/rust/pull/82834 which will cause the compiler
29 // to omit emitting a `noalias` annotation on mutable references to disable
30 // compiler optimization that assume the mutable reference is unique.
31 // * `next` and `prev` themselves are accessed by `Link` through direct pointer
32 // math on the `LinkInner` struct. This avoids creating mutable references to
33 // those fields themselves which can not be annotated with `PhantomPinned`.
34 // `LinkInner` is `#[repr(C)]` to make the pointer math deterministic.
35 // `LinkInner` is declared in an `inner` module so that `next` and `prev` can
36 // not be accessed directly be the rest of the code.
37 //
38 // TODO: konkers - Understand if we need to annotate the alignment of LinkInner.
39 mod inner {
40 use core::{marker::PhantomPinned, mem::offset_of, ptr::NonNull};
41
42 use super::Link;
43
44 #[repr(C)]
45 pub struct LinkInner {
46 #[allow(dead_code)]
47 next: Option<NonNull<Link>>,
48 #[allow(dead_code)]
49 prev: Option<NonNull<Link>>,
50 _pin: PhantomPinned,
51 }
52
53 impl LinkInner {
54 pub const NEXT_OFFSET: usize = offset_of!(LinkInner, next);
55 pub const PREV_OFFSET: usize = offset_of!(LinkInner, prev);
56
new() -> Self57 pub const fn new() -> Self {
58 Self {
59 next: None,
60 prev: None,
61 _pin: PhantomPinned,
62 }
63 }
64 }
65 }
66 use inner::LinkInner;
67
68 pub struct Link {
69 // UnsafeCell here is used to allow the code to access the data mutably.
70 // Bare mutable pointer access is unsound without this.
71 inner: UnsafeCell<LinkInner>,
72 }
73
74 #[inline]
get_element(inner: &UnsafeCell<LinkInner>, offset: usize) -> Option<NonNull<Link>>75 unsafe fn get_element(inner: &UnsafeCell<LinkInner>, offset: usize) -> Option<NonNull<Link>> {
76 let inner_ptr = inner.get() as *const Option<NonNull<Link>>;
77 let element_ptr = inner_ptr.byte_add(offset);
78 core::ptr::read(element_ptr)
79 }
80
81 #[inline]
set_element(inner: &UnsafeCell<LinkInner>, offset: usize, value: Option<NonNull<Link>>)82 unsafe fn set_element(inner: &UnsafeCell<LinkInner>, offset: usize, value: Option<NonNull<Link>>) {
83 let inner_ptr = inner.get() as *mut Option<NonNull<Link>>;
84 let element_ptr = inner_ptr.byte_add(offset);
85 core::ptr::write(element_ptr, value);
86 }
87
88 impl Link {
new() -> Self89 pub const fn new() -> Self {
90 Self {
91 inner: UnsafeCell::new(LinkInner::new()),
92 }
93 }
94
is_unlinked(&self) -> bool95 pub fn is_unlinked(&self) -> bool {
96 self.get_next().is_none() && self.get_prev().is_none()
97 }
98
is_linked(&self) -> bool99 pub fn is_linked(&self) -> bool {
100 !self.is_unlinked()
101 }
102
103 #[inline]
get_next(&self) -> Option<NonNull<Link>>104 fn get_next(&self) -> Option<NonNull<Link>> {
105 unsafe { get_element(&self.inner, LinkInner::NEXT_OFFSET) }
106 }
107
108 #[inline]
set_next(&mut self, value: Option<NonNull<Link>>)109 fn set_next(&mut self, value: Option<NonNull<Link>>) {
110 unsafe { set_element(&self.inner, LinkInner::NEXT_OFFSET, value) }
111 }
112
113 #[inline]
get_prev(&self) -> Option<NonNull<Link>>114 fn get_prev(&self) -> Option<NonNull<Link>> {
115 unsafe { get_element(&self.inner, LinkInner::PREV_OFFSET) }
116 }
117
118 #[inline]
set_prev(&mut self, value: Option<NonNull<Link>>)119 fn set_prev(&mut self, value: Option<NonNull<Link>>) {
120 unsafe { set_element(&self.inner, LinkInner::PREV_OFFSET, value) }
121 }
122 }
123
124 impl Default for Link {
default() -> Self125 fn default() -> Self {
126 Self::new()
127 }
128 }
129
130 // `UnsafeList` uses None to mark the beginning and end of lists as opposed to
131 // pointers to the base list node. This means that there are never pointers to
132 // `UnsafeList` and the same care is not needed to avoid mutable references as
133 // is taken with the `Link` structure.
134 pub struct UnsafeList<T, A: Adapter> {
135 head: Option<NonNull<Link>>,
136 tail: Option<NonNull<Link>>,
137 _phantom_type: PhantomData<T>,
138 _phantom_adapter: PhantomData<A>,
139 }
140
141 pub trait Adapter {
142 const LINK_OFFSET: usize;
143 }
144
145 impl<T, A: Adapter> UnsafeList<T, A> {
new() -> Self146 pub const fn new() -> Self {
147 Self {
148 head: None,
149 tail: None,
150 _phantom_type: PhantomData,
151 _phantom_adapter: PhantomData,
152 }
153 }
154
155 /// # Safety
156 /// It is up to the caller to ensure exclusive access to the list and its
157 /// members.
is_empty(&self) -> bool158 pub unsafe fn is_empty(&self) -> bool {
159 self.head.is_none()
160 }
161
get_link_ptr(element: NonNull<T>) -> NonNull<Link>162 unsafe fn get_link_ptr(element: NonNull<T>) -> NonNull<Link> {
163 let element_ptr: NonNull<Link> = core::mem::transmute::<NonNull<T>, NonNull<Link>>(element);
164 element_ptr.byte_add(A::LINK_OFFSET)
165 }
166
get_element_ptr(link: NonNull<Link>) -> *const T167 unsafe fn get_element_ptr(link: NonNull<Link>) -> *const T {
168 link.byte_sub(A::LINK_OFFSET).as_ptr() as *const T
169 }
170
get_element_mut(link: NonNull<Link>) -> *mut T171 unsafe fn get_element_mut(link: NonNull<Link>) -> *mut T {
172 link.byte_sub(A::LINK_OFFSET).as_ptr() as *mut T
173 }
174
175 /// unchecked means:
176 /// * we don't `assert!((*element_ptr.as_ptr()).is_unlinked());`
177 /// * we don't check that `element` is non-null.
178 ///
179 /// # Safety
180 /// It is up to the caller to ensure exclusive access to the list and its
181 /// members.
182 /// It is up to the caller to ensure the element is not in a list.
183 /// It is up to the caller to ensure the element is non-null.
push_front_unchecked(&mut self, element: *mut T)184 pub unsafe fn push_front_unchecked(&mut self, element: *mut T) {
185 let element = NonNull::new_unchecked(element);
186 let link_ptr = Self::get_link_ptr(element);
187
188 // Link up the added element.
189 (*link_ptr.as_ptr()).set_next(self.head);
190 (*link_ptr.as_ptr()).set_prev(None);
191
192 match self.head {
193 // If `head` was `None`, the list is empty and `tail` should point
194 // to the added element.
195 None => self.tail = Some(link_ptr),
196
197 // If `head` is not `None`, point the previous `head` to the added
198 // element.
199 Some(head) => (*head.as_ptr()).set_prev(Some(link_ptr)),
200 }
201
202 // Finally point `head` to the added element.
203 self.head = Some(link_ptr);
204 }
205
206 /// unchecked means:
207 /// * we don't `assert!((*element_ptr.as_ptr()).is_unlinked());`
208 /// * we don't check that `element` is non-null.
209 ///
210 /// # Safety
211 /// It is up to the caller to ensure exclusive access to the list and its
212 /// members.
213 /// It is up to the caller to ensure the element is not in a list.
214 /// It is up to the caller to ensure the element is non-null.
push_back_unchecked(&mut self, element: *mut T)215 pub unsafe fn push_back_unchecked(&mut self, element: *mut T) {
216 let element = NonNull::new_unchecked(element);
217 let link_ptr = Self::get_link_ptr(element);
218
219 // Link up the added element.
220 (*link_ptr.as_ptr()).set_next(None);
221 (*link_ptr.as_ptr()).set_prev(self.tail);
222
223 match self.tail {
224 // If `tail` was `None`, the list is empty and `head` should point
225 // to the added element.
226 None => self.head = Some(link_ptr),
227
228 // If `tail` is not `None`, point the previous `tail` to the added
229 // element.
230 Some(tail) => (*tail.as_ptr()).set_next(Some(link_ptr)),
231 }
232
233 // Finally point `tail` to the added element.
234 self.tail = Some(link_ptr);
235 }
236
237 /// unlinks element from the linked list.
238 ///
239 /// # Safety
240 /// It is up to the caller to ensure exclusive access to the list and its
241 /// members.
242 /// It is up to the caller to ensure the element is in the list
243 /// It is up to the caller to ensure the element is non-null.
unlink_element(&mut self, element: *mut T)244 pub unsafe fn unlink_element(&mut self, element: *mut T) {
245 let element = NonNull::new_unchecked(element);
246 let link_ptr = Self::get_link_ptr(element);
247
248 let prev = (*link_ptr.as_ptr()).get_prev();
249 let next = (*link_ptr.as_ptr()).get_next();
250
251 match prev {
252 // Element is at the head of the list
253 None => self.head = next,
254
255 // Element has elements before it in the list.
256 Some(prev_ptr) => (*prev_ptr.as_ptr()).set_next(next),
257 }
258
259 match next {
260 // Element is at the tail of the list
261 None => self.tail = prev,
262
263 // Element has elements after it in the list.
264 Some(next_ptr) => (*next_ptr.as_ptr()).set_prev(prev),
265 }
266
267 (*link_ptr.as_ptr()).set_next(None);
268 (*link_ptr.as_ptr()).set_prev(None);
269 }
270
271 /// # Safety
272 /// It is up to the caller to ensure exclusive access to the list and its
273 /// members.
for_each<E, F: FnMut(&T) -> Result<(), E>>( &self, mut callback: F, ) -> Result<(), E>274 pub unsafe fn for_each<E, F: FnMut(&T) -> Result<(), E>>(
275 &self,
276 mut callback: F,
277 ) -> Result<(), E> {
278 let mut cur = self.head;
279
280 loop {
281 let Some(cur_ptr) = cur else {
282 break;
283 };
284
285 let element = Self::get_element_ptr(cur_ptr);
286 callback(&*element)?;
287
288 cur = (*cur_ptr.as_ptr()).get_next();
289 }
290
291 Ok(())
292 }
293
294 /// Filter iterates over every element in the list calling `callback` on
295 /// each one. If `callback` returns false, the element will be removed
296 /// from the list without modifying the element itself. It is safe to
297 /// add the element to the another linked list within `callback` if it
298 /// returns false.
299 ///
300 /// # Safety
301 /// It is up to the caller to ensure exclusive access to the list and its
302 /// members.
filter<F: FnMut(&mut T) -> bool>(&mut self, mut callback: F)303 pub unsafe fn filter<F: FnMut(&mut T) -> bool>(&mut self, mut callback: F) {
304 let mut cur = self.head;
305
306 loop {
307 let Some(cur_ptr) = cur else {
308 break;
309 };
310
311 let element = Self::get_element_mut(cur_ptr);
312
313 // Cache the next element so that we don't rely on `element` staying
314 // coherent across calls to `callback`.
315 let next = (*cur_ptr.as_ptr()).get_next();
316
317 if !callback(&mut *element) {
318 self.unlink_element(element);
319 }
320
321 cur = next;
322 }
323 }
324
325 /// Return a reference to the first element in the list, clearing the
326 /// prev/next fields in the element.
327 ///
328 /// TODO: reevalulate the lifetime marker here, since it is a lie.
329 ///
330 /// # Safety
331 /// It is up to the caller to ensure exclusive access to the list and its
332 /// members.
pop_head(&mut self) -> Option<*mut T>333 pub unsafe fn pop_head(&mut self) -> Option<*mut T> {
334 let cur = self.head?;
335
336 let element = Self::get_element_mut(cur);
337
338 self.unlink_element(element);
339 Some(element)
340 }
341 }
342
343 impl<T, A: Adapter> Default for UnsafeList<T, A> {
default() -> Self344 fn default() -> Self {
345 Self::new()
346 }
347 }
348