use libc; use crate::other::*; #[derive(Copy, Clone)] #[repr(C)] pub struct clistcell { pub data: *mut libc::c_void, pub previous: *mut clistcell, pub next: *mut clistcell, } #[derive(Clone)] #[repr(C)] pub struct clist { pub first: *mut clistcell, pub last: *mut clistcell, pub count: libc::c_int, } impl Default for clist { fn default() -> Self { Self { first: std::ptr::null_mut(), last: std::ptr::null_mut(), count: 0, } } } impl Drop for clist { fn drop(&mut self) { unsafe { let mut l1 = self.first; while !l1.is_null() { let l2 = (*l1).next; free(l1 as *mut libc::c_void); l1 = l2 } } } } pub type clistiter = clistcell; pub struct CListIterator { cur: *mut clistiter, } impl Iterator for CListIterator { type Item = *mut libc::c_void; fn next(&mut self) -> Option { unsafe { if self.cur.is_null() { None } else { let data = (*self.cur).data; self.cur = (*self.cur).next; Some(data) } } } } impl IntoIterator for &clist { type Item = *mut libc::c_void; type IntoIter = CListIterator; fn into_iter(self) -> Self::IntoIter { return CListIterator { cur: self.first }; } } pub type clist_func = Option ()>; /* Allocate a new pointer list */ pub fn clist_new() -> *mut clist { Box::into_raw(Box::new(Default::default())) } /* Destroys a list. Data pointed by data pointers is NOT freed. */ pub unsafe fn clist_free(mut lst: *mut clist) { Box::from_raw(lst); } /* Inserts this data pointer after the element pointed by the iterator */ pub unsafe fn clist_insert_after( mut lst: *mut clist, mut iter: *mut clistiter, mut data: *mut libc::c_void, ) -> libc::c_int { let mut c: *mut clistcell = 0 as *mut clistcell; c = malloc(::std::mem::size_of::() as libc::size_t) as *mut clistcell; if c.is_null() { return -1i32; } (*c).data = data; (*lst).count += 1; if (*lst).first == (*lst).last && (*lst).last.is_null() { (*c).next = 0 as *mut clistcell; (*c).previous = (*c).next; (*lst).last = c; (*lst).first = (*lst).last; return 0i32; } if iter.is_null() { (*c).previous = (*lst).last; (*(*c).previous).next = c; (*c).next = 0 as *mut clistcell; (*lst).last = c; return 0i32; } (*c).previous = iter; (*c).next = (*iter).next; if !(*c).next.is_null() { (*(*c).next).previous = c } else { (*lst).last = c } (*(*c).previous).next = c; return 0i32; } /* Deletes the element pointed by the iterator. Returns an iterator to the next element. */ pub unsafe fn clist_delete(mut lst: *mut clist, mut iter: *mut clistiter) -> *mut clistiter { let mut ret: *mut clistiter = 0 as *mut clistiter; if iter.is_null() { return 0 as *mut clistiter; } if !(*iter).previous.is_null() { (*(*iter).previous).next = (*iter).next } else { (*lst).first = (*iter).next } if !(*iter).next.is_null() { (*(*iter).next).previous = (*iter).previous; ret = (*iter).next } else { (*lst).last = (*iter).previous; ret = 0 as *mut clistiter } free(iter as *mut libc::c_void); (*lst).count -= 1; return ret; } pub unsafe fn clist_foreach( mut lst: *mut clist, mut func: clist_func, mut data: *mut libc::c_void, ) { let mut cur: *mut clistiter = 0 as *mut clistiter; cur = (*lst).first; while !cur.is_null() { func.expect("non-null function pointer")((*cur).data, data); cur = (*cur).next } } pub unsafe fn clist_nth_data(mut lst: *mut clist, mut indx: libc::c_int) -> *mut libc::c_void { let mut cur: *mut clistiter = 0 as *mut clistiter; cur = internal_clist_nth(lst, indx); if cur.is_null() { return 0 as *mut libc::c_void; } return (*cur).data; } #[inline] unsafe fn internal_clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter { let mut cur: *mut clistiter = 0 as *mut clistiter; cur = (*lst).first; while indx > 0i32 && !cur.is_null() { cur = (*cur).next; indx -= 1 } if cur.is_null() { return 0 as *mut clistiter; } return cur; } pub unsafe fn clist_nth(mut lst: *mut clist, mut indx: libc::c_int) -> *mut clistiter { return internal_clist_nth(lst, indx); } #[cfg(test)] mod tests { use super::*; use std::ptr; #[test] fn test_clist_iterator() { unsafe { let mut c = clist_new(); assert!(!c.is_null()); clist_insert_after(c, ptr::null_mut(), clist_nth as _); assert_eq!((*c).count, 1); /* Only one iteration */ for data in &*c { assert_eq!(data, clist_nth as _); } assert_eq!((*c).count, 1); clist_free(c); } } }