1use nonempty::NonEmpty;
2
3use crate::action::ActionClip;
4
5#[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)] #[inline]
20 pub fn len(&self) -> usize {
21 self.clips.len()
22 }
23
24 #[inline]
26 pub fn start(&self) -> f32 {
27 self.clips.first().start
28 }
29
30 #[inline]
32 pub fn end(&self) -> f32 {
33 self.clips.last().end()
34 }
35
36 #[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}