use std::any::Any;
use std::fmt::Display;
use std::marker::PhantomData;
use bitvec::prelude::*;
use optics::traits::{AffineFoldRef, AffineFoldMut};
use crate::curve::concrete::KeyframeCurve;
use super::AnyCurve;
use super::animatable::Animatable;
use super::concrete::{CurveContent, CurveContentStatic};
pub trait AnyCurveBuilder {
fn push_keyframe(&mut self, k: u16, x: &mut dyn Any);
fn finish_boxed(self: Box<Self>) -> Option<Box<dyn AnyCurve>>;
}
#[derive(Default)]
#[allow(missing_debug_implementations)]
pub struct CurveBuilder<C> {
indices: Vec<u16>,
contents: C,
}
impl<C: CurveContentBuilder> CurveBuilder<C> {
pub fn new() -> CurveBuilder<C> { CurveBuilder::default() }
pub fn push_keyframe(&mut self, k: u16, x: <C::Target as CurveContentStatic>::Keyframe) {
self.indices.push(k);
self.contents.push_keyframe(x);
}
pub fn into_dynamic<F, S>(self, field_accessor: F) -> Box<dyn AnyCurveBuilder>
where S: 'static, C::Target: CurveContent<Keyframe=F::View>,
F: Send + Sync + 'static
+ for<'a> AffineFoldRef<'a, S>
+ for<'a> AffineFoldMut<'a, S>,
F::View: PartialEq + Animatable + Sized + Send + Sync + 'static,
F::Error: Display {
Box::new(DynCurveBuilder {
builder: self,
field_accessor,
_marker: PhantomData,
})
}
pub fn finish<F, S>(self, field_accessor: F) -> Option<Box<dyn AnyCurve>>
where S: 'static, C::Target: CurveContent<Keyframe=F::View>,
F: Send + Sync + 'static
+ for<'a> AffineFoldRef<'a, S>
+ for<'a> AffineFoldMut<'a, S>,
F::View: PartialEq + Animatable + Sized + Send + Sync + 'static,
F::Error: Display {
if self.indices.is_empty() { return None; }
Some(Box::new(KeyframeCurve::new(
field_accessor.to_str_err(),
self.indices.into_boxed_slice(),
self.contents.finish(),
)))
}
}
struct DynCurveBuilder<C, F, S> {
builder: CurveBuilder<C>,
field_accessor: F,
_marker: PhantomData<fn() -> S>,
}
impl<C, F, S> AnyCurveBuilder for DynCurveBuilder<C, F, S>
where S: 'static, C: CurveContentBuilder,
C::Target: CurveContent<Keyframe=F::View>,
F: Send + Sync + 'static
+ for<'a> AffineFoldRef<'a, S>
+ for<'a> AffineFoldMut<'a, S>,
F::View: PartialEq + Animatable + Sized + Send + Sync + 'static,
F::Error: Display {
fn push_keyframe(&mut self, k: u16, x: &mut dyn Any) {
let x = x.downcast_mut::<Option<F::View>>()
.expect("check the type before use").take()
.expect("should call with '&mut Some(x)'");
self.builder.push_keyframe(k, x);
}
fn finish_boxed(self: Box<Self>) -> Option<Box<dyn AnyCurve>> {
self.builder.finish(self.field_accessor)
}
}
pub trait CurveContentBuilder: Default + Sized + 'static {
type Target: CurveContent + Send + Sync;
fn push_keyframe(&mut self, x: <Self::Target as CurveContentStatic>::Keyframe);
fn finish(self) -> Self::Target;
}
impl<T: Send + Sync + 'static> CurveContentBuilder for Vec<T> {
type Target = Box<[T]>;
fn push_keyframe(&mut self, x: T) { self.push(x) }
fn finish(self) -> Box<[T]> { self.into_boxed_slice() }
}
impl<T, O> CurveContentBuilder for BitVec<T, O>
where T: BitStore + Send + Sync + 'static,
O: BitOrder + Send + Sync + 'static {
type Target = BitBox<T, O>;
fn push_keyframe(&mut self, x: bool) { self.push(x) }
fn finish(self) -> Self::Target { self.into_boxed_bitslice() }
}