1use core::ptr;
2
3use crate::bindings::ngx_queue_t;
4
5#[macro_export]
12macro_rules! ngx_queue_data {
13 ($q:expr, $type:path, $link:ident) => {
14 $q.byte_sub(::core::mem::offset_of!($type, $link)).cast::<$type>()
15 };
16}
17
18#[inline]
24pub unsafe fn ngx_queue_init(q: *mut ngx_queue_t) {
25 (*q).prev = q;
26 (*q).next = q;
27}
28
29#[inline]
35pub unsafe fn ngx_queue_empty(q: *const ngx_queue_t) -> bool {
36 q == (*q).prev
37}
38
39#[inline]
45pub unsafe fn ngx_queue_insert_after(q: *mut ngx_queue_t, x: *mut ngx_queue_t) {
46 (*x).next = (*q).next;
47 (*(*x).next).prev = x;
48 (*x).prev = q;
49 (*q).next = x;
50}
51
52#[inline]
58pub unsafe fn ngx_queue_insert_before(q: *mut ngx_queue_t, x: *mut ngx_queue_t) {
59 (*x).prev = (*q).prev;
60 (*(*x).prev).next = x;
61 (*x).next = q;
62 (*q).prev = x;
63}
64
65#[inline]
71pub unsafe fn ngx_queue_remove(q: *mut ngx_queue_t) {
72 (*(*q).next).prev = (*q).prev;
73 (*(*q).prev).next = (*q).next;
74 (*q).prev = ptr::null_mut();
75 (*q).next = ptr::null_mut();
76}
77
78#[inline]
86pub unsafe fn ngx_queue_split(h: *mut ngx_queue_t, q: *mut ngx_queue_t, n: *mut ngx_queue_t) {
87 (*n).prev = (*h).prev;
88 (*(*n).prev).next = n;
89 (*n).next = q;
90 (*h).prev = (*q).prev;
91 (*(*h).prev).next = h;
92 (*q).prev = n;
93}
94
95#[inline]
102pub unsafe fn ngx_queue_add(h: *mut ngx_queue_t, n: *mut ngx_queue_t) {
103 (*(*h).prev).next = (*n).next;
104 (*(*n).next).prev = (*h).prev;
105 (*h).prev = (*n).prev;
106 (*(*h).prev).next = h;
107}
108
109impl ngx_queue_t {
110 pub fn is_empty(&self) -> bool {
112 unsafe { ngx_queue_empty(self) }
113 }
114}
115
116impl Default for ngx_queue_t {
117 fn default() -> ngx_queue_t {
118 ngx_queue_t {
119 prev: ptr::null_mut(),
120 next: ptr::null_mut(),
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 extern crate alloc;
128 use alloc::boxed::Box;
129
130 use super::*;
131
132 struct TestData {
133 value: usize,
134 queue: ngx_queue_t,
135 }
136
137 impl TestData {
138 pub fn new(value: usize) -> *mut Self {
139 let mut x = Box::new(Self {
142 value,
143 queue: Default::default(),
144 });
145 unsafe { ngx_queue_init(ptr::addr_of_mut!(x.queue)) };
146 Box::into_raw(x)
147 }
148
149 pub unsafe fn free(x: *mut Self) {
150 let _ = Box::from_raw(x);
151 }
152 }
153
154 impl Drop for TestData {
155 fn drop(&mut self) {
156 if !self.queue.next.is_null() && !self.queue.is_empty() {
157 unsafe { ngx_queue_remove(ptr::addr_of_mut!(self.queue)) };
158 }
159 }
160 }
161
162 struct Iter {
163 h: *mut ngx_queue_t,
164 q: *mut ngx_queue_t,
165 next: fn(*mut ngx_queue_t) -> *mut ngx_queue_t,
166 }
167
168 impl Iter {
169 pub fn new(h: *mut ngx_queue_t) -> Self {
170 let next = |x: *mut ngx_queue_t| unsafe { (*x).next };
171 Self { h, q: next(h), next }
172 }
173
174 pub fn new_reverse(h: *mut ngx_queue_t) -> Self {
175 let next = |x: *mut ngx_queue_t| unsafe { (*x).prev };
176 Self { h, q: next(h), next }
177 }
178 }
179
180 impl Iterator for Iter {
181 type Item = *mut ngx_queue_t;
182
183 fn next(&mut self) -> Option<Self::Item> {
184 if self.h == self.q {
185 return None;
186 }
187
188 let item = self.q;
189 self.q = (self.next)(self.q);
190 Some(item)
191 }
192 }
193
194 #[test]
195 fn test_queue() {
196 fn value(q: *mut ngx_queue_t) -> usize {
197 unsafe { (*ngx_queue_data!(q, TestData, queue)).value }
198 }
199
200 fn cmp(h: *mut ngx_queue_t, other: &[usize]) -> bool {
202 Iter::new(h).map(value).eq(other.iter().cloned())
203 && Iter::new_reverse(h).map(value).eq(other.iter().rev().cloned())
204 }
205
206 unsafe {
209 let mut h1 = ngx_queue_t::default();
212 ngx_queue_init(ptr::addr_of_mut!(h1));
213
214 let mut h2 = ngx_queue_t::default();
215 ngx_queue_init(ptr::addr_of_mut!(h2));
216
217 for i in 1..=5 {
218 let elem = TestData::new(i);
219 ngx_queue_insert_before(ptr::addr_of_mut!(h1), ptr::addr_of_mut!((*elem).queue));
220
221 let elem = TestData::new(i);
222 ngx_queue_insert_after(ptr::addr_of_mut!(h2), ptr::addr_of_mut!((*elem).queue));
223 }
224
225 assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5]));
228 assert!(cmp(ptr::addr_of_mut!(h2), &[5, 4, 3, 2, 1]));
229
230 ngx_queue_add(ptr::addr_of_mut!(h1), ptr::addr_of_mut!(h2));
234
235 assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5, 5, 4, 3, 2, 1]));
236
237 ngx_queue_split(ptr::addr_of_mut!(h1), (*h2.next).next, ptr::addr_of_mut!(h2));
238
239 assert!(cmp(ptr::addr_of_mut!(h1), &[1, 2, 3, 4, 5, 5]));
240 assert!(cmp(ptr::addr_of_mut!(h2), &[4, 3, 2, 1]));
241
242 for q in Iter::new(ptr::addr_of_mut!(h1)) {
245 let td = ngx_queue_data!(q, TestData, queue);
246 TestData::free(td);
247 }
248 assert!(h1.is_empty());
249
250 for q in Iter::new(ptr::addr_of_mut!(h2)) {
251 let td = ngx_queue_data!(q, TestData, queue);
252 TestData::free(td);
253 }
254 assert!(h2.is_empty());
255 };
256 }
257}