use core::ptr;
use alloc::boxed::Box;
use super::base::{Iter, IterMut, NtSingleListEntry, NtSingleListHead};
use super::traits::NtSingleList;
use crate::traits::{NtBoxedListElement, NtListElement, NtTypedList};
#[repr(transparent)]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub struct NtBoxingSingleListHead<
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
>(NtSingleListHead<E, L>);
impl<E, L> NtBoxingSingleListHead<E, L>
where
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
{
pub fn new() -> Self {
Self(NtSingleListHead::<E, L>::new())
}
pub fn clear(&mut self) {
let mut current = self.0.next;
self.0.clear();
while !current.is_null() {
unsafe {
let next = (*current).next;
let element = NtSingleListEntry::<E, L>::containing_record_mut(current);
drop(Box::from_raw(element));
current = next;
}
}
}
pub fn front(&self) -> Option<&E> {
unsafe { self.0.front() }
}
pub fn front_mut(&mut self) -> Option<&mut E> {
unsafe { self.0.front_mut() }
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter(&self) -> Iter<E, L> {
unsafe { self.0.iter() }
}
pub fn iter_mut(&mut self) -> IterMut<E, L> {
unsafe { self.0.iter_mut() }
}
pub fn len(&self) -> usize {
unsafe { self.0.len() }
}
pub fn pop_front(&mut self) -> Option<Box<E>> {
unsafe { self.0.pop_front().map(|element| Box::from_raw(element)) }
}
pub fn push_front(&mut self, element: E) {
let boxed_element = Box::new(element);
unsafe { self.0.push_front(Box::leak(boxed_element)) }
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&mut E) -> bool,
{
let mut previous = (self as *mut Self).cast();
let mut current = self.0.next;
while !current.is_null() {
unsafe {
let next = (*current).next;
let element = NtSingleListEntry::containing_record_mut(current);
if f(element) {
previous = current;
current = next;
} else {
(*previous).next = next;
current = next;
drop(Box::from_raw(element));
}
}
}
}
}
impl<E, L> Default for NtBoxingSingleListHead<E, L>
where
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
{
fn default() -> Self {
Self::new()
}
}
impl<E, L> Drop for NtBoxingSingleListHead<E, L>
where
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
{
fn drop(&mut self) {
for element in self.iter_mut() {
unsafe {
drop(Box::from_raw(element));
}
}
}
}
impl<E, L> FromIterator<Box<E>> for NtBoxingSingleListHead<E, L>
where
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Box<E>>,
{
let mut list = NtBoxingSingleListHead::<E, L>::new();
let mut previous =
(&mut list.0 as *mut NtSingleListHead<E, L>).cast::<NtSingleListEntry<E, L>>();
for element in iter.into_iter() {
unsafe {
let entry = NtSingleListHead::entry(Box::leak(element));
(*entry).next = ptr::null_mut();
(*previous).next = entry;
previous = entry;
}
}
list
}
}
impl<E, L> FromIterator<E> for NtBoxingSingleListHead<E, L>
where
E: NtBoxedListElement<L = L> + NtListElement<L>,
L: NtTypedList<T = NtSingleList>,
{
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = E>,
{
iter.into_iter().map(Box::new).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::single_list::NtSingleListEntry;
#[derive(NtSingleList)]
enum MyList {}
#[derive(Default, NtListElement)]
#[repr(C)]
struct MyElement {
value: i32,
#[boxed]
entry: NtSingleListEntry<Self, MyList>,
}
impl MyElement {
fn new(value: i32) -> Self {
Self {
value,
..Default::default()
}
}
}
#[test]
fn test_from_iter() {
let integers = [0, 1, 2, 3, 4, 5];
let list = integers
.into_iter()
.map(MyElement::new)
.collect::<NtBoxingSingleListHead<MyElement, MyList>>();
for (i, element) in integers.into_iter().zip(list.iter()) {
assert_eq!(i, element.value);
}
}
#[test]
fn test_front() {
let mut list = NtBoxingSingleListHead::<MyElement, MyList>::new();
for i in 0..=3 {
list.push_front(MyElement::new(i));
}
assert_eq!(list.front().unwrap().value, 3);
assert_eq!(list.front_mut().unwrap().value, 3);
}
#[test]
fn test_pop_front() {
let mut list = NtBoxingSingleListHead::<MyElement, MyList>::new();
for i in 0..10 {
list.push_front(MyElement::new(i));
}
for i in (0..10).rev() {
let element = list.pop_front().unwrap();
assert_eq!(i, element.value);
}
assert!(list.is_empty());
}
#[test]
fn test_push_front() {
let mut list = NtBoxingSingleListHead::<MyElement, MyList>::new();
for i in 0..10 {
list.push_front(MyElement::new(i));
}
assert_eq!(list.len(), 10);
for (i, element) in (0..10).rev().zip(list.iter()) {
assert_eq!(i, element.value);
}
}
#[test]
fn test_retain() {
let mut list = NtBoxingSingleListHead::<MyElement, MyList>::new();
for i in 0..10 {
list.push_front(MyElement::new(i));
}
list.retain(|element| element.value % 2 == 0);
assert_eq!(list.len(), 5);
for (i, element) in (0..=8).rev().step_by(2).zip(list.iter()) {
assert_eq!(i, element.value);
}
list.retain(|element| element.value == 8 || element.value == 0);
let mut iter = list.iter();
assert_eq!(iter.next().unwrap().value, 8);
assert_eq!(iter.next().unwrap().value, 0);
assert!(matches!(iter.next(), None));
}
}