1mod duration;
4mod iteration;
5mod mode;
6mod normalized;
7mod utils;
8
9pub use duration::{Delay, Duration};
10pub use iced::animation::Easing;
11pub use iteration::IterationCount;
12pub use mode::{Direction, FillMode};
13pub use normalized::{NormalizedTiming, TimingPhase, TimingSampleState};
14
15#[cfg(test)]
16mod tests;
17
18use crate::{
19 nearly_equal_f64,
20 timing::utils::{completed_iterations_from, sanitize_non_negative, sanitize_playback_rate},
21};
22
23#[derive(Debug, Clone, Copy, PartialEq)]
46pub struct Timing {
47 duration: Duration,
49 delay: Delay,
51 direction: Direction,
53 fill_mode: FillMode,
55 easing: Easing,
57 iterations: IterationCount,
59 playback_rate: f64,
61}
62
63impl Timing {
64 #[must_use]
66 pub fn new(duration_ms: f64) -> Self {
67 Self {
68 duration: Duration::from_millis(duration_ms),
69 ..Self::default()
70 }
71 }
72
73 #[must_use]
75 pub const fn duration(&self) -> Duration {
76 self.duration
77 }
78
79 #[must_use]
81 pub const fn delay(&self) -> Delay {
82 self.delay
83 }
84
85 #[must_use]
87 pub const fn direction(&self) -> Direction {
88 self.direction
89 }
90
91 #[must_use]
93 pub const fn fill_mode(&self) -> FillMode {
94 self.fill_mode
95 }
96
97 #[must_use]
99 pub const fn easing(&self) -> Easing {
100 self.easing
101 }
102
103 #[must_use]
105 pub const fn iterations(&self) -> IterationCount {
106 self.iterations
107 }
108
109 #[must_use]
111 pub const fn playback_rate(&self) -> f64 {
112 self.playback_rate
113 }
114
115 #[must_use]
117 pub const fn with_delay(mut self, delay: Delay) -> Self {
118 self.delay = delay;
119 self
120 }
121
122 #[must_use]
124 pub const fn with_direction(mut self, direction: Direction) -> Self {
125 self.direction = direction;
126 self
127 }
128
129 #[must_use]
131 pub const fn with_fill_mode(mut self, fill_mode: FillMode) -> Self {
132 self.fill_mode = fill_mode;
133 self
134 }
135
136 #[must_use]
138 pub const fn with_easing(mut self, easing: Easing) -> Self {
139 self.easing = easing;
140 self
141 }
142
143 #[must_use]
145 pub fn with_iterations(mut self, iterations: impl Into<IterationCount>) -> Self {
146 self.iterations = iterations.into();
147 self
148 }
149
150 #[must_use]
152 pub fn with_playback_rate(mut self, playback_rate: f64) -> Self {
153 self.playback_rate = sanitize_playback_rate(playback_rate);
154 self
155 }
156
157 #[must_use]
159 pub fn active_duration(self) -> Option<Duration> {
160 let count = self.iterations.finite_count()?;
161
162 self.duration.checked_mul(count)
163 }
164
165 #[must_use]
167 pub fn total_duration(self) -> Option<Duration> {
168 let active = self.active_duration()?;
169
170 active.checked_add_delay(self.delay)
171 }
172
173 #[must_use]
175 pub fn normalize_elapsed(self, elapsed_ms: f64) -> NormalizedTiming {
176 let elapsed_ms = sanitize_non_negative(elapsed_ms);
177 let scaled_elapsed = elapsed_ms * self.playback_rate;
178 let delay_ms = self.delay.as_millis();
179
180 if scaled_elapsed < delay_ms {
181 return NormalizedTiming::before_start(self.fill_mode, self.direction.start_progress());
182 }
183
184 let active_elapsed = scaled_elapsed - delay_ms;
185 let duration_ms = self.duration.as_millis();
186
187 if nearly_equal_f64(duration_ms, 0.0) {
188 let count = self.iterations.finite_count().unwrap_or(1);
189
190 return NormalizedTiming::after_end(
191 count,
192 self.fill_mode,
193 self.direction.end_progress(count),
194 );
195 }
196
197 let active_progress = active_elapsed / duration_ms;
198 let completed_iterations = completed_iterations_from(active_progress);
199
200 if let Some(iteration_count) = self.iterations.finite_count()
201 && completed_iterations >= iteration_count
202 {
203 return NormalizedTiming::after_end(
204 iteration_count,
205 self.fill_mode,
206 self.direction.end_progress(iteration_count),
207 );
208 }
209
210 if !active_progress.is_finite() {
211 let directed_iteration_progress =
212 self.direction.sample_progress(completed_iterations, 0.0);
213
214 return NormalizedTiming::active(
215 completed_iterations,
216 directed_iteration_progress,
217 f64::from(completed_iterations),
218 );
219 }
220
221 let iteration_elapsed = active_elapsed % duration_ms;
222 let raw_iteration_progress = iteration_elapsed / duration_ms;
223 let directed_iteration_progress = self
224 .direction
225 .sample_progress(completed_iterations, raw_iteration_progress);
226
227 NormalizedTiming::active(
228 completed_iterations,
229 directed_iteration_progress,
230 active_progress,
231 )
232 }
233}
234
235impl Default for Timing {
236 fn default() -> Self {
237 Self {
238 duration: Duration::ZERO,
239 delay: Delay::ZERO,
240 direction: Direction::default(),
241 fill_mode: FillMode::default(),
242 easing: Easing::Linear,
243 iterations: IterationCount::default(),
244 playback_rate: 1.0,
245 }
246 }
247}