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