1#![warn(unsafe_op_in_unsafe_fn)]
6
7use fuchsia_rcu::RcuReadScope;
8use fuchsia_rcu::subtle::{RcuPtr, RcuPtrRef};
9
10#[derive(Debug)]
14pub struct Link {
15 next: RcuPtr<Link>,
19
20 prev: RcuPtr<Link>,
24}
25
26impl Default for Link {
27 fn default() -> Self {
28 Self { next: RcuPtr::null(), prev: RcuPtr::null() }
29 }
30}
31
32#[macro_export]
38macro_rules! container_of {
39 ($ptr:expr, $container:path, $field:ident) => {{ $ptr.sub_byte_offset::<$container>(memoffset::offset_of!($container, $field)) }};
40}
41
42#[macro_export]
48macro_rules! field_of {
49 ($ptr:expr, $container:path, $field:ident, $field_type:ty) => {{ $ptr.add_byte_offset::<$field_type>(memoffset::offset_of!($container, $field)) }};
50}
51
52#[macro_export]
53macro_rules! rcu_list_adapter {
54 ($node:ty, $link:ident) => {
55 fn to_link(
56 node: fuchsia_rcu::subtle::RcuPtrRef<'_, $node>,
57 ) -> fuchsia_rcu::subtle::RcuPtrRef<'_, Link> {
58 if node.is_null() {
59 return fuchsia_rcu::subtle::RcuPtrRef::null();
60 }
61 unsafe { $crate::field_of!(node, $node, $link, Link) }
63 }
64
65 fn from_link(
66 link: fuchsia_rcu::subtle::RcuPtrRef<'_, Link>,
67 ) -> fuchsia_rcu::subtle::RcuPtrRef<'_, $node> {
68 if link.is_null() {
69 return fuchsia_rcu::subtle::RcuPtrRef::null();
70 }
71 unsafe { $crate::container_of!(link, $node, $link) }
73 }
74 };
75}
76
77pub use {container_of, field_of, rcu_list_adapter};
78
79pub trait RcuListAdapter<T> {
80 fn to_link(node: RcuPtrRef<'_, T>) -> RcuPtrRef<'_, Link>;
82
83 fn from_link(link: RcuPtrRef<'_, Link>) -> RcuPtrRef<'_, T>;
85}
86
87#[derive(Debug)]
88pub struct RcuIntrusiveList<T, A: RcuListAdapter<T>> {
89 head: RcuPtr<Link>,
93
94 tail: RcuPtr<Link>,
98
99 _marker: std::marker::PhantomData<(T, A)>,
100}
101
102impl<T, A: RcuListAdapter<T>> Default for RcuIntrusiveList<T, A> {
103 fn default() -> Self {
104 Self::new(RcuPtr::null(), RcuPtr::null())
105 }
106}
107
108impl<T, A: RcuListAdapter<T>> RcuIntrusiveList<T, A> {
109 pub(crate) fn new(head: RcuPtr<Link>, tail: RcuPtr<Link>) -> Self {
111 Self { head, tail, _marker: std::marker::PhantomData }
112 }
113
114 pub unsafe fn push_front<'a>(&self, scope: &'a RcuReadScope, data: RcuPtrRef<'a, T>) {
120 let link_ptr = A::to_link(data);
121 let link = link_ptr.as_ref().unwrap();
122 let head_ptr = self.head.read(&scope);
123 if let Some(head) = head_ptr.as_ref() {
124 head.prev.assign_ptr(link_ptr);
125 link.next.assign_ptr(head_ptr);
126 } else {
127 self.tail.assign_ptr(link_ptr);
128 }
129 self.head.assign_ptr(link_ptr);
130 }
131
132 pub unsafe fn push_back<'a>(&self, scope: &RcuReadScope, data: RcuPtrRef<'a, T>) {
138 let link_ptr = A::to_link(data);
139 let link = link_ptr.as_ref().unwrap();
140 let tail_ptr = self.tail.read(&scope);
141 if let Some(tail) = tail_ptr.as_ref() {
142 link.prev.assign_ptr(tail_ptr);
143 tail.next.assign_ptr(link_ptr);
144 } else {
145 self.head.assign_ptr(link_ptr);
146 }
147 self.tail.assign_ptr(link_ptr);
148 }
149
150 pub unsafe fn append(&self, scope: &RcuReadScope, other: Self) {
156 let other_head_ptr = other.head.read(&scope);
157 if let Some(other_head) = other_head_ptr.as_ref() {
158 let tail_ptr = self.tail.read(&scope);
159 if let Some(tail) = tail_ptr.as_ref() {
160 tail.next.assign_ptr(other_head_ptr);
161 other_head.prev.assign_ptr(tail_ptr);
162 } else {
163 self.head.assign_ptr(other_head_ptr);
164 }
165 let other_tail_ptr = other.tail.read(&scope);
166 assert!(!other_tail_ptr.is_null());
167 self.tail.assign_ptr(other_tail_ptr);
168 }
169 other.head.assign(std::ptr::null_mut());
170 other.tail.assign(std::ptr::null_mut());
171 }
172
173 pub unsafe fn remove<'a>(
181 &self,
182 scope: &'a RcuReadScope,
183 node: RcuPtrRef<'a, T>,
184 ) -> RcuPtrRef<'a, Link> {
185 let link_ptr = A::to_link(node);
186 let link = link_ptr.as_ref().unwrap();
187
188 let prev = link.prev.read(scope);
189 let next = link.next.read(scope);
190
191 if let Some(next) = next.as_ref() {
192 next.prev.assign_ptr(prev);
193 } else {
194 self.tail.assign_ptr(prev);
195 }
196 if let Some(prev) = prev.as_ref() {
197 prev.next.assign_ptr(next);
198 } else {
199 self.head.assign_ptr(next);
200 }
201
202 link.prev.poison();
205
206 next
207 }
208
209 pub unsafe fn split_off(&self, scope: &RcuReadScope, pos: usize) -> Self {
217 if pos == 0 {
220 let head = RcuPtr::new(self.head.replace(std::ptr::null_mut()));
221 let tail = RcuPtr::new(self.tail.replace(std::ptr::null_mut()));
222 return Self::new(head, tail);
223 }
224 let mut i = 1;
225 let mut prev_ptr = self.head.read(&scope);
226 while let Some(prev) = prev_ptr.as_ref() {
227 if i == pos {
228 let head = prev.next.replace(std::ptr::null_mut());
229 if head.is_null() {
230 break;
232 }
233 let tail = self.tail.read(&scope);
234 self.tail.assign_ptr(prev_ptr);
235 return Self::new(RcuPtr::new(head), RcuPtr::new(tail.as_mut_ptr()));
236 }
237 prev_ptr = prev.next.read(&scope);
238 i += 1;
239 }
240 Self::default()
242 }
243
244 pub unsafe fn update(&self, scope: &RcuReadScope, other: Self) {
250 self.head.assign_ptr(other.head.read(scope));
251 self.tail.assign_ptr(other.tail.read(scope));
252 }
253
254 pub unsafe fn clear<'a>(&self, scope: &'a RcuReadScope, callback: impl Fn(RcuPtrRef<'a, T>))
266 where
267 T: 'static,
268 {
269 let mut current = self.head.read(scope);
270
271 self.head.assign(std::ptr::null_mut());
272 self.tail.assign(std::ptr::null_mut());
273
274 while let Some(link) = current.as_ref() {
275 let next = link.next.read(scope);
276
277 link.prev.poison();
280 callback(A::from_link(current));
281 current = next;
282 }
283 }
284
285 #[cfg(test)]
286 pub(crate) fn is_empty(&self, scope: &RcuReadScope) -> bool {
287 self.head.read(scope).is_null()
288 }
289
290 pub fn cursor<'a>(&'a self, scope: &'a RcuReadScope) -> RcuIntrusiveListCursor<'a, T, A> {
295 let current = self.head.read(scope);
296 RcuIntrusiveListCursor { scope, list: self, current }
297 }
298
299 pub fn iter<'a>(&self, scope: &'a RcuReadScope) -> impl Iterator<Item = &'a T>
301 where
302 T: 'static,
303 {
304 let next = self.head.read(&scope);
305 RcuIntrusiveListIter::<T, A> { scope, next, _marker: std::marker::PhantomData }
306 }
307}
308
309pub struct RcuIntrusiveListCursor<'a, T, A: RcuListAdapter<T>> {
313 scope: &'a RcuReadScope,
314 list: &'a RcuIntrusiveList<T, A>,
315 current: RcuPtrRef<'a, Link>,
316}
317
318impl<'a, T, A: RcuListAdapter<T>> RcuIntrusiveListCursor<'a, T, A> {
319 pub fn current(&self) -> Option<&'a T> {
321 let node = A::from_link(self.current);
322 node.as_ref()
323 }
324
325 pub fn advance(&mut self) {
327 if let Some(link) = self.current.as_ref() {
328 self.current = link.next.read(&self.scope);
329 }
330 }
331
332 pub unsafe fn remove(&mut self) -> RcuPtrRef<'a, T> {
346 if self.current.is_null() {
347 return RcuPtrRef::null();
348 }
349 let removed_node = A::from_link(self.current);
350 unsafe {
352 self.current = self.list.remove(&self.scope, removed_node);
353 }
354 removed_node
355 }
356}
357
358struct RcuIntrusiveListIter<'a, T, A: RcuListAdapter<T>> {
359 scope: &'a RcuReadScope,
360 next: RcuPtrRef<'a, Link>,
361 _marker: std::marker::PhantomData<(T, A)>,
362}
363
364impl<'a, T: 'static, A: RcuListAdapter<T>> Iterator for RcuIntrusiveListIter<'a, T, A> {
365 type Item = &'a T;
366
367 fn next(&mut self) -> Option<Self::Item> {
368 if let Some(link) = self.next.as_ref() {
369 let current = self.next;
370 self.next = link.next.read(&self.scope);
371 Some(A::from_link(current).as_ref().unwrap())
372 } else {
373 None
374 }
375 }
376}