use super::edit_log::*;
use super::pending_log::*;
use super::vector_layer::*;
use super::super::traits::*;
use super::super::editor::*;
use std::sync::*;
use std::collections::*;
use std::time::Duration;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
struct AnimationCore {
edit_log: InMemoryEditLog<AnimationEdit>,
next_element_id: i64,
size: (f64, f64),
layers: HashMap<u64, Box<Layer>>,
}
pub struct InMemoryAnimation {
core: Arc<Mutex<AnimationCore>>,
}
impl InMemoryAnimation {
pub fn new() -> InMemoryAnimation {
let core = AnimationCore {
edit_log: InMemoryEditLog::new(),
size: (1980.0, 1080.0),
next_element_id: 0,
layers: HashMap::new()
};
InMemoryAnimation {
core: Arc::new(Mutex::new(core)),
}
}
pub fn perform_edits(&self, edits: Vec<AnimationEdit>) {
let mut editor = self.edit();
editor.set_pending(&edits);
editor.commit_pending();
}
}
struct CoreLayerRef<'a, CoreRef: 'a>(CoreRef, u64, PhantomData<&'a CoreRef>);
impl<'a, CoreRef: Deref<Target=AnimationCore>> Deref for CoreLayerRef<'a, CoreRef> {
type Target = Layer+'a;
fn deref(&self) -> &Self::Target {
&**self.0.layers.get(&self.1).unwrap()
}
}
impl<'a, CoreRef: Deref<Target=AnimationCore>+DerefMut> DerefMut for CoreLayerRef<'a, CoreRef> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut **self.0.layers.get_mut(&self.1).unwrap()
}
}
impl Animation for InMemoryAnimation {
fn size(&self) -> (f64, f64) {
(*self.core).lock().unwrap().size
}
fn duration(&self) -> Duration {
Duration::from_millis(1000 * 120)
}
fn frame_length(&self) -> Duration {
Duration::new(0, 1_000_000_000 / 30)
}
fn get_layer_ids(&self) -> Vec<u64> {
(*self.core).lock().unwrap()
.layers.keys().cloned().collect()
}
fn get_layer_with_id<'a>(&'a self, layer_id: u64) -> Option<Reader<'a, Layer>> {
let core = (*self.core).lock().unwrap();
if core.layers.contains_key(&layer_id) {
let layer_ref = CoreLayerRef(core, layer_id, PhantomData);
let reader = Reader::new(layer_ref);
Some(reader)
} else {
None
}
}
fn get_log<'a>(&'a self) -> Reader<'a, EditLog<AnimationEdit>> {
let core: &Mutex<EditLog<AnimationEdit>> = &*self.core;
Reader::new(core.lock().unwrap())
}
fn edit<'a>(&'a self) -> Editor<'a, PendingEditLog<AnimationEdit>> {
let core = self.core.clone();
let edit_log = InMemoryPendingLog::new(move |edits| core.lock().unwrap().commit_edits(edits));
let edit_log: Box<'a+PendingEditLog<AnimationEdit>> = Box::new(edit_log);
Editor::new(edit_log)
}
fn edit_layer<'a>(&'a self, layer_id: u64) -> Editor<'a, PendingEditLog<LayerEdit>> {
let core = self.core.clone();
let edit_log = InMemoryPendingLog::new(move |edits| {
let edits = edits.into_iter()
.map(|edit| AnimationEdit::Layer(layer_id, edit));
core.lock().unwrap().commit_edits(edits)
});
let edit_log: Box<'a+PendingEditLog<LayerEdit>> = Box::new(edit_log);
Editor::new(edit_log)
}
}
impl AnimationCore {
fn commit_edits<I: IntoIterator<Item=AnimationEdit>>(&mut self, edits: I) {
let editor = AnimationEditor::new();
let mut assigned_edits = vec![];
for edit in edits {
assigned_edits.push(edit.assign_element_id(|| {
let id = self.next_element_id;
self.next_element_id += 1;
id
}));
}
editor.perform(self, assigned_edits.iter().cloned());
self.edit_log.commit_edits(assigned_edits);
}
}
impl MutableAnimation for AnimationCore {
fn set_size(&mut self, size: (f64, f64)) {
self.size = size;
}
fn add_layer(&mut self, new_layer_id: u64) {
self.layers.entry(new_layer_id)
.or_insert_with(|| {
let layer = InMemoryVectorLayer::new(new_layer_id);
Box::new(layer)
});
}
fn remove_layer(&mut self, old_layer_id: u64) {
self.layers.remove(&old_layer_id);
}
fn edit_layer<'a>(&'a mut self, layer_id: u64) -> Option<Editor<'a, Layer>> {
if self.layers.contains_key(&layer_id) {
let layer_ref = CoreLayerRef(self, layer_id, PhantomData);
let reader = Editor::new(layer_ref);
Some(reader)
} else {
None
}
}
}
impl EditLog<AnimationEdit> for AnimationCore {
fn length(&self) -> usize {
self.edit_log.length()
}
fn read(&self, indices: &mut Iterator<Item=usize>) -> Vec<AnimationEdit> {
self.edit_log.read(indices)
}
}
#[cfg(test)]
mod test {
use super::*;
use std::time::Duration;
#[test]
fn can_add_layer() {
let animation = InMemoryAnimation::new();
assert!(animation.get_layer_ids().len() == 0);
animation.perform_edits(vec![
AnimationEdit::AddNewLayer(0)
]);
assert!(animation.get_layer_ids().len() == 1);
}
#[test]
fn can_remove_layer() {
let animation = InMemoryAnimation::new();
let keep1 = 0;
let keep2 = 1;
let to_remove = 2;
let keep3 = 3;
animation.perform_edits(vec![
AnimationEdit::AddNewLayer(keep1),
AnimationEdit::AddNewLayer(keep2),
AnimationEdit::AddNewLayer(to_remove),
AnimationEdit::AddNewLayer(keep3),
]);
let mut ids = animation.get_layer_ids();
ids.sort();
assert!(ids == vec![keep1, keep2, to_remove, keep3]);
animation.perform_edits(vec![
AnimationEdit::RemoveLayer(to_remove)
]);
let mut ids = animation.get_layer_ids();
ids.sort();
assert!(ids == vec![keep1, keep2, keep3]);
}
#[test]
fn will_assign_element_ids() {
let animation = InMemoryAnimation::new();
animation.perform_edits(vec![
AnimationEdit::AddNewLayer(0),
AnimationEdit::Layer(0, LayerEdit::AddKeyFrame(Duration::from_millis(0))),
AnimationEdit::Layer(0, LayerEdit::Paint(Duration::from_millis(0), PaintEdit::BrushStroke(ElementId::Unassigned, Arc::new(vec![
RawPoint::from((10.0, 10.0)),
RawPoint::from((20.0, 5.0))
]))))
]);
let edit_log = animation.get_log();
let paint_edit = edit_log.read(&mut (2..3));
assert!(match &paint_edit[0] { &AnimationEdit::Layer(0, LayerEdit::Paint(_, _)) => true, _ => false });
assert!(match &paint_edit[0] { &AnimationEdit::Layer(0, LayerEdit::Paint(_, PaintEdit::BrushStroke(ElementId::Assigned(_), _))) => true, _ => false });
}
#[test]
fn can_draw_brush_stroke() {
let animation = InMemoryAnimation::new();
animation.perform_edits(vec![
AnimationEdit::AddNewLayer(0),
]);
assert!(animation.get_layer_ids().len() == 1);
animation.perform_edits(vec![
AnimationEdit::Layer(0, LayerEdit::AddKeyFrame(Duration::from_millis(0))),
]);
{
let mut layer_edit = animation.edit_layer(0);
layer_edit.set_pending(&vec![
LayerEdit::Paint(Duration::from_millis(442), PaintEdit::BrushStroke(ElementId::Unassigned, Arc::new(vec![
RawPoint::from((10.0, 10.0)),
RawPoint::from((20.0, 5.0))
])))
]);
layer_edit.commit_pending();
}
}
}