motiongfx/
sequence.rs

1use nonempty::NonEmpty;
2
3use crate::action::ActionClip;
4
5/// A non-overlapping sequence of [`ActionClip`]s.
6#[derive(Debug, Clone)]
7pub struct Sequence {
8    pub clips: NonEmpty<ActionClip>,
9}
10
11impl Sequence {
12    pub const fn new(span: ActionClip) -> Self {
13        Self {
14            clips: NonEmpty::new(span),
15        }
16    }
17
18    #[allow(clippy::len_without_is_empty)] // It is non empty!
19    #[inline]
20    pub fn len(&self) -> usize {
21        self.clips.len()
22    }
23
24    /// Get the start time of the sequence.
25    #[inline]
26    pub fn start(&self) -> f32 {
27        self.clips.first().start
28    }
29
30    /// Get the end time of the sequence.
31    #[inline]
32    pub fn end(&self) -> f32 {
33        self.clips.last().end()
34    }
35
36    /// Get the duration of the sequence.
37    #[inline]
38    pub fn duration(&self) -> f32 {
39        self.end() - self.start()
40    }
41
42    pub(crate) fn delay(&mut self, duration: f32) {
43        for clip in self.clips.iter_mut() {
44            clip.start += duration;
45        }
46    }
47}
48
49impl Sequence {
50    #[inline]
51    pub fn push(&mut self, span: ActionClip) {
52        debug_assert!(
53            span.start >= self.end(),
54            "({} >= {}) `ActionClip`s shouldn't overlap!",
55            span.start,
56            self.end(),
57        );
58
59        self.clips.push(span);
60    }
61}
62
63impl Extend<ActionClip> for Sequence {
64    #[inline]
65    fn extend<T: IntoIterator<Item = ActionClip>>(
66        &mut self,
67        iter: T,
68    ) {
69        #[cfg(debug_assertions)]
70        let mut end = self.end();
71        #[cfg(debug_assertions)]
72        let iter = {
73            iter.into_iter().inspect(|clip| {
74                debug_assert!(
75                    clip.start >= end,
76                    "({} >= {}) `ActionClip`s shouldn't overlap!",
77                    clip.start,
78                    end,
79                );
80
81                end = clip.end();
82            })
83        };
84
85        self.clips.extend(iter);
86    }
87}
88
89impl IntoIterator for Sequence {
90    type Item = ActionClip;
91
92    type IntoIter = <NonEmpty<ActionClip> as IntoIterator>::IntoIter;
93
94    fn into_iter(self) -> Self::IntoIter {
95        self.clips.into_iter()
96    }
97}