use crate::{Frame, Motion, MotionState};
use std::{collections::HashMap, hash::Hash, time::Duration};
#[derive(Debug, Default)]
struct Entry {
state: MotionState,
batch: u64,
}
#[derive(Debug)]
pub struct Motions<K> {
entries: HashMap<K, Box<Entry>>,
batch: u64,
last: Duration,
#[cfg(feature = "gpui")]
pub(crate) epoch: Option<std::time::Instant>,
}
impl<K> Default for Motions<K> {
fn default() -> Self {
Self::new()
}
}
impl<K> Motions<K> {
pub fn new() -> Self {
Self::with_capacity(0)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
entries: HashMap::with_capacity(capacity),
batch: 0,
last: Duration::ZERO,
#[cfg(feature = "gpui")]
epoch: None,
}
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn capacity(&self) -> usize {
self.entries.capacity()
}
pub fn clear(&mut self) {
self.entries.clear();
}
}
impl<K: Eq + Hash> Motions<K> {
pub fn sample<const N: usize>(
&mut self,
declarations: [(K, Motion); N],
now: Duration,
reduced_motion: bool,
) -> [Frame; N] {
self.last = self.last.max(now);
self.batch = self.batch.wrapping_add(1);
if self.batch == 0 {
for entry in self.entries.values_mut() {
entry.batch = 0;
}
self.batch = 1;
}
declarations.map(|(key, motion)| {
let entry = self.entries.entry(key).or_default();
assert_ne!(entry.batch, self.batch, "duplicate key in Motions batch");
entry.batch = self.batch;
entry.state.sample(motion, self.last, reduced_motion)
})
}
pub fn sample_one(
&mut self,
key: K,
motion: Motion,
now: Duration,
reduced_motion: bool,
) -> Frame {
self.last = self.last.max(now);
self.entries
.entry(key)
.or_default()
.state
.sample(motion, self.last, reduced_motion)
}
pub fn contains_key(&self, key: &K) -> bool {
self.entries.contains_key(key)
}
pub fn remove(&mut self, key: &K) -> bool {
self.entries.remove(key).is_some()
}
pub fn retain(&mut self, mut keep: impl FnMut(&K) -> bool) {
self.entries.retain(|key, _| keep(key));
}
pub fn reserve(&mut self, additional: usize) {
self.entries.reserve(additional);
}
pub fn shrink_to_fit(&mut self) {
self.entries.shrink_to_fit();
}
}