use std::cell::RefCell;
use std::collections::HashMap;
use super::{Container, Platform};
pub enum Command<P>
where
P: Platform + ?Sized,
{
Mount(
P::ContainerID,
P::ContainerID,
Box<dyn FnOnce(&mut P::Container, &mut P::Environment) -> P::Container + Send>,
),
Mutate(
Vec<P::ContainerID>,
Box<dyn FnOnce(&mut [&mut P::Container], &mut P::Environment) + Send>,
),
Unmount(P::ContainerID),
}
pub trait CommandBuffer<P>
where
P: Platform + ?Sized,
{
fn mount<F>(&mut self, parent_id: P::ContainerID, initializer: F) -> P::ContainerID
where
F: FnOnce(&mut P::Container, &mut P::Environment) -> P::Container + Send + 'static;
fn mutate<F>(&mut self, ids: &[P::ContainerID], mutator: F)
where
F: FnOnce(&mut [&mut P::Container], &mut P::Environment) + Send + 'static;
fn unmount(&mut self, id: P::ContainerID);
fn layout(&mut self);
fn commit(self);
}
pub trait Compositor<P>
where
P: Platform + ?Sized,
{
fn buffer(&self) -> P::CommandBuffer;
}
pub struct Composition<P>
where
P: Platform + ?Sized,
{
map: HashMap<P::ContainerID, RefCell<P::Container>>,
}
impl<P> Composition<P>
where
P: Platform + ?Sized,
{
pub fn insert(&mut self, id: P::ContainerID, container: P::Container) {
self.map.insert(id, RefCell::new(container));
}
pub fn process(&mut self, environment: &mut P::Environment, command: Command<P>) {
match command {
Command::Mount(id, parent_id, initializer) => {
let container = if let Some(parent) = self.map.get_mut(&parent_id) {
let mut parent = parent.borrow_mut();
let mut container = initializer(&mut *parent, environment);
parent.mount(&mut container, environment);
container
} else {
return;
};
self.map.insert(id, RefCell::new(container));
}
Command::Mutate(ids, mutation) => {
let borrows = ids
.into_iter()
.map(|id| self.map.get(&id).map(|container| container.borrow_mut()))
.collect::<Option<Vec<_>>>();
if let Some(mut borrows) = borrows {
let mut containers = borrows
.iter_mut()
.map(|borrow| &mut **borrow)
.collect::<Vec<_>>();
mutation(containers.as_mut_slice(), environment);
}
}
Command::Unmount(id) => {
if let Some(container) = self.map.remove(&id) {
container.borrow_mut().unmount();
}
}
}
}
}
impl<P> Default for Composition<P>
where
P: Platform + ?Sized,
{
fn default() -> Self {
Composition {
map: HashMap::new(),
}
}
}