#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SliderEventType {
Head,
Tick,
Repeat,
LastTick,
Tail,
}
#[derive(Clone, Debug, PartialEq)]
pub struct SliderEvent {
pub kind: SliderEventType,
pub span_idx: i32,
pub span_start_time: f64,
pub time: f64,
pub path_progress: f64,
}
#[derive(Debug, PartialEq)]
pub struct SliderEventsIter<'ticks_buf> {
start_time: f64,
span_duration: f64,
min_dist_from_end: f64,
tick_dist: f64,
len: f64,
span_count: i32,
ticks: &'ticks_buf mut Vec<SliderEvent>,
state: SliderEventsIterState,
}
impl<'ticks_buf> SliderEventsIter<'ticks_buf> {
const MAX_LEN: f64 = 100_000.0;
const TAIL_LENIENCY: f64 = -36.0;
pub fn new(
start_time: f64,
span_duration: f64,
velocity: f64,
mut tick_dist: f64,
total_dist: f64,
span_count: i32,
ticks: &'ticks_buf mut Vec<SliderEvent>,
) -> Self {
let len = Self::MAX_LEN.min(total_dist);
tick_dist = tick_dist.clamp(0.0, len);
ticks.clear();
Self {
start_time,
span_duration,
min_dist_from_end: velocity * 10.0,
tick_dist,
len,
span_count,
ticks,
state: SliderEventsIterState::Head,
}
}
}
impl Iterator for SliderEventsIter<'_> {
type Item = SliderEvent;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.state {
SliderEventsIterState::Head => {
self.state = if self.tick_dist.abs() >= f64::EPSILON {
SliderEventsIterState::Ticks { span: 0 }
} else {
SliderEventsIterState::LastTick
};
return Some(SliderEvent {
kind: SliderEventType::Head,
span_idx: 0,
span_start_time: self.start_time,
time: self.start_time,
path_progress: 0.0,
});
}
SliderEventsIterState::Ticks { ref mut span } => {
if let Some(event) = self.ticks.pop() {
return Some(event);
}
if *span == self.span_count {
self.state = SliderEventsIterState::LastTick;
} else {
let curr_span = *span;
*span += 1;
generate_ticks(self, curr_span);
}
}
SliderEventsIterState::LastTick => {
let total_duration = f64::from(self.span_count) * self.span_duration;
let final_span_idx = self.span_count - 1;
let final_span_start_time =
self.start_time + f64::from(final_span_idx) * self.span_duration;
let last_tick_time = (self.start_time + total_duration / 2.0)
.max((final_span_start_time + self.span_duration) + Self::TAIL_LENIENCY);
let mut last_tick_progress =
(last_tick_time - final_span_start_time) / self.span_duration;
if self.span_count % 2 == 0 {
last_tick_progress = 1.0 - last_tick_progress;
}
self.state = SliderEventsIterState::Tail;
return Some(SliderEvent {
kind: SliderEventType::LastTick,
span_idx: final_span_idx,
span_start_time: final_span_start_time,
time: last_tick_time,
path_progress: last_tick_progress,
});
}
SliderEventsIterState::Tail => {
let total_duration = f64::from(self.span_count) * self.span_duration;
let final_span_idx = self.span_count - 1;
self.state = SliderEventsIterState::Done;
return Some(SliderEvent {
kind: SliderEventType::Tail,
span_idx: final_span_idx,
span_start_time: self.start_time
+ f64::from(self.span_count - 1) * self.span_duration,
time: self.start_time + total_duration,
path_progress: f64::from(self.span_count % 2),
});
}
SliderEventsIterState::Done => return None,
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.state {
SliderEventsIterState::Head => (3, None),
SliderEventsIterState::Ticks { .. } => (2 + self.ticks.len(), None),
SliderEventsIterState::LastTick => (2, Some(2)),
SliderEventsIterState::Tail => (1, Some(1)),
SliderEventsIterState::Done => (0, Some(0)),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum SliderEventsIterState {
Head,
Ticks { span: i32 },
LastTick,
Tail,
Done,
}
fn generate_ticks(iter: &mut SliderEventsIter<'_>, span: i32) {
let reversed = span % 2 == 1;
let span_start_time = iter.start_time + f64::from(span) * iter.span_duration;
let with_repeat = span < iter.span_count - 1;
if reversed && with_repeat {
let repeat = new_repeat_point(span, span_start_time, iter.span_duration);
iter.ticks.push(repeat);
}
let mut d = iter.tick_dist;
while d <= iter.len {
if d >= iter.len - iter.min_dist_from_end {
break;
}
let path_progress = d / iter.len;
let time_progres = if reversed {
1.0 - path_progress
} else {
path_progress
};
let tick = SliderEvent {
kind: SliderEventType::Tick,
span_idx: span,
span_start_time,
time: span_start_time + time_progres * iter.span_duration,
path_progress,
};
iter.ticks.push(tick);
d += iter.tick_dist;
}
if !reversed {
if with_repeat {
let repeat = new_repeat_point(span, span_start_time, iter.span_duration);
iter.ticks.push(repeat);
}
iter.ticks.reverse();
}
}
fn new_repeat_point(span: i32, span_start_time: f64, span_duration: f64) -> SliderEvent {
SliderEvent {
kind: SliderEventType::Repeat,
span_idx: span,
span_start_time,
time: span_start_time + span_duration,
path_progress: f64::from((span + 1) % 2),
}
}
#[cfg(test)]
mod tests {
use super::*;
const START_TIME: f64 = 0.0;
const SPAN_DURATION: f64 = 1000.0;
#[test]
fn single_span() {
let mut buf = Vec::new();
let events: Vec<_> = SliderEventsIter::new(
START_TIME,
SPAN_DURATION,
1.0,
SPAN_DURATION / 2.0,
SPAN_DURATION,
1,
&mut buf,
)
.collect();
assert_eq!(events[0].kind, SliderEventType::Head);
assert!((events[0].time - START_TIME).abs() < f64::EPSILON);
assert_eq!(events[1].kind, SliderEventType::Tick);
assert!((events[1].time - (SPAN_DURATION / 2.0)).abs() < f64::EPSILON);
assert_eq!(events[3].kind, SliderEventType::Tail);
assert!((events[3].time - SPAN_DURATION).abs() < f64::EPSILON);
}
#[test]
fn repeat() {
let mut buf = Vec::new();
let events: Vec<_> = SliderEventsIter::new(
START_TIME,
SPAN_DURATION,
1.0,
SPAN_DURATION / 2.0,
SPAN_DURATION,
2,
&mut buf,
)
.collect();
assert_eq!(events[0].kind, SliderEventType::Head);
assert!((events[0].time - START_TIME).abs() < f64::EPSILON);
assert_eq!(events[1].kind, SliderEventType::Tick);
assert!((events[1].time - (SPAN_DURATION / 2.0)).abs() < f64::EPSILON);
assert_eq!(events[2].kind, SliderEventType::Repeat);
assert!((events[2].time - SPAN_DURATION).abs() < f64::EPSILON);
assert_eq!(events[3].kind, SliderEventType::Tick);
assert!((events[3].time - (SPAN_DURATION + SPAN_DURATION / 2.0)).abs() < f64::EPSILON);
assert_eq!(events[5].kind, SliderEventType::Tail);
assert!((events[5].time - (2.0 * SPAN_DURATION)).abs() < f64::EPSILON);
}
#[test]
fn non_even_ticks() {
let mut buf = Vec::new();
let events: Vec<_> = SliderEventsIter::new(
START_TIME,
SPAN_DURATION,
1.0,
300.0,
SPAN_DURATION,
2,
&mut buf,
)
.collect();
assert_eq!(events[0].kind, SliderEventType::Head);
assert!((events[0].time - START_TIME).abs() < f64::EPSILON);
assert_eq!(events[1].kind, SliderEventType::Tick);
assert!((events[1].time - 300.0).abs() < f64::EPSILON);
assert_eq!(events[2].kind, SliderEventType::Tick);
assert!((events[2].time - 600.0).abs() < f64::EPSILON);
assert_eq!(events[3].kind, SliderEventType::Tick);
assert!((events[3].time - 900.0).abs() < f64::EPSILON);
assert_eq!(events[4].kind, SliderEventType::Repeat);
assert!((events[4].time - SPAN_DURATION).abs() < f64::EPSILON);
assert_eq!(events[5].kind, SliderEventType::Tick);
assert!((events[5].time - 1100.0).abs() < f64::EPSILON);
assert_eq!(events[6].kind, SliderEventType::Tick);
assert!((events[6].time - 1400.0).abs() < f64::EPSILON);
assert_eq!(events[7].kind, SliderEventType::Tick);
assert!((events[7].time - 1700.0).abs() < f64::EPSILON);
assert_eq!(events[9].kind, SliderEventType::Tail);
assert!((events[9].time - (2.0 * SPAN_DURATION)).abs() < f64::EPSILON);
}
#[test]
fn last_tick_offset() {
let mut buf = Vec::new();
let last_tick = SliderEventsIter::new(
START_TIME,
SPAN_DURATION,
1.0,
SPAN_DURATION / 2.0,
SPAN_DURATION,
1,
&mut buf,
)
.nth(2)
.unwrap();
assert_eq!(last_tick.kind, SliderEventType::LastTick);
assert!(
(last_tick.time - (SPAN_DURATION + SliderEventsIter::TAIL_LENIENCY)).abs()
< f64::EPSILON
);
}
#[test]
fn min_tick_dist() {
const VELOCITY: f64 = 5.0;
const MIN_DIST: f64 = VELOCITY * 10.0;
let mut buf = Vec::new();
let events = SliderEventsIter::new(
START_TIME,
SPAN_DURATION,
VELOCITY,
VELOCITY,
SPAN_DURATION,
2,
&mut buf,
);
for event in events {
if event.kind == SliderEventType::Tick {
assert!(
event.time < SPAN_DURATION - MIN_DIST || event.time > SPAN_DURATION + MIN_DIST
);
}
}
}
}