use crate::timestamp::Timestamped;
use std::{fmt::Debug, ops::Deref};
pub trait DisplayState: Send + Sync + Clone + Debug {
fn from_interpolation(state1: &Self, state2: &Self, t: f64) -> Self;
}
impl<T: DisplayState> DisplayState for Timestamped<T> {
fn from_interpolation(state1: &Self, state2: &Self, t: f64) -> Self {
if t == 0.0 {
state1.clone()
} else if (t - 1.0).abs() < f64::EPSILON {
state2.clone()
} else {
assert_eq!(state1.timestamp(), state2.timestamp(), "Can only interpolate between timestamped states of the same timestamp. If timestamps differ, you will need to use Tweened::from_interpolation to also interpolate the timestamp value into a float.");
Self::new(
DisplayState::from_interpolation(state1.inner(), state2.inner(), t),
state1.timestamp(),
)
}
}
}
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Tweened<T> {
display_state: T,
timestamp: f64,
}
impl<T: DisplayState> Tweened<T> {
pub fn display_state(&self) -> &T {
&self.display_state
}
pub fn float_timestamp(&self) -> f64 {
self.timestamp
}
}
impl<T: DisplayState> Deref for Tweened<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.display_state
}
}
impl<T: DisplayState> Tweened<T> {
pub fn from_interpolation(state1: &Timestamped<T>, state2: &Timestamped<T>, t: f64) -> Self {
let timestamp_difference: i16 = (state2.timestamp() - state1.timestamp()).into();
let timestamp_offset: f64 = t * (timestamp_difference as f64);
let timestamp_interpolated = i16::from(state1.timestamp()) as f64 + timestamp_offset;
Self {
display_state: T::from_interpolation(state1.inner(), state2.inner(), t),
timestamp: timestamp_interpolated,
}
}
}
impl<T: DisplayState> From<Timestamped<T>> for Tweened<T> {
fn from(timestamped: Timestamped<T>) -> Self {
Self {
display_state: timestamped.inner().clone(),
timestamp: i16::from(timestamped.timestamp()) as f64,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::timestamp::Timestamp;
#[derive(Clone, Default, Debug, PartialEq)]
struct MockDisplayState(f64);
impl DisplayState for MockDisplayState {
fn from_interpolation(state1: &Self, state2: &Self, t: f64) -> Self {
Self(state1.0 * t + state2.0 * (1.0 - t))
}
}
#[test]
fn when_interpolating_displaystate_with_t_0_then_state1_is_returned() {
let state1 = Timestamped::new(MockDisplayState(4.0), Timestamp::default() + 2);
let state2 = Timestamped::new(MockDisplayState(8.0), Timestamp::default() + 5);
let interpolated = DisplayState::from_interpolation(&state1, &state2, 0.0);
assert_eq!(state1, interpolated);
}
#[test]
fn when_interpolating_displaystate_with_t_1_then_state2_is_returned() {
let state1 = Timestamped::new(MockDisplayState(4.0), Timestamp::default() + 2);
let state2 = Timestamped::new(MockDisplayState(8.0), Timestamp::default() + 5);
let interpolated = DisplayState::from_interpolation(&state1, &state2, 1.0);
assert_eq!(state2, interpolated);
}
}