use crate::sir::FrameExpr;
use num_rational::Rational64;
pub trait SpecContext {}
pub trait Spec: Sync + Send {
fn timestamps(&self, context: &dyn SpecContext) -> Vec<Rational64>;
fn render(&self, context: &dyn SpecContext, t: &Rational64) -> FrameExpr;
}
pub(crate) fn get_framerate(spec: &dyn Spec) -> usize {
let context = crate::dve::EmptySpecCtx;
let frame_times = spec.timestamps(&context);
let mut frame_deltas = frame_times.windows(2).map(|w| w[1] - w[0]);
let first_delta = frame_deltas.next().unwrap_or(Rational64::new(1, 30));
assert!(frame_deltas.all(|d| d == first_delta));
assert_eq!(*first_delta.numer(), 1, "Frame rate must be an integer");
*first_delta.denom() as usize
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct JsonSpec {
pub frames: Vec<(Rational64, FrameExpr)>,
}
impl Spec for JsonSpec {
fn timestamps(&self, _context: &dyn SpecContext) -> Vec<Rational64> {
self.frames.iter().map(|(t, _)| *t).collect()
}
fn render(&self, _context: &dyn SpecContext, t: &Rational64) -> FrameExpr {
let index = self
.frames
.binary_search_by(|(t2, _)| t2.partial_cmp(t).unwrap())
.unwrap();
self.frames[index].1.clone()
}
}