oxihuman_export/
anim_event_export.rs1#![allow(dead_code)]
4
5#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct AnimEvent {
11 pub name: String,
12 pub time: f32,
13 pub payload: String,
14}
15
16#[allow(dead_code)]
18#[derive(Debug, Clone, Default)]
19pub struct AnimEventTrack {
20 pub events: Vec<AnimEvent>,
21}
22
23#[allow(dead_code)]
25pub fn new_event_track() -> AnimEventTrack {
26 AnimEventTrack::default()
27}
28
29#[allow(dead_code)]
31pub fn add_event(track: &mut AnimEventTrack, name: &str, time: f32, payload: &str) {
32 track.events.push(AnimEvent {
33 name: name.to_string(),
34 time,
35 payload: payload.to_string(),
36 });
37}
38
39#[allow(dead_code)]
41pub fn sort_events(track: &mut AnimEventTrack) {
42 track.events.sort_by(|a, b| {
43 a.time
44 .partial_cmp(&b.time)
45 .unwrap_or(std::cmp::Ordering::Equal)
46 });
47}
48
49#[allow(dead_code)]
51pub fn event_count(track: &AnimEventTrack) -> usize {
52 track.events.len()
53}
54
55#[allow(dead_code)]
57pub fn events_from(track: &AnimEventTrack, time: f32) -> Vec<&AnimEvent> {
58 track.events.iter().filter(|e| e.time >= time).collect()
59}
60
61#[allow(dead_code)]
63pub fn track_duration(track: &AnimEventTrack) -> f32 {
64 if track.events.len() < 2 {
65 return 0.0;
66 }
67 let first = track.events.iter().map(|e| e.time).fold(f32::MAX, f32::min);
68 let last = track.events.iter().map(|e| e.time).fold(f32::MIN, f32::max);
69 last - first
70}
71
72#[allow(dead_code)]
74pub fn serialize_events(track: &AnimEventTrack) -> String {
75 track
76 .events
77 .iter()
78 .map(|e| format!("{},{},{}", e.name, e.time, e.payload))
79 .collect::<Vec<_>>()
80 .join("\n")
81}
82
83#[allow(dead_code)]
85pub fn has_event_named(track: &AnimEventTrack, name: &str) -> bool {
86 track.events.iter().any(|e| e.name == name)
87}
88
89#[allow(dead_code)]
91pub fn trim_before(track: &mut AnimEventTrack, cutoff: f32) {
92 track.events.retain(|e| e.time >= cutoff);
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_add_event() {
101 let mut t = new_event_track();
102 add_event(&mut t, "step", 1.0, "left");
103 assert_eq!(event_count(&t), 1);
104 }
105
106 #[test]
107 fn test_sort_events() {
108 let mut t = new_event_track();
109 add_event(&mut t, "b", 2.0, "");
110 add_event(&mut t, "a", 0.5, "");
111 sort_events(&mut t);
112 assert!((t.events[0].time - 0.5).abs() < 1e-6);
113 }
114
115 #[test]
116 fn test_events_from() {
117 let mut t = new_event_track();
118 add_event(&mut t, "x", 0.0, "");
119 add_event(&mut t, "y", 1.5, "");
120 let r = events_from(&t, 1.0);
121 assert_eq!(r.len(), 1);
122 }
123
124 #[test]
125 fn test_track_duration_empty() {
126 let t = new_event_track();
127 assert_eq!(track_duration(&t), 0.0);
128 }
129
130 #[test]
131 fn test_track_duration() {
132 let mut t = new_event_track();
133 add_event(&mut t, "a", 1.0, "");
134 add_event(&mut t, "b", 3.0, "");
135 assert!((track_duration(&t) - 2.0).abs() < 1e-6);
136 }
137
138 #[test]
139 fn test_serialize_events() {
140 let mut t = new_event_track();
141 add_event(&mut t, "step", 1.0, "L");
142 let s = serialize_events(&t);
143 assert!(s.contains("step"));
144 }
145
146 #[test]
147 fn test_has_event_named() {
148 let mut t = new_event_track();
149 add_event(&mut t, "jump", 0.5, "");
150 assert!(has_event_named(&t, "jump"));
151 assert!(!has_event_named(&t, "fall"));
152 }
153
154 #[test]
155 fn test_trim_before() {
156 let mut t = new_event_track();
157 add_event(&mut t, "a", 0.2, "");
158 add_event(&mut t, "b", 1.5, "");
159 trim_before(&mut t, 1.0);
160 assert_eq!(event_count(&t), 1);
161 }
162
163 #[test]
164 fn test_empty_serialize() {
165 let t = new_event_track();
166 assert!(serialize_events(&t).is_empty());
167 }
168
169 #[test]
170 fn test_event_fields() {
171 let e = AnimEvent {
172 name: "n".to_string(),
173 time: 3.0,
174 payload: "p".to_string(),
175 };
176 assert!((e.time - 3.0).abs() < 1e-6);
177 }
178}