nolock 0.4.1

A collection of Lock-Free Datastructures
Documentation
use std::{fmt::Debug, sync::atomic};

use crate::allocator::lrmalloc::{descriptor::Descriptor, util::list::List};

pub struct Collection {
    list: List<atomic::AtomicPtr<Descriptor>>,
}

impl Collection {
    pub const fn new() -> Self {
        Self {
            list: List::new(atomic::AtomicPtr::new(std::ptr::null_mut())),
        }
    }

    pub fn insert(&self, descriptor: *mut Descriptor) {
        for a_ptr in self.list.iter() {
            if !a_ptr.load(atomic::Ordering::Acquire).is_null() {
                continue;
            }

            if a_ptr
                .compare_exchange(
                    std::ptr::null_mut(),
                    descriptor,
                    atomic::Ordering::AcqRel,
                    atomic::Ordering::Relaxed,
                )
                .is_ok()
            {
                return;
            }
        }

        self.list.append(atomic::AtomicPtr::new(descriptor));
    }

    pub fn get(&self, ptr: *mut u8) -> Option<*mut Descriptor> {
        for a_ptr in self.list.iter() {
            let desc_ptr = a_ptr.load(atomic::Ordering::Acquire);
            if desc_ptr.is_null() {
                continue;
            }

            let desc = unsafe { &*desc_ptr };

            if desc.contains(ptr) {
                return Some(desc_ptr);
            }
        }

        None
    }

    pub fn remove(&self, descriptor: *mut Descriptor) {
        for a_ptr in self.list.iter() {
            let desc_ptr = a_ptr.load(atomic::Ordering::Acquire);
            if desc_ptr == descriptor {
                let _ = a_ptr.compare_exchange(
                    desc_ptr,
                    std::ptr::null_mut(),
                    atomic::Ordering::AcqRel,
                    atomic::Ordering::Relaxed,
                );
            }
        }
    }
}

unsafe impl Sync for Collection {}

impl Debug for Collection {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[")?;

        for a_ptr in self.list.iter() {
            let ptr = a_ptr.load(atomic::Ordering::SeqCst);
            if ptr.is_null() {
                write!(f, "{:p},", ptr)?;
            } else {
                let desc = unsafe { &*ptr };
                write!(f, "{:?},", desc)?;
            }
        }

        write!(f, "]")?;
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn insert_descriptor() {
        let collection = Collection::new();

        collection.insert(0x123 as *mut Descriptor);
    }

    #[test]
    fn insert_get() {
        let collection = Collection::new();

        let desc_ptr = Box::into_raw(Box::new(Descriptor::new(
            128,
            4,
            Some(1),
            0x1000 as *mut u8,
        )));

        collection.insert(desc_ptr);

        let result = collection.get(0x1000 as *mut u8);
        assert_eq!(Some(desc_ptr), result);
    }
}