obj-pool 0.7.0

A simple object arena
Documentation
use obj_pool::{ObjId, ObjPool};

struct Node<T> {
    /// Previous node in the list.
    prev: Option<ObjId>,

    /// Next node in the list.
    next: Option<ObjId>,

    /// Actual value stored in node.
    value: T,
}

struct List<T> {
    /// This is where nodes are stored.
    obj_pool: ObjPool<Node<T>>,

    /// First node in the list.
    head: Option<ObjId>,

    /// Last node in the list.
    tail: Option<ObjId>,
}

impl<T> List<T> {
    /// Constructs a new, empty doubly linked list.
    fn new() -> Self {
        List {
            obj_pool: ObjPool::new(),
            head: None,
            tail: None,
        }
    }

    /// Returns the number of elements in the list.
    fn len(&self) -> usize {
        self.obj_pool.len() as usize
    }

    /// Links nodes `a` and `b` together, so that `a` comes before `b` in the list.
    fn link(&mut self, a: Option<ObjId>, b: Option<ObjId>) {
        if let Some(a) = a {
            self.obj_pool[a].next = b;
        }
        if let Some(b) = b {
            self.obj_pool[b].prev = a;
        }
    }

    /// Appends `value` to the back of the list.
    fn push_back(&mut self, value: T) -> usize {
        let node = self.obj_pool.insert(Node {
            prev: None,
            next: None,
            value,
        });

        let tail = self.tail;
        self.link(tail, Some(node));

        self.tail = Some(node);
        if self.head.is_none() {
            self.head = Some(node);
        }
        self.obj_pool.obj_id_to_index(node) as usize
    }

    /// Pops and returns the value at the front of the list.
    fn pop_front(&mut self) -> T {
        let head = self.head.expect("the list is empty");
        let node = self.obj_pool.remove(head).unwrap();

        self.link(None, node.next);
        self.head = node.next;
        if node.next.is_none() {
            self.tail = None;
        }
        node.value
    }

    /// Removes the element specified by `index`.
    fn remove(&mut self, index: usize) -> T {
        let obj_id = self.obj_pool.index_to_obj_id(index as u32);
        let node = self.obj_pool.remove(obj_id).unwrap();

        self.link(node.prev, node.next);
        if self.head == Some(obj_id) {
            self.head = node.next;
        }
        if self.tail == Some(obj_id) {
            self.tail = node.prev;
        }

        node.value
    }
}

fn main() {
    let mut list = List::new();

    // The list is now [].

    let one = list.push_back(1);
    list.push_back(2);
    list.push_back(3);

    // The list is now [1, 2, 3].

    list.push_back(10);
    let twenty = list.push_back(20);
    list.push_back(30);

    // The list is now [1, 2, 3, 10, 20, 30].

    assert_eq!(list.len(), 6);

    assert_eq!(list.remove(one), 1);
    assert_eq!(list.remove(twenty), 20);

    // The list is now [2, 3, 10, 30].

    assert_eq!(list.len(), 4);

    assert_eq!(list.pop_front(), 2);
    assert_eq!(list.pop_front(), 3);
    assert_eq!(list.pop_front(), 10);
    assert_eq!(list.pop_front(), 30);

    // The list is now [].

    assert_eq!(list.len(), 0);
}