#![no_std]
#![feature(const_fn)]
use core::ptr::null_mut;
use core::mem::size_of;
pub use crate::error::Error;
use crate::error::Error::*;
mod error;
pub trait Clear {
fn clear(&mut self);
}
struct Linked<T> where T: Clear {
next: *mut Linked<T>,
data: T,
}
impl<T> Clear for Linked<T> where T: Clear {
fn clear(&mut self) {
self.data.clear();
}
}
pub struct StaticLinkedList<'buf, T> where T: Clear {
size: usize,
head: *mut Linked<T>,
tail: *mut Linked<T>,
array: *mut StaticLinkedListBackingArray<'buf, T>
}
impl<'buf, T> StaticLinkedList<'buf, T> where T: Clear {
pub fn size(&self) -> usize {
self.size
}
pub fn free_space(&self) -> usize {
if self.array.is_null() {
0
} else {
unsafe {
(*self.array).free_space()
}
}
}
pub fn append(&mut self, data: T) -> Result<(), Error> {
if self.array.is_null() {
Err(NullPointer)
} else {
unsafe {
if let Some(new) = (*self.array).get_free() {
(*new).data = data;
if self.tail.is_null() {
self.head = new;
} else {
(*self.tail).next = new;
}
(*new).next = null_mut();
self.tail = new;
self.size += 1;
Ok(())
} else {
Err(OutOfSpace)
}
}
}
}
pub fn prepend(&mut self, data: T) -> Result<&mut Self, Error> {
if self.array.is_null() {
Err(NullPointer)
} else {
unsafe {
if let Some(new) = (*self.array).get_free() {
(*new).data = data;
if self.tail.is_null() {
self.tail = new;
}
(*new).next = self.head;
self.head = new;
self.size += 1;
Ok(self)
} else {
Err(OutOfSpace)
}
}
}
}
pub fn head(&self) -> Option<&T> {
if self.head.is_null() {
None
} else {
unsafe {
Some(&(*self.head).data)
}
}
}
pub fn tail(&self) -> Option<&T> {
if self.tail.is_null() {
None
} else {
unsafe {
Some(&(*self.tail).data)
}
}
}
pub fn at(&self, index: usize) -> Result<&T, Error> {
if index >= self.size() {
Err(IndexOutOfBounds)
} else {
let mut i = 0;
let mut iter = self.into_iter();
while i != index {
iter.next();
i += 1;
}
Ok(iter.next().unwrap())
}
}
pub fn remove_head(&mut self) -> Result<&mut Self, Error> {
if !self.head.is_null() {
unsafe {
if let Some(p) = self.array.as_mut() {
(*self.head).data.clear();
if self.head == self.tail {
self.tail = null_mut();
}
let to_remove = self.head;
self.head = (*self.head).next;
p.free(to_remove.as_mut().unwrap());
self.size -= 1;
Ok(self)
} else {
Err(OutOfSpace)
}
}
} else {
Err(HeadIsNull)
}
}
pub fn remove_all_satisfying(&mut self, predicate: fn(&T) -> bool) -> Result<&mut Self, Error> {
let mut cursor = self.head;
let mut prev = null_mut();
unsafe {
while !cursor.is_null() {
if predicate(&(*cursor).data) {
let to_remove = cursor;
if to_remove == self.head {
self.head = (*cursor).next;
}
if to_remove == self.tail {
self.tail = prev;
}
if !prev.is_null() {
(*prev).next = (*cursor).next;
}
(*self.array).free(to_remove.as_mut().unwrap());
self.size -= 1;
} else {
prev = cursor;
}
cursor = (*cursor).next;
}
Ok(self)
}
}
}
impl<'buf, T> Drop for StaticLinkedList<'buf, T> where T: Clear {
fn drop(&mut self) {
if self.array.is_null() {
return;
}
while self.size() > 0 {
self.remove_head().unwrap();
}
unsafe {
(*self.array).drop_list();
}
}
}
pub struct StaticLinkedListIterator<'a, T> where T: Clear {
cursor: *mut Linked<T>,
_phantom: &'a core::marker::PhantomData<T>,
}
impl<'a, T> StaticLinkedListIterator<'a, T> where T: Clear {
fn new(list: &'a StaticLinkedList<T>) -> Self {
StaticLinkedListIterator {
cursor: list.head,
_phantom: &core::marker::PhantomData::<T>,
}
}
}
impl<'a, T> Iterator for StaticLinkedListIterator<'a, T> where T: Clear {
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
unsafe {
if self.cursor.is_null() {
None
} else {
let ret = &(*self.cursor).data;
self.cursor = (*self.cursor).next;
Some(ret)
}
}
}
}
impl<'l, 'buf, T> IntoIterator for &'l StaticLinkedList<'buf, T> where T: Clear {
type Item = &'l T;
type IntoIter = StaticLinkedListIterator<'l, T>;
fn into_iter(self) -> StaticLinkedListIterator<'l, T> {
StaticLinkedListIterator::<'l, T>::new(self)
}
}
pub struct StaticLinkedListBackingArray<'buf, T> where T: Clear {
capacity: usize,
free_space: usize,
lists: usize,
_buf: &'buf mut [u8], free: *mut Linked<T>, }
impl<'buf, T> StaticLinkedListBackingArray<'buf, T> where T: Clear {
pub const fn capacity_for(n: usize) -> usize {
n * size_of::<Linked<T>>()
}
pub fn new(buf: &'buf mut [u8]) -> Result<Self, Error> {
if core::mem::size_of::<T>() == 0 {
Err(ZeroSizedType)
} else {
let linkedbuf = buf.as_mut_ptr() as *mut Linked<T>;
let capacity = buf.len() / size_of::<Linked<T>>();
unsafe {
let mut cursor = linkedbuf;
for _i in 0..(capacity - 1) {
(*cursor).next = cursor.add(1);
cursor.as_mut().unwrap().clear();
cursor = (*cursor).next;
}
(*cursor).next = null_mut();
}
Ok(StaticLinkedListBackingArray {
capacity: capacity,
free_space: capacity,
lists: 0,
_buf: buf,
free: linkedbuf,
})
}
}
pub fn capacity(&self) -> usize {
self.capacity
}
pub fn free_space(&self) -> usize {
self.free_space
}
unsafe fn get_free(&mut self) -> Option<*mut Linked<T>> {
if self.free.is_null() {
None
} else {
let to_return = self.free;
self.free = (*self.free).next;
self.free_space -= 1;
Some(to_return)
}
}
fn free(&mut self, link: &mut Linked<T>) {
link.clear();
link.next = self.free;
self.free = link;
self.free_space += 1;
}
pub fn is_full(&self) -> bool {
self.free_space == 0
}
pub fn lists(&self) -> usize {
self.lists
}
fn drop_list(&mut self) {
self.lists -= 1;
}
pub fn new_list(&mut self) -> StaticLinkedList<'buf, T> {
self.lists += 1;
StaticLinkedList {
size: 0,
head: core::ptr::null_mut(),
tail: core::ptr::null_mut(),
array: self as *mut StaticLinkedListBackingArray<'buf, T>
}
}
}
#[cfg(test)]
mod tests;