use std::collections::{btree_map, BTreeMap};
use crate::component::{Component, ComponentTypeID};
use crate::component_data::ComponentValueRef;
use crate::entity::EntityID;
use crate::snapshot::{Edit, EditAction};
#[derive(Clone, Debug)]
enum ComponentAction {
Set(usize, usize),
Remove,
}
#[derive(Clone, Debug)]
pub struct CommandBuffer {
component_data: Vec<u8>,
commands: BTreeMap<(EntityID, ComponentTypeID), ComponentAction>,
}
impl CommandBuffer {
pub fn new() -> CommandBuffer {
CommandBuffer {
component_data: Vec::new(),
commands: BTreeMap::new(),
}
}
pub fn merge(buffers: &[&CommandBuffer]) -> CommandBuffer {
let mut dest = CommandBuffer::new();
let max_data = buffers.iter()
.fold(0, |data, buffer| {
data + buffer.component_data.len()
});
dest.component_data.reserve(max_data);
let mut entity_merger = EntityMerger::new();
let mut iters = buffers.iter()
.map(|b| b.commands.iter().peekable())
.collect::<Vec<_>>();
loop {
let next_entity = iters.iter_mut()
.filter_map(|i| i.peek().map(|e| e.0.0))
.min();
if next_entity.is_none() {
break;
}
let next_entity = next_entity.unwrap();
for (buffer_idx, i) in iters.iter_mut().enumerate() {
let ok = i.peek().map_or(false, |x| x.0.0 == next_entity);
if !ok {
continue;
}
while i.peek().map_or(false, |x| x.0.0 == next_entity) {
let ((_, type_id), action) = i.next().unwrap();
let new_action = match action {
ComponentAction::Set(start, end) =>
EntityMergeAction::Set(buffer_idx, *start, *end),
ComponentAction::Remove => EntityMergeAction::Remove,
};
entity_merger.insert(*type_id, new_action);
}
}
assert!(!entity_merger.entries.is_empty());
for (type_id, action) in entity_merger.entries.iter() {
let new_action = match action {
EntityMergeAction::Set(buffer, start, end) => {
let offset = dest.component_data.len();
dest.component_data.extend_from_slice(
&buffers[*buffer].component_data[*start..*end]);
ComponentAction::Set(offset, offset + end - start)
}
EntityMergeAction::Remove => ComponentAction::Remove
};
dest.commands.insert((next_entity, *type_id), new_action);
}
entity_merger.clear();
}
dest
}
pub fn iter_edits(&self) -> CommandBufferIterator<'_> {
CommandBufferIterator::new(self)
}
pub fn set_component<T: Component>(&mut self, entity_id: EntityID, component: &T) {
let v = ComponentValueRef::from(component);
let data = v.as_slice();
let start = self.component_data.len();
let end = start + data.len();
self.component_data.extend_from_slice(data);
self.commands.insert(
(entity_id, v.type_id()),
ComponentAction::Set(start, end));
}
pub fn remove_component<T: Component>(&mut self, entity_id: EntityID) {
self.commands.insert((entity_id, T::type_id()), ComponentAction::Remove);
}
}
pub struct CommandBufferIterator<'a> {
buffer: &'a CommandBuffer,
iter: btree_map::Iter<'a, (EntityID, ComponentTypeID), ComponentAction>,
}
impl<'a> CommandBufferIterator<'a> {
fn new(buffer: &'a CommandBuffer) -> CommandBufferIterator<'a> {
let iter = buffer.commands.iter();
CommandBufferIterator {
buffer,
iter,
}
}
}
impl<'a> Iterator for CommandBufferIterator<'a> {
type Item = Edit<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self.iter.next() {
None => None,
Some(((id, type_id), command)) => {
let action = match command {
ComponentAction::Set(start, end) => unsafe {
EditAction::SetComponent(ComponentValueRef::from_raw(
*type_id,
&self.buffer.component_data[*start..*end],
))
},
ComponentAction::Remove => EditAction::RemoveComponent(*type_id),
};
Some(Edit(*id, action))
}
}
}
}
enum EntityMergeAction {
Set(usize, usize, usize),
Remove,
}
struct EntityMerger {
entries: Vec<(ComponentTypeID, EntityMergeAction)>,
}
impl EntityMerger {
pub fn new() -> EntityMerger {
EntityMerger {
entries: Vec::new(),
}
}
pub fn clear(&mut self) {
self.entries.clear();
}
pub fn insert(&mut self, type_id: ComponentTypeID, action: EntityMergeAction) {
match self.entries.binary_search_by_key(&type_id, |e| e.0) {
Ok(idx) => { self.entries[idx].1 = action; }
Err(idx) => { self.entries.insert(idx, (type_id, action)); }
}
}
}