wraith/structures/
list_entry.rs

1//! LIST_ENTRY doubly-linked list abstraction
2
3use core::marker::PhantomData;
4use core::ptr::NonNull;
5
6/// raw LIST_ENTRY structure matching Windows definition
7#[repr(C)]
8#[derive(Debug)]
9pub struct ListEntry {
10    pub flink: *mut ListEntry,
11    pub blink: *mut ListEntry,
12}
13
14impl ListEntry {
15    /// check if this entry is the list head (points to itself)
16    pub fn is_empty(&self) -> bool {
17        core::ptr::eq(self.flink, self as *const _ as *mut _)
18    }
19
20    /// get next entry in list (Flink)
21    ///
22    /// returns None if this is the last entry (points to head)
23    pub fn next(&self, head: *const ListEntry) -> Option<NonNull<ListEntry>> {
24        if core::ptr::eq(self.flink, head as *mut _) {
25            None
26        } else {
27            NonNull::new(self.flink)
28        }
29    }
30
31    /// get previous entry in list (Blink)
32    pub fn prev(&self, head: *const ListEntry) -> Option<NonNull<ListEntry>> {
33        if core::ptr::eq(self.blink, head as *mut _) {
34            None
35        } else {
36            NonNull::new(self.blink)
37        }
38    }
39}
40
41/// iterator over LIST_ENTRY chain
42pub struct ListEntryIter<'a, T> {
43    head: *const ListEntry,
44    current: *const ListEntry,
45    offset: usize,
46    _marker: PhantomData<&'a T>,
47}
48
49impl<'a, T> ListEntryIter<'a, T> {
50    /// create new iterator starting from head
51    ///
52    /// # Safety
53    /// - head must point to valid LIST_ENTRY
54    /// - offset must be correct offset of LIST_ENTRY within T
55    pub unsafe fn new(head: *const ListEntry, offset: usize) -> Self {
56        let first = unsafe { (*head).flink };
57        Self {
58            head,
59            current: first,
60            offset,
61            _marker: PhantomData,
62        }
63    }
64}
65
66impl<'a, T> Iterator for ListEntryIter<'a, T> {
67    type Item = &'a T;
68
69    fn next(&mut self) -> Option<Self::Item> {
70        // stop when we've wrapped back to head
71        if core::ptr::eq(self.current, self.head) {
72            return None;
73        }
74
75        // CONTAINING_RECORD macro equivalent
76        let container = unsafe {
77            let entry_addr = self.current as usize;
78            let container_addr = entry_addr - self.offset;
79            &*(container_addr as *const T)
80        };
81
82        // advance to next entry
83        self.current = unsafe { (*self.current).flink };
84
85        Some(container)
86    }
87}
88
89/// mutable iterator over LIST_ENTRY chain
90pub struct ListEntryIterMut<'a, T> {
91    head: *mut ListEntry,
92    current: *mut ListEntry,
93    offset: usize,
94    _marker: PhantomData<&'a mut T>,
95}
96
97impl<'a, T> ListEntryIterMut<'a, T> {
98    /// create new mutable iterator
99    ///
100    /// # Safety
101    /// - head must point to valid LIST_ENTRY
102    /// - offset must be correct offset of LIST_ENTRY within T
103    /// - caller must ensure exclusive access
104    pub unsafe fn new(head: *mut ListEntry, offset: usize) -> Self {
105        let first = unsafe { (*head).flink };
106        Self {
107            head,
108            current: first,
109            offset,
110            _marker: PhantomData,
111        }
112    }
113}
114
115impl<'a, T> Iterator for ListEntryIterMut<'a, T> {
116    type Item = &'a mut T;
117
118    fn next(&mut self) -> Option<Self::Item> {
119        if core::ptr::eq(self.current, self.head) {
120            return None;
121        }
122
123        let container = unsafe {
124            let entry_addr = self.current as usize;
125            let container_addr = entry_addr - self.offset;
126            &mut *(container_addr as *mut T)
127        };
128
129        self.current = unsafe { (*self.current).flink };
130
131        Some(container)
132    }
133}
134
135/// safely unlink an entry from its list
136///
137/// # Safety
138/// - entry must be part of a valid doubly-linked list
139/// - caller must handle any synchronization
140pub unsafe fn unlink_entry(entry: *mut ListEntry) {
141    unsafe {
142        let flink = (*entry).flink;
143        let blink = (*entry).blink;
144        (*blink).flink = flink;
145        (*flink).blink = blink;
146        // clear the entry's links to indicate it's unlinked
147        (*entry).flink = entry;
148        (*entry).blink = entry;
149    }
150}
151
152/// relink an entry back into a list after a specific entry
153///
154/// # Safety
155/// - after must be part of a valid list
156/// - entry must not currently be linked
157pub unsafe fn link_entry_after(entry: *mut ListEntry, after: *mut ListEntry) {
158    unsafe {
159        let next = (*after).flink;
160        (*entry).flink = next;
161        (*entry).blink = after;
162        (*after).flink = entry;
163        (*next).blink = entry;
164    }
165}