alchemy-lifecycle 0.1.0

A crate containing traits used in Alchemy, the Rust cross-platform GUI framework.
Documentation
//! Implements storage for Component instances, in a way that allows us to 
//! short-circuit the rendering process so we don't have to re-scan entire 
//! tree structures when updating state.

use std::collections::HashMap;

pub use alchemy_styles::Appearance;

use crate::reconciler::error::{RenderEngineError as Error};
use crate::reconciler::instance::Instance;
use crate::reconciler::key::{Allocator, Id, INSTANCE_ALLOCATOR, ComponentKey};

/// This is a clone of a structure you'll also find over in stretch. We do this separately 
/// here for two reasons.
///
/// - First, a Component may have children that don't require styles or layout passes. These nodes 
/// should not have `Style` or `Appearance` nodes created, but we do need the correct parent/child 
/// relationships in place.
/// - The `Storage` pieces of stretch are realistically an implementation detail that we shouldn't 
/// rely on. 
struct Storage<T>(HashMap<ComponentKey, T>);

impl<T> Storage<T> {
    pub fn new() -> Self {
        Storage(HashMap::new())
    }

    pub fn get(&self, key: ComponentKey) -> Result<&T, Error> {
        match self.0.get(&key) {
            Some(v) => Ok(v),
            None => Err(Error::InvalidComponentKey(key)),
        }
    }

    pub fn get_mut(&mut self, key: ComponentKey) -> Result<&mut T, Error> {
        match self.0.get_mut(&key) {
            Some(v) => Ok(v),
            None => Err(Error::InvalidComponentKey(key)),
        }
    }

    pub fn remove(&mut self, key: ComponentKey) -> Result<T, Error> {
        match self.0.remove(&key) {
            Some(v) => Ok(v),
            None => Err(Error::InvalidComponentKey(key))
        }
    }

    pub fn insert(&mut self, key: ComponentKey, value: T) -> Option<T> {
        self.0.insert(key, value)
    }
}

impl<T> std::ops::Index<&ComponentKey> for Storage<T> {
    type Output = T;

    fn index(&self, idx: &ComponentKey) -> &T {
        &(self.0)[idx]
    }
}

pub(crate) struct ComponentStore {
    id: Id,
    nodes: Allocator,
    components: Storage<Instance>,
    parents: Storage<Vec<ComponentKey>>,
    children: Storage<Vec<ComponentKey>>
}

impl ComponentStore {
    pub fn new() -> Self {
        ComponentStore {
            id: INSTANCE_ALLOCATOR.lock().unwrap().allocate(),
            nodes: Allocator::new(),
            components: Storage::new(),
            parents: Storage::new(),
            children: Storage::new()
        }
    }

    pub fn new_key(&mut self) -> ComponentKey {
        let local = self.nodes.allocate();
        ComponentKey { instance: self.id, local }
    }

    pub fn insert(
        &mut self,
        key: ComponentKey,
        instance: Instance
    ) -> Result<(), Error> {
        /*for child in &children {
            self.parents.get_mut(*child)?.push(key);
        }*/

        self.components.insert(key, instance);
        self.parents.insert(key, Vec::with_capacity(1));
        self.children.insert(key, vec![]); //children);

        Ok(())
    }

    pub fn remove(&mut self, key: ComponentKey) -> Result<Instance, Error> {
        self.parents.remove(key)?;
        self.children.remove(key)?;
        self.components.remove(key)
    }

    pub fn add_child(&mut self, key: ComponentKey, child: ComponentKey) -> Result<(), Error> {
        self.parents.get_mut(child)?.push(key);
        self.children.get_mut(key)?.push(child);
        Ok(())
    }

    pub fn set_children(&mut self, key: ComponentKey, children: Vec<ComponentKey>) -> Result<(), Error> {
        // Remove node as parent from all its current children.
        for child in self.children.get(key)? {
            self.parents.get_mut(*child)?.retain(|p| *p != key);
        }

        *self.children.get_mut(key)? = Vec::with_capacity(children.len());

        // Build up relation node <-> child
        for child in children {
            self.parents.get_mut(child)?.push(key);
            self.children.get_mut(key)?.push(child);
        }

        Ok(())
    }

    pub fn remove_child(&mut self, key: ComponentKey, child: ComponentKey) -> Result<ComponentKey, Error> {
        match self.children(key)?.iter().position(|n| *n == child) {
            Some(index) => self.remove_child_at_index(key, index),
            None => Err(Error::InvalidComponentKey(child)),
        }
    }

    pub fn remove_child_at_index(&mut self, key: ComponentKey, index: usize) -> Result<ComponentKey, Error> {
        let child = self.children.get_mut(key)?.remove(index);
        self.parents.get_mut(child)?.retain(|p| *p != key);
        Ok(child)
    }

    pub fn replace_child_at_index(&mut self, key: ComponentKey, index: usize, child: ComponentKey) -> Result<ComponentKey, Error> {
        self.parents.get_mut(child)?.push(key);
        let old_child = std::mem::replace(&mut self.children.get_mut(key)?[index], child);
        self.parents.get_mut(old_child)?.retain(|p| *p != key);
        Ok(old_child)
    }

    pub fn children(&self, key: ComponentKey) -> Result<Vec<ComponentKey>, Error> {
        self.children.get(key).map(Clone::clone)
    }

    pub fn child_count(&self, key: ComponentKey) -> Result<usize, Error> {
        self.children.get(key).map(Vec::len)
    }

    pub fn get(&self, key: ComponentKey) -> Result<&Instance, Error> {
        self.components.get(key)
    }
    
    pub fn get_mut(&mut self, key: ComponentKey) -> Result<&mut Instance, Error> {
        self.components.get_mut(key)
    }
}