i_slint_core/items/flickable/
data_ringbuffer.rs1use crate::Coord;
8use crate::animations::Instant;
9use crate::lengths::{LogicalPx, LogicalVector};
10use core::time::Duration;
11use euclid::Vector2D;
12
13#[derive(Debug)]
15pub(crate) struct VelocityRingBuffer<const N: usize> {
16 curr_index: usize,
18 full: bool,
20 values: [(Instant, Vector2D<Coord, LogicalPx>); N],
21}
22
23impl<const N: usize> Default for VelocityRingBuffer<N> {
24 fn default() -> Self {
25 Self { curr_index: 0, full: false, values: [(Instant::default(), Vector2D::default()); N] }
27 }
28}
29
30impl<const N: usize> VelocityRingBuffer<N> {
31 pub fn empty(&self) -> bool {
33 !(self.full || self.curr_index > 0)
34 }
35
36 pub fn push(&mut self, time: Instant, value: LogicalVector) {
38 if self.curr_index < self.values.len() {
39 self.values[self.curr_index] = (time, value);
40 }
41 self.curr_index += 1;
42 if self.curr_index >= N {
43 self.full = true;
44 self.curr_index = 0;
45 }
46 }
47
48 fn latest_index(&self) -> usize {
50 if self.curr_index > 0 { self.curr_index - 1 } else { N - 1 }
51 }
52
53 fn len(&self) -> usize {
54 if self.full { N } else { self.curr_index }
55 }
56
57 pub fn last_time(&self) -> Option<Instant> {
59 if !self.empty() { Some(self.values[self.latest_index()].0) } else { None }
60 }
61
62 pub fn mean_velocity(&self) -> LogicalVector {
63 let len = self.len();
64 if len < 2 {
65 return Default::default();
66 }
67
68 let oldest_index = if self.full { self.curr_index } else { 0 };
69 let newest_index = self.latest_index();
70 let duration = self.values[newest_index].0.duration_since(self.values[oldest_index].0);
71 if duration == Duration::ZERO {
72 return Default::default();
73 }
74
75 let mut total_delta = LogicalVector::default();
78 let mut index = (oldest_index + 1) % N;
79 for _ in 1..len {
80 total_delta += self.values[index].1;
81 index = (index + 1) % N;
82 }
83
84 (total_delta.cast::<f32>() / duration.as_secs_f32()).cast::<Coord>()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::animations::Instant;
92 use core::time::Duration;
93
94 #[test]
95 fn test_empty_buffer() {
96 let buffer: VelocityRingBuffer<5> = VelocityRingBuffer::default();
97 assert!(buffer.empty());
98 assert_eq!(buffer.curr_index, 0);
99 assert!(!buffer.full);
100 assert_eq!(buffer.last_time(), None);
101 assert_eq!(buffer.mean_velocity(), Vector2D::default());
102 }
103
104 #[test]
105 fn test_push_single_element() {
106 let mut buffer: VelocityRingBuffer<5> = VelocityRingBuffer::default();
107 let time = Instant::default();
108 let delta = Vector2D::new(10.0, 20.0);
109
110 buffer.push(time, delta);
111
112 assert!(!buffer.empty());
113 assert_eq!(buffer.curr_index, 1);
114 assert!(!buffer.full);
115 assert_eq!(buffer.latest_index(), 0);
116 assert_eq!(buffer.last_time(), Some(time));
117 assert_eq!(buffer.mean_velocity(), Vector2D::default());
118 }
119
120 #[test]
122 fn test_push_two_elements() {
123 let mut buffer: VelocityRingBuffer<5> = VelocityRingBuffer::default();
124 let time = Instant::default();
125
126 buffer.push(time, Vector2D::new(10.0, 20.0));
127 buffer.push(time + Duration::from_millis(100), Vector2D::new(13.0, -5.0));
128
129 assert!(!buffer.empty());
130 assert_eq!(buffer.curr_index, 2);
131 assert!(!buffer.full);
132 assert_eq!(buffer.latest_index(), 1);
133 assert_eq!(buffer.last_time(), Some(time + Duration::from_millis(100)));
134
135 assert_eq!(buffer.mean_velocity(), Vector2D::new(130.0, -50.0));
136 }
137
138 #[test]
139 fn test_push_until_full() {
140 let mut buffer: VelocityRingBuffer<5> = VelocityRingBuffer::default();
141 let base_time = Instant::default();
142
143 for i in 0..5 {
145 let time = base_time + Duration::from_millis(i * 100);
146 buffer.push(time, Vector2D::new(1.0, -2.0));
147 }
148
149 assert!(!buffer.empty());
150 assert_eq!(buffer.curr_index, 0);
151 assert!(buffer.full);
152 assert_eq!(buffer.last_time(), Some(base_time + Duration::from_millis(400)));
153 assert_eq!(buffer.latest_index(), 4);
154
155 assert_eq!(buffer.mean_velocity(), Vector2D::new(10.0, -20.0));
156 }
157
158 #[test]
159 fn test_push_beyond_capacity() {
160 const CAP: usize = 5;
161 let mut buffer: VelocityRingBuffer<CAP> = VelocityRingBuffer::default();
162 let base_time = Instant::default();
163
164 for i in 0..(CAP + 2) {
166 let time = base_time + Duration::from_millis(i as u64 * 100);
167 buffer.push(time, Vector2D::new(1.0, 2.0));
168 }
169
170 assert!(!buffer.empty());
171 assert!(buffer.full);
172 assert_eq!(buffer.curr_index, 2);
173 assert_eq!(buffer.latest_index(), 1);
174 assert_eq!(buffer.last_time(), Some(base_time + Duration::from_millis(600)));
175
176 assert_eq!(buffer.mean_velocity(), Vector2D::new(10.0, 20.0));
177 }
178
179 #[test]
180 fn test_push_beyond_capacity_wrap_back() {
181 const CAP: usize = 5;
182 let mut buffer: VelocityRingBuffer<CAP> = VelocityRingBuffer::default();
183 let base_time = Instant::default();
184
185 for i in 0..CAP {
187 let time = base_time + Duration::from_millis(i as u64 * 100);
188 buffer.push(time, Vector2D::new(3.0, -2.0));
189 }
190
191 assert!(!buffer.empty());
192 assert!(buffer.full);
193 assert_eq!(buffer.curr_index, 0);
194 assert_eq!(buffer.latest_index(), CAP - 1);
195 assert_eq!(buffer.last_time(), Some(base_time + Duration::from_millis(400)));
196
197 assert_eq!(buffer.mean_velocity(), Vector2D::new(30.0, -20.0));
198 }
199}