game_kernel_utils 0.1.0

Miscellaneous utilities for game_kernel
Documentation
extern crate evmap;
extern crate parking_lot;

use self::evmap::ShallowCopy;
use self::parking_lot::Mutex;

pub type Keytype = u64;

#[derive(Hash, Eq, PartialEq)]
pub struct HierarchyIndexer {
    last_index: Keytype,
}

impl HierarchyIndexer {
    pub fn new() -> Self {
        Self { last_index: 1 } //we start from 1 because 0 is the root
    }
    pub fn get_index(&mut self) -> Keytype {
        self.last_index += 1;
        self.last_index
    }
}

pub struct AdjHashMap {
    pub r: evmap::ReadHandle<Keytype, Keytype>,
    pub w: Mutex<evmap::WriteHandle<Keytype, Keytype>>,
    indexer: HierarchyIndexer,
}

impl AdjHashMap {
    pub fn new() -> Self {
        let (r, mut w) = evmap::new();
        Self {
            r,
            w: Mutex::new(w),
            indexer: HierarchyIndexer::new(),
        }
    }
    pub fn exists(&self, index: &Keytype) -> bool {
        if *index == 0u64 {
            return true;
        }
        self.r.get(index).is_some()
    }

    pub fn insert_entity(&mut self, parent: &Keytype) -> Option<Keytype> {
        if !self.exists(parent) {
            return None;
        }
        let mut hierarchy_w = self.w.lock();

        let new_index: Keytype = self.indexer.get_index();

        hierarchy_w.insert(parent.clone(), new_index);
        hierarchy_w.refresh();
        Some(new_index)
    }

    pub fn insert_parent(&mut self, children: &[Keytype]) -> Option<Keytype> {
        let mut hierarchy_w = self.w.lock();

        let parent: Keytype = self.indexer.get_index();
        for child in children {
            hierarchy_w.insert(parent.clone(), child.clone());
        }
        hierarchy_w.refresh();
        Some(parent)
    }
}

pub mod utils {
    pub enum RecursiveOpError<E> {
        NotFound(),
        OpError(E),
    }

    impl<E> RecursiveOpError<E> {
        pub fn map_to_op(self, mapper: fn(Self) -> E) -> E {
            if let Self::OpError(e) = self {
                e
            } else {
                mapper(self)
            }
        }
    }

    use super::*;
    //moves all the children from one parent to a new one, return false if it can't find
    //the new parent, true otherwise
    pub fn move_children(
        hierarchy: &mut AdjHashMap,
        old_parent: &Keytype,
        new_parent: &Keytype,
    ) -> bool {
        let mut hierarchy_w = hierarchy.w.lock();
        let hierarchy_r = &hierarchy.r;
        //checks if the new parent exists
        if !hierarchy.exists(new_parent) {
            return false;
        }
        //copies all the children of old_parent to the new parent
        for child in hierarchy_r.get(&old_parent).unwrap().iter() {
            hierarchy_w.insert(new_parent.clone(), (*child).clone());
        }
        //removes the children from the old parent
        hierarchy_w.clear(old_parent.clone());
        hierarchy_w.flush();

        true
    }

    //executes function recursively
    pub fn recursive_op<E>(
        hierarchy: &AdjHashMap,
        parent: &Keytype,
        pre_op: Option<&Fn(&Keytype) -> Result<(), E>>,
        post_op: Option<&Fn(&Keytype) -> Result<(), E>>,
    ) -> Result<(), RecursiveOpError<E>> {
        let hierarchy_r = &hierarchy.r.clone();
        //if the parent hasn't been found return an error
        if !hierarchy.exists(parent) {
            return Err(RecursiveOpError::NotFound());
        }
        //if the current parent is a lief the function returns
        if hierarchy_r.get(parent).unwrap().is_empty() {
            return Ok(());
        }

        for child in hierarchy_r.get(parent).unwrap().iter() {
            if let Some(pre_op) = pre_op {
                if let Err(error) = pre_op(child) {
                    return Err(RecursiveOpError::OpError(error));
                }
            }
            recursive_op(hierarchy, child, pre_op, post_op);
            if let Some(post_op) = post_op {
                if let Err(error) = post_op(child) {
                    return Err(RecursiveOpError::OpError(error));
                }
            }
        }
        Ok(())
    }

    //deletes entities recursively
    pub fn recursive_delete(
        hierarchy: &mut AdjHashMap,
        parent: &Keytype,
        on_removed: &Fn(&Keytype),
    ) -> bool {
        let hierarchy_r = &hierarchy.r.clone();
        //if the parent hasn't been found we return false
        if !hierarchy.exists(parent) {
            return false;
        }
        //if the current parent is a lief the function returns
        if hierarchy_r.get(parent).unwrap().is_empty() {
            return true;
        }

        for child in hierarchy_r.get(parent).unwrap().iter() {
            on_removed(child);
            recursive_delete(hierarchy, child, on_removed);
        }
        //at  this point we lock the mutex, if that happened before the recursive call we would
        // get a dead lock
        let mut hierarchy_w = hierarchy.w.lock();
        hierarchy_w.clear(parent.clone());
        true
    }
}