1use super::time_helper::*;
2use std::time::{Duration, Instant};
3
4pub const DEFAULT_STICKINESS_SECS_F64: f64 = 0.16;
9
10#[derive(Debug)]
16pub struct InputJump {
17 pub stickiness: Option<Duration>,
22
23 first_pop: bool,
24 last_request: Option<Instant>,
25}
26
27impl InputJump {
28 pub fn new() -> InputJump {
38 let mut ret = InputJump {
39 stickiness: None,
40 first_pop: false,
41 last_request: None,
42 };
43 ret.set_stickiness_secs_f64(Some(DEFAULT_STICKINESS_SECS_F64));
44 ret
45 }
46
47 pub fn set_stickiness_secs_f64(&mut self, stickiness_secs_f64: Option<f64>) {
58 self.stickiness = match stickiness_secs_f64 {
59 Some(m) => {
60 if m > 0.0 {
61 Some(Duration::from_secs_f64(m))
62 } else {
63 None
64 }
65 }
66 None => None,
67 };
68 }
69
70 pub fn push_jump(&mut self, now: Option<Instant>) {
86 let now = unwrap_now(now);
87 self.last_request = Some(match self.last_request {
88 Some(last_request) => {
89 if last_request < now {
90 now
91 } else {
92 last_request
93 }
94 }
95 None => now,
96 });
97 self.last_request = Some(now);
98 self.first_pop = true;
99 }
100
101 pub fn pop_jump(&mut self, now: Option<Instant>) -> bool {
125 match self.last_request {
126 Some(last_request) => {
127 let state = match self.stickiness {
128 Some(stickiness) => {
129 let now = unwrap_now(now);
130 if now >= last_request {
131 let delay: Duration = now - last_request;
132 delay <= stickiness
133 } else {
134 false
135 }
136 }
137 None => false,
138 };
139 if !state {
140 self.last_request = None
141 }
142 if self.first_pop {
143 self.first_pop = false;
144 true
145 } else {
146 state
147 }
148 }
149 None => false,
150 }
151 }
152}
153
154impl std::default::Default for InputJump {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use crate::*;
163 use std::time::{Duration, Instant};
164
165 #[test]
166 fn test_default() {
167 let input_jump = InputJump::default();
168 assert_eq!(
169 Some(Duration::from_secs_f64(DEFAULT_STICKINESS_SECS_F64)),
170 input_jump.stickiness
171 );
172 }
173
174 #[test]
175 fn test_set_stickiness_secs_f64() {
176 let mut input_jump = InputJump::new();
177 assert_eq!(
178 Some(Duration::from_secs_f64(DEFAULT_STICKINESS_SECS_F64)),
179 input_jump.stickiness
180 );
181 input_jump.set_stickiness_secs_f64(None);
182 assert_eq!(None, input_jump.stickiness);
183 input_jump.set_stickiness_secs_f64(Some(0.5));
184 assert_eq!(Some(Duration::from_secs_f64(0.5)), input_jump.stickiness);
185 }
186
187 #[test]
188 fn test_push_pop_without_stickiness() {
189 let mut input_jump = InputJump::new();
190 let now = Instant::now();
191 input_jump.set_stickiness_secs_f64(None);
192 assert!(!input_jump.pop_jump(Some(now)));
193 input_jump.push_jump(Some(now));
194 assert!(input_jump.pop_jump(Some(now)));
195 assert!(!input_jump.pop_jump(Some(now)));
196 input_jump.push_jump(Some(now));
197 input_jump.push_jump(Some(now));
198 input_jump.push_jump(Some(now));
199 assert!(input_jump.pop_jump(Some(now)));
200 assert!(!input_jump.pop_jump(Some(now)));
201 }
202
203 #[test]
204 fn test_push_pop_with_stickiness() {
205 let mut input_jump = InputJump::new();
206 let now = Instant::now();
207 let short_enough = Duration::from_secs_f64(DEFAULT_STICKINESS_SECS_F64 - 0.001);
208 let too_long = Duration::from_secs_f64(DEFAULT_STICKINESS_SECS_F64 + 0.001);
209 assert!(!input_jump.pop_jump(Some(now)));
210 input_jump.push_jump(Some(now));
211 assert!(input_jump.pop_jump(Some(now)));
212 assert!(input_jump.pop_jump(Some(now)));
213 assert!(input_jump.pop_jump(Some(now + short_enough)));
214 assert!(input_jump.pop_jump(Some(now + short_enough)));
215 assert!(!input_jump.pop_jump(Some(now + too_long)));
216 assert!(!input_jump.pop_jump(Some(now + short_enough)));
217 assert!(!input_jump.pop_jump(Some(now)));
218 }
219
220 #[test]
221 fn test_push_pop_rearm() {
222 let mut input_jump = InputJump::new();
223 let now = Instant::now();
224 let extra_delay = Duration::from_secs_f64(DEFAULT_STICKINESS_SECS_F64 * 3.0);
225 assert!(!input_jump.pop_jump(Some(now)));
226 input_jump.push_jump(Some(now));
227 input_jump.push_jump(Some(now + extra_delay));
228 input_jump.push_jump(Some(now));
229 assert!(input_jump.pop_jump(Some(now + extra_delay)));
230 }
231}