propertybindings 0.0.3

Experimental rust-based QML-like language.
use core::ptr;
use core::ptr::NonNull;
use core::cell::Cell;
use core::pin::Pin;
/*
pub trait PinRef<T> : Copy {
    fn as_ptr(self) -> *const T;
    fn from_ptr(ptr: *const T) -> Self;
    fn default() -> Self;
}

impl<T> PinRef<T> for *const T {
    fn as_ptr(self) -> *const T { self }
    fn from_ptr(ptr: *const T) -> Self { ptr };
    fn default() -> Self { core::ptr::null() };
}
*/

pub trait PtrCell<T> {
    //unsafe fn get(self: Pin<&Self>) -> Option<&Pin<T>>;
    //unsafe fn set(self: Pin<&Self>, value: Option<&Pin<T>>);
    fn get(&self) -> *const T;
    fn set(&self, ptr: *const T);
    fn default() -> Self;

    unsafe fn get_node<L: LinkedList<NodePtr = Self> + ?Sized>(&self) -> *const Node<L>
        where Self: PtrCell<L::NodeItem> + Sized
    {
        let n : *const L::NodeItem = self.get();
        if n.is_null() {
            ptr::null()
        } else {
            L::node(unsafe { Pin::new_unchecked(&*n) }).get_ref() as *const _
        }
    }
}

impl<T> PtrCell<T> for Cell<*const T> {
    fn get(&self) -> *const T { self.get() }
    fn set(&self, ptr: *const T) { self.set(ptr) }
    fn default() -> Self { Cell::new(core::ptr::null()) }
}

pub trait LinkedList {
    /// Type of the element, in which the Node is embedded as a field
    type NodeItem;

    /// Type of the pointer that represent a head
    type NodePtr : PtrCell<Self::NodeItem>;

    /// Projection to the node within the item
    fn node(node: Pin<&Self::NodeItem>) -> Pin<&Node<Self>>;
}

pub struct Node<L: LinkedList + ?Sized> {
    next: L::NodePtr,
    prev: Cell<*const L::NodePtr>,
    phantom: core::marker::PhantomPinned,
}

impl<L: LinkedList + ?Sized> Default for Node<L> {
    fn default() -> Self {
        Node {
            next: L::NodePtr::default(),
            prev: Cell::new(core::ptr::null()),
            phantom: core::marker::PhantomPinned,
        }
    }
}

impl<L: LinkedList + ?Sized> Node<L> {
    /*fn next(&self) -> *const Self {
        let n = self.next.get();
        if n.is_null() {
            ptr::null()
        } else {
            L::node(unsafe { &*n }) as *const _
        }
    }*/

    fn verify(&self) {
        unsafe {
            let n : *const Self = self.next.get_node();
            debug_assert!(n.is_null() || ptr::eq((*n).prev.get(), &self.next as *const _));
            let p = self.prev.get();
            debug_assert!(!p.is_null() || ptr::eq( (*p).get_node(), self as *const _));
        }
    }
}


impl<L: LinkedList + ?Sized> Drop for Node<L> {
    fn drop(&mut self) {
        self.verify();

        let prev = self.prev.get();
        let next : *const Self = unsafe { self.next.get_node() };
        if !next.is_null() {
            unsafe { (*next).prev.set(prev) };
        }
        if !prev.is_null() {
            unsafe { (*prev).set(self.next.get()) };
        }

        // *self = Default::default();
    }
}

struct NodeIter<'a, L: LinkedList + ?Sized>(&'a L::NodePtr);

impl<'a, L: LinkedList + ?Sized> Iterator for NodeIter<L> {
    type Item = NonNull<L::NodeItem>;
    fn next(&mut self) -> Option<Self::Item> {
        let r = NonNull::new(self.0);
        r.as_ref()
            .map(|n| unsafe { self.0 = L::next_ptr(*n).as_ref().next });
        return r;
    }
}

pub struct Head<L: LinkedList + ?Sized>(L::NodePtr);

impl<L: LinkedList + ?Sized> Default for Head<L> {
    fn default() -> Self {
        Head(ptr::null_mut())
    }
}

impl<L: LinkedList + ?Sized> Head<L> {
    pub unsafe fn append(&mut self, node: NonNull<L::NodeItem>) {
        let mut node_node = L::next_ptr(node);
        node_node.as_mut().next = self.0;
        node_node.as_mut().prev = &mut self.0 as *mut *mut L::NodeItem;
        if !self.0.is_null() {
            L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev =
                &mut node_node.as_mut().next as *mut _
        }
        self.0 = node.as_ptr();
    }

    // Not safe because it breaks if the list is modified while iterating.
    fn iter(&mut self) -> NodeIter<L> {
        return NodeIter(self.0);
    }

    pub fn swap(&mut self, other: &mut Self) {
        unsafe {
            ::std::mem::swap(&mut self.0, &mut other.0);
            if !self.0.is_null() {
                L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev = self.0 as *mut _;
            }
            if !other.0.is_null() {
                L::next_ptr(NonNull::new_unchecked(other.0)).as_mut().prev = other.0 as *mut _;
            }
        }
    }

    pub fn clear(&mut self) {
        unsafe {
            for x in self.iter() {
                Box::from_raw(x.as_ptr());
            }
        }
    }
}

impl<L: LinkedList + ?Sized> Iterator for Head<L> {
    type Item = Box<L::NodeItem>;
    fn next(&mut self) -> Option<Self::Item> {
        NonNull::new(self.0).map(|n| unsafe {
            let mut node_node = L::next_ptr(n);
            self.0 = node_node.as_ref().next;
            if !self.0.is_null() {
                L::next_ptr(NonNull::new_unchecked(self.0)).as_mut().prev =
                    &mut self.0 as *mut _;
            }
            node_node.as_mut().prev = ::std::ptr::null_mut();
            node_node.as_mut().next = ::std::ptr::null_mut();
            Box::from_raw(n.as_ptr())
        })
    }
}

impl<L: LinkedList + ?Sized> Drop for Head<L> {
    fn drop(&mut self) {
        self.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    enum TestList {}
    #[derive(Default)]
    struct TestNode {
        elem: u32,
        list: Node<TestList>,
    }
    impl LinkedList for TestList {
        type NodeItem = TestNode;
        unsafe fn next_ptr(mut node: NonNull<Self::NodeItem>) -> NonNull<Node<Self>> {
            NonNull::new_unchecked(&mut node.as_mut().list as *mut _)
        }
    }
    impl TestNode {
        fn new(v: u32) -> Self {
            TestNode {
                elem: v,
                ..Default::default()
            }
        }
    }

    #[test]
    fn list_append() {
        let mut l: Head<TestList> = Default::default();
        assert_eq!(l.iter().count(), 0);
        unsafe {
            l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
                TestNode::new(10),
            ))));
        }
        assert_eq!(l.iter().count(), 1);
        unsafe {
            l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
                TestNode::new(20),
            ))));
        }
        assert_eq!(l.iter().count(), 2);
        unsafe {
            l.append(NonNull::new_unchecked(Box::into_raw(Box::new(
                TestNode::new(30),
            ))));
        }
        assert_eq!(l.iter().count(), 3);
        assert_eq!(
            l.iter()
                .map(|x| unsafe { x.as_ref().elem })
                .collect::<Vec<u32>>(),
            vec![30, 20, 10]
        );
        // take a ptr to the second element;
        let ptr = l.iter().nth(1).unwrap();
        assert_eq!(unsafe { ptr.as_ref().elem }, 20);
        unsafe {
            Box::from_raw(ptr.as_ptr());
        }
        assert_eq!(l.iter().count(), 2);
        assert_eq!(
            l.iter()
                .map(|x| unsafe { x.as_ref().elem })
                .collect::<Vec<u32>>(),
            vec![30, 10]
        );
    }
}
*/