/ src / timer.rs
timer.rs
  1  use std::cmp::Ordering;
  2  use std::time::{Duration, Instant};
  3  
  4  // TODO:
  5  // - [ ] add states to get and set timer, also the instants?
  6  // - [ ] enhance error handling with error types also for set_timer
  7  // - [ ] use struct instead of tuples in get_timer and set_timer
  8  // - [ ] add trait to string for state so that get_timer gets str
  9  // - [ ] do the opossite to create a strate from str
 10  // - [ ] externalize the import and export timer to main by doing the
 11  // traits to str into the state too
 12  // - [ ] refactor get_duration to return seconds instead of duration?
 13  // - [ ] reorganize get_duration and this crate
 14  // - [ ] simplify this crate code
 15  
 16  pub fn get_duration(instant: Instant) -> Option<Duration> {
 17      Instant::now().checked_duration_since(instant)
 18  }
 19  
 20  pub fn get_elapsed_seconds(instant: Instant) -> u64 {
 21      match Instant::now().checked_duration_since(instant) {
 22          Some(s) => s.as_secs(),
 23          None => Duration::from_secs(0).as_secs(),
 24      }
 25  }
 26  
 27  // Transition To another state
 28  #[derive(Debug, Clone, Copy, PartialEq)]
 29  pub enum To {
 30      Paused,
 31      Started,
 32  }
 33  
 34  #[derive(Debug, Clone, PartialEq)]
 35  pub enum State {
 36      Idle,
 37      Started,
 38      Tranistion(To),
 39      Paused,
 40      Ended,
 41  }
 42  
 43  impl State {
 44      pub fn update_state(timer: &mut Timer) -> Result<(), &'static str> {
 45          match (timer.started_instant, timer.paused_instant) {
 46              (Some(started), Some(paused)) => match started.cmp(&paused) {
 47                  Ordering::Less => match get_duration(started) {
 48                      Some(_accumulated_timer) => {
 49                          timer.state = Self::Tranistion(To::Paused);
 50                          Ok(())
 51                      }
 52                      //None => Err("This instant is later than started"),
 53                      None => Err("This instant is later than started"),
 54                  },
 55                  Ordering::Greater => match get_duration(paused) {
 56                      Some(_accumulated_paused) => {
 57                          timer.state = Self::Tranistion(To::Started);
 58                          Ok(())
 59                      }
 60                      //None => Err("This instant is later than paused"),
 61                      None => Err("This instant is later than paused"),
 62                  },
 63                  Ordering::Equal => Err("On state transiton Instants cannot be Equal"),
 64              },
 65              (Some(_started), None) => {
 66                  timer.state = Self::Started;
 67                  Ok(())
 68              }
 69              (None, Some(_paused)) => {
 70                  timer.state = Self::Paused;
 71                  Ok(())
 72              }
 73              (None, None) => {
 74                  timer.state = Self::Idle;
 75                  Ok(())
 76              }
 77          }
 78      }
 79  }
 80  
 81  #[derive(Debug, Clone)]
 82  pub struct Timer {
 83      pub state: State,
 84      pub started_instant: Option<Instant>,
 85      pub paused_instant: Option<Instant>,
 86      pub accumulated_timer: Duration,
 87      pub accumulated_paused: Duration,
 88  }
 89  
 90  impl Timer {
 91      pub fn new() -> Self {
 92          Self::build(
 93              State::Idle,
 94              None,
 95              None,
 96              Duration::from_secs(0),
 97              Duration::from_secs(0),
 98          )
 99      }
100  
101      pub fn build(
102          state: State,
103          started_instant: Option<Instant>,
104          paused_instant: Option<Instant>,
105          accumulated_timer: Duration,
106          accumulated_paused: Duration,
107      ) -> Self {
108          Self {
109              state,
110              started_instant,
111              paused_instant,
112              accumulated_timer,
113              accumulated_paused,
114          }
115      }
116      pub fn get_timer(&self) -> (String, Duration, Duration) {
117          let state = match self.state {
118              State::Started => "started",
119              State::Paused => "paused",
120              State::Idle => "idle",
121              State::Ended => "ended",
122              State::Tranistion(t) => match &t {
123                  To::Paused => "transition_to_paused",
124                  To::Started => "transition_to_started",
125              },
126          };
127  
128          let timer_duration = match self.started_instant {
129              Some(timer_instant) => {
130                  self.accumulated_timer
131                      + get_duration(timer_instant).unwrap_or(Duration::from_secs(0))
132              }
133              None => self.accumulated_timer,
134          };
135          let paused_duration = match self.paused_instant {
136              Some(paused_instant) => {
137                  self.accumulated_paused
138                      + get_duration(paused_instant).unwrap_or(Duration::from_secs(0))
139              }
140              None => self.accumulated_paused,
141          };
142          (state.to_string(), timer_duration, paused_duration)
143      }
144  
145      pub fn set_timer(&mut self, data: (&str, Duration, Duration)) -> Result<(), &'static str> {
146          let state = match data.0 {
147              "started" => State::Started,
148              "paused" => State::Paused,
149              "idle" => State::Idle,
150              "ended" => State::Ended,
151              "transition_to_paused" => State::Tranistion(To::Paused),
152              "transition_to_started" => State::Tranistion(To::Started),
153              _ => return Err("Unknown State"),
154          };
155          self.state = state;
156          self.accumulated_timer = data.1;
157          self.accumulated_paused = data.2;
158          Ok(())
159      }
160  
161      // send as a serialized string
162      pub fn export_timer(&self) -> String {
163          let state = match self.state {
164              State::Started => "started",
165              State::Paused => "paused",
166              State::Idle => "idle",
167              State::Ended => "ended",
168              State::Tranistion(t) => match &t {
169                  To::Paused => "transition_to_paused",
170                  To::Started => "transition_to_started",
171              },
172          };
173  
174          let elapsed_timer_seconds = match self.started_instant {
175              Some(timer_instant) => {
176                  self.accumulated_timer.as_secs() + get_elapsed_seconds(timer_instant)
177              }
178              None => self.accumulated_timer.as_secs(),
179          };
180          let elapsed_paused_seconds = match self.paused_instant {
181              Some(paused_instant) => {
182                  self.accumulated_paused.as_secs() + get_elapsed_seconds(paused_instant)
183              }
184              None => self.accumulated_paused.as_secs(),
185          };
186  
187          // here the structure is state, timer and paused time
188          format!(
189              "{}•{}•{}",
190              state, elapsed_timer_seconds, elapsed_paused_seconds
191          )
192      }
193  
194      // for imports only
195      pub fn import_timer(&mut self, data: String) -> Result<(), &'static str> {
196          let data_vec: Vec<&str> = data.split('•').collect();
197  
198          if data_vec.len() == 3 {
199              self.state = State::Idle;
200              self.started_instant = None;
201              self.paused_instant = None;
202  
203              self.accumulated_timer = match data_vec.get(1) {
204                  Some(elapsed_timer_string) => match elapsed_timer_string.parse::<u64>() {
205                      Ok(elapsed_timer_seconds) => Duration::from_secs(elapsed_timer_seconds),
206                      Err(_) => return Err("Error on conversion importing accumulated_timer"),
207                  },
208                  None => Duration::from_secs(0),
209              };
210  
211              self.accumulated_paused = match data_vec.get(2) {
212                  Some(elapsed_paused_string) => match elapsed_paused_string.parse::<u64>() {
213                      Ok(elapsed_paused_seconds) => Duration::from_secs(elapsed_paused_seconds),
214                      Err(_) => return Err("Error on conversion importing accumulated_paused"),
215                  },
216                  None => Duration::from_secs(0),
217              };
218              Ok(())
219          } else {
220              Err("Error on data vector size: it must be 3")
221          }
222      }
223  
224      pub fn print_time(&self) {
225          let timer_data = self.export_timer();
226          let data_vec: Vec<&str> = timer_data.split('•').collect();
227  
228          if data_vec.len() == 3 {
229              println!();
230              println!("State: {}", data_vec[0]);
231              println!("timer time: {}ms", data_vec[1]);
232              println!("paused time: {}ms", data_vec[2]);
233          }
234      }
235  
236      pub fn start(&mut self) -> Result<(), &'static str> {
237          match self.state {
238              State::Started => Err("State: Started, should be IDLE or Paused"),
239              State::Paused => {
240                  self.started_instant = Some(Instant::now());
241                  State::update_state(self)?;
242                  Ok(())
243              }
244              State::Idle => {
245                  self.started_instant = Some(Instant::now());
246                  State::update_state(self)?;
247                  Ok(())
248              }
249              State::Ended => Err("State: Ended, Timer should be deleted"),
250              State::Tranistion(_) => Err("State: Transition, call transiton method to follow"),
251          }
252      }
253  
254      pub fn pause(&mut self) -> Result<(), &'static str> {
255          match self.state {
256              State::Started => {
257                  self.paused_instant = Some(Instant::now());
258                  State::update_state(self)?;
259                  Ok(())
260              }
261              State::Paused => Err("State: paused, Should be started"),
262              State::Idle => Err("State: IDLE, call start method"),
263              State::Ended => Err("State: Ended, Timer should be deleted"),
264              State::Tranistion(_) => Err("State: Transition, call transiton method to follow"),
265          }
266      }
267  
268      fn _transition(&mut self) -> Result<(), &'static str> {
269          match (self.started_instant, self.paused_instant) {
270              (Some(started), Some(paused)) => match started.cmp(&paused) {
271                  Ordering::Less => match get_duration(started) {
272                      Some(accumulated_timer) => {
273                          self.accumulated_timer += accumulated_timer;
274                          self.started_instant = None;
275                          State::update_state(self)?;
276                          Ok(())
277                      }
278                      None => Err("This instant is later than started"),
279                  },
280                  Ordering::Greater => match get_duration(paused) {
281                      Some(accumulated_paused) => {
282                          self.accumulated_paused += accumulated_paused;
283                          self.paused_instant = None;
284                          State::update_state(self)?;
285                          Ok(())
286                      }
287                      None => Err("This instant is later than paused"),
288                  },
289                  Ordering::Equal => Err("On state transition Instants cannot be Equal"),
290              },
291              (None, None) => Err("Cannot do a transition: State is Idle"),
292              (None, Some(_paused)) => Err("Cannot do a transition: State is Paused"),
293              (Some(_started), None) => Err("Cannot do a transiton: State is Started"),
294          }
295      }
296  
297      pub fn start_pause(&mut self) -> Result<(), &'static str> {
298          match self.state {
299              State::Idle => self.start(),
300              State::Paused => {
301                  self.start()?;
302                  self._transition()?;
303                  Ok(())
304              }
305              State::Started => {
306                  self.pause()?;
307                  self._transition()?;
308                  Ok(())
309              }
310              _ => self._transition(),
311          }
312      }
313  }
314  
315  // ToDo: Assert timer.state in tests
316  #[cfg(test)]
317  mod tests {
318      use super::*;
319      use std::thread::sleep;
320  
321      #[test]
322      fn test_idle_state() {
323          // State: Idle
324          let timer = Timer::new();
325  
326          assert_eq!(timer.paused_instant, None);
327          assert_eq!(timer.started_instant, None);
328          assert_eq!(timer.state, State::Idle);
329      }
330  
331      #[test]
332      fn simple_started_state() {
333          // State: Idle
334          let mut timer = Timer::new();
335  
336          // Start timer
337          if let Err(e) = timer.start_pause() {
338              panic!("starting error: {e}");
339          }
340  
341          // State: Working
342          assert!(timer.started_instant.is_some());
343          assert_eq!(timer.paused_instant, None);
344          assert_eq!(timer.state, State::Started);
345  
346          // move time 1
347          sleep(Duration::new(1, 0));
348  
349          // verify started instant
350          assert_eq!(
351              timer
352                  .started_instant
353                  .expect("Not Elapsed")
354                  .elapsed()
355                  .as_secs(),
356              Duration::new(1, 0).as_secs()
357          );
358      }
359  
360      #[test]
361      fn simple_paused_state() {
362          // State: Idle
363          let mut timer = Timer::new();
364  
365          // Start timer
366          if let Err(e) = timer.start_pause() {
367              panic!("starting error: {e}");
368          }
369  
370          // State: Transiton -> State: Paused
371          // accumulated_timer = Some(Paused) - Some(Working)
372          // State: Paused
373          if let Err(e) = timer.start_pause() {
374              panic!("pausing error: {e}");
375          };
376  
377          // State: Paused
378          assert_eq!(timer.started_instant, None);
379          assert!(timer.paused_instant.is_some());
380          assert_eq!(timer.state, State::Paused);
381  
382          // move time 1
383          sleep(Duration::new(1, 0));
384  
385          // verify paused instant
386          assert_eq!(
387              timer
388                  .paused_instant
389                  .expect("Not Elapsed")
390                  .elapsed()
391                  .as_secs(),
392              Duration::new(1, 0).as_secs()
393          );
394      }
395  
396      #[test]
397      #[ignore]
398      fn simple_start_stop_cycles_simulate() {
399          // State: Idle
400          let mut timer = Timer::new();
401  
402          for cycle in 1..=10 {
403              match timer.start_pause() {
404                  Ok(_) => match (timer.started_instant, timer.paused_instant) {
405                      (Some(started), None) => {
406                          assert!(timer.started_instant.is_some());
407                          assert_eq!(timer.paused_instant, None);
408                          sleep(Duration::new(1, 0));
409                          // the important assert elapsed timer time
410                          assert_eq!(started.elapsed().as_secs(), Duration::new(1, 0).as_secs());
411                          // ((cycle - 1) / 2) ecuation maps, 2,4,6,.. into 1,2,3
412                          assert_eq!(
413                              timer.accumulated_paused.as_secs(),
414                              Duration::new((cycle - 1) / 2, 0).as_secs()
415                          );
416                      }
417                      (None, Some(paused)) => {
418                          assert_eq!(timer.started_instant, None);
419                          assert!(timer.paused_instant.is_some());
420                          sleep(Duration::new(1, 0));
421                          // the important assert elapsed timer time
422                          assert_eq!(paused.elapsed().as_secs(), Duration::new(1, 0).as_secs());
423                          //assert_eq!(timer.accumulated_paused.as_secs(),
424                          //Duration::new(((cycle - 1) / 2) + 1, 0).as_secs());
425                          // ((cycle - 1) / 2) + 1 ecuation maps, 1,3,5,.. into 1,2,3
426                          assert_eq!(
427                              timer.accumulated_timer.as_secs(),
428                              Duration::new(((cycle - 1) / 2) + 1, 0).as_secs()
429                          );
430                      }
431                      (Some(_), Some(_)) | (None, None) => {
432                          panic!("transition or IDLE error");
433                      }
434                  },
435                  Err(e) => panic!("start_pause error: {e}, on {cycle}"),
436              }
437          }
438      }
439  
440      #[test]
441      fn started_state() {
442          // State: Idle
443          let mut timer = Timer::new();
444  
445          // Start timer
446          if let Err(e) = timer.start() {
447              panic!("starting error: {e}");
448          }
449  
450          // State: Started
451          assert!(timer.started_instant.is_some());
452          assert_eq!(timer.paused_instant, None);
453          assert_eq!(timer.state, State::Started);
454  
455          // move time 1
456          sleep(Duration::new(1, 0));
457  
458          // verify started instant
459          assert_eq!(
460              timer
461                  .started_instant
462                  .expect("Not Elapsed")
463                  .elapsed()
464                  .as_secs(),
465              Duration::new(1, 0).as_secs()
466          );
467      }
468  
469      #[test]
470      fn paused_state() {
471          // State: Idle
472          let mut timer = Timer::new();
473  
474          // Start timer
475          if let Err(e) = timer.start() {
476              panic!("starting error: {e}");
477          }
478  
479          match timer.pause() {
480              Ok(()) => match timer._transition() {
481                  Err(e) => {
482                      panic!("transitioning error: {e}");
483                  }
484                  Ok(()) => (),
485              },
486              Err(e) => {
487                  panic!("pausing error: {e}");
488              }
489          }
490  
491          // State: Paused
492          assert_eq!(timer.started_instant, None);
493          assert!(timer.paused_instant.is_some());
494          assert_eq!(timer.state, State::Paused);
495  
496          // move time 1
497          sleep(Duration::new(1, 0));
498  
499          // verify paused instant
500          assert_eq!(
501              timer
502                  .paused_instant
503                  .expect("Not Elapsed")
504                  .elapsed()
505                  .as_secs(),
506              Duration::new(1, 0).as_secs()
507          );
508      }
509  
510      #[test]
511      fn transiton_to_paused() {
512          // State: Idle
513          let mut timer = Timer::new();
514  
515          // Start timer
516          if let Err(e) = timer.start() {
517              panic!("starting error: {e}");
518          }
519  
520          if let Err(e) = timer.pause() {
521              panic!("pausing error: {e}");
522          }
523  
524          // State: transition started -> paused
525          assert!(timer.started_instant < timer.paused_instant);
526          assert!(timer.started_instant.is_some());
527          assert!(timer.paused_instant.is_some());
528          assert_eq!(timer.state, State::Tranistion(To::Paused));
529  
530          if let Err(e) = timer._transition() {
531              panic!("transitioning error: {e}");
532          };
533  
534          // means the transition passed sucessfully
535          // State: Paused
536          assert_eq!(timer.started_instant, None);
537          assert!(timer.paused_instant.is_some());
538          assert_eq!(timer.state, State::Paused);
539      }
540      // ToDo: to test transition is required to decompose the start_pause method
541      #[test]
542      fn transiton_to_restarted() {
543          let mut timer = Timer::new();
544  
545          // Start timer
546          if let Err(e) = timer.start() {
547              panic!("starting error: {e}");
548          }
549  
550          if let Err(e) = timer.pause() {
551              panic!("pausing error: {e}");
552          }
553  
554          if let Err(e) = timer._transition() {
555              panic!("transitioning error: {e}");
556          };
557  
558          if let Err(e) = timer.start() {
559              panic!("starting error: {e}");
560          }
561  
562          // State: transition paused -> started
563          assert!(timer.started_instant > timer.paused_instant);
564          assert!(timer.started_instant.is_some());
565          assert!(timer.paused_instant.is_some());
566          assert_eq!(timer.state, State::Tranistion(To::Started));
567  
568          if let Err(e) = timer._transition() {
569              panic!("transitioning error: {e}");
570          };
571  
572          // means the transition passed sucessfully
573          // State: Started
574          assert!(timer.started_instant.is_some());
575          assert_eq!(timer.paused_instant, None);
576          assert_eq!(timer.state, State::Started);
577      }
578  
579      #[test]
580      fn start_stop_cycles() {
581          let mut timer = Timer::new();
582  
583          // Start timer
584          if let Err(e) = timer.start() {
585              panic!("starting error: {e}");
586          }
587  
588          // State: Started
589          assert!(timer.started_instant.is_some());
590          assert_eq!(timer.paused_instant, None);
591  
592          for _ in 0..10 {
593              if let Err(e) = timer.pause() {
594                  panic!("pausing error: {e}");
595              }
596              // State: transition started -> paused
597              assert!(timer.started_instant < timer.paused_instant);
598              assert!(timer.started_instant.is_some());
599              assert!(timer.paused_instant.is_some());
600  
601              if let Err(e) = timer._transition() {
602                  panic!("transitioning error: {e}");
603              };
604  
605              // means the transition passed sucessfully
606              // State: Paused
607              assert_eq!(timer.started_instant, None);
608              assert!(timer.paused_instant.is_some());
609  
610              if let Err(e) = timer.start() {
611                  panic!("starting error: {e}");
612              }
613  
614              // State: transition paused -> started
615              assert!(timer.started_instant > timer.paused_instant);
616              assert!(timer.started_instant.is_some());
617              assert!(timer.paused_instant.is_some());
618  
619              if let Err(e) = timer._transition() {
620                  panic!("transitioning error: {e}");
621              };
622  
623              // means the transition passed sucessfully
624              // State: Started
625              assert!(timer.started_instant.is_some());
626              assert_eq!(timer.paused_instant, None);
627          }
628      }
629  
630      #[test]
631      #[ignore]
632      fn start_stop_elapsed_time_cycles() {
633          let mut timer = Timer::new();
634  
635          // Start timer
636          if let Err(e) = timer.start() {
637              panic!("starting error: {e}");
638          }
639  
640          // add 1s to started/working
641          sleep(Duration::new(1, 0));
642  
643          // verify started instant
644          assert_eq!(
645              timer
646                  .started_instant
647                  .expect("Not Elapsed")
648                  .elapsed()
649                  .as_secs(),
650              Duration::new(1, 0).as_secs()
651          );
652  
653          for cycle in 0..10 {
654              if let Err(e) = timer.pause() {
655                  panic!("pausing error: {e}");
656              }
657  
658              if let Err(e) = timer._transition() {
659                  panic!("transitioning error: {e}");
660              };
661  
662              // Once the transition to paused the started time goes into accumulated_timer
663              assert_eq!(
664                  timer.accumulated_timer.as_secs(),
665                  Duration::new(cycle + 1, 0).as_secs()
666              );
667  
668              // Add 1s to paused
669              sleep(Duration::new(1, 0));
670  
671              // verify paused instant
672              assert_eq!(
673                  timer
674                      .paused_instant
675                      .expect("Not Elapsed")
676                      .elapsed()
677                      .as_secs(),
678                  Duration::new(1, 0).as_secs()
679              );
680  
681              if let Err(e) = timer.start() {
682                  panic!("starting error: {e}");
683              }
684  
685              if let Err(e) = timer._transition() {
686                  panic!("transitioning error: {e}");
687              };
688  
689              // Once the transition to (re)started time goes into accumulated_paused
690              assert_eq!(
691                  timer.accumulated_paused.as_secs(),
692                  Duration::new(cycle + 1, 0).as_secs()
693              );
694  
695              // add 1s to started/working
696              sleep(Duration::new(1, 0));
697  
698              // verify started instant
699              assert_eq!(
700                  timer
701                      .started_instant
702                      .expect("Not Elapsed")
703                      .elapsed()
704                      .as_secs(),
705                  Duration::new(1, 0).as_secs()
706              );
707          }
708      }
709  
710      #[test]
711      #[ignore]
712      fn get_set_timer() {
713          let mut timer = Timer::new();
714          let mut timer_data = timer.get_timer();
715  
716          assert_eq!("idle", timer_data.0);
717          assert_eq!(Duration::from_secs(0), timer_data.1);
718          assert_eq!(Duration::from_secs(0), timer_data.2);
719  
720          if let Err(e) = timer.start_pause() {
721              panic!("starting error: {e}");
722          }
723  
724          // add 1s to started/working
725          sleep(Duration::new(1, 0));
726  
727          timer_data = timer.get_timer();
728  
729          assert_eq!("started", timer_data.0);
730          assert_eq!(Duration::from_secs(1).as_secs(), timer_data.1.as_secs());
731          assert_eq!(Duration::from_secs(0).as_secs(), timer_data.2.as_secs());
732  
733          if let Err(e) = timer.start_pause() {
734              panic!("starting error: {e}");
735          }
736  
737          // add 1s to paused
738          sleep(Duration::new(1, 0));
739  
740          timer_data = timer.get_timer();
741  
742          assert_eq!("paused", timer_data.0);
743          assert_eq!(Duration::from_secs(1).as_secs(), timer_data.1.as_secs());
744          assert_eq!(Duration::from_secs(1).as_secs(), timer_data.2.as_secs());
745  
746          // Now that we tested get_timer we will set_timer and reset it
747  
748          if let Err(e) = timer.import_timer("paused•2•2".to_string()) {
749              panic!("set_timer error: {e}");
750          }
751  
752          if let Err(e) = timer.set_timer(("idle", Duration::from_secs(2), Duration::from_secs(2))) {
753              panic!("set_timer error: {e}");
754          }
755  
756          timer_data = timer.get_timer();
757  
758          assert_eq!("idle", timer_data.0);
759          assert_eq!(Duration::from_secs(2).as_secs(), timer_data.1.as_secs());
760          assert_eq!(Duration::from_secs(2).as_secs(), timer_data.2.as_secs());
761  
762          assert_eq!(timer.state, State::Idle);
763      }
764  
765      #[test]
766      #[ignore]
767      fn export_import_timer() {
768          let mut timer = Timer::new();
769  
770          if let Err(e) = timer.start_pause() {
771              panic!("starting error: {e}");
772          }
773  
774          // add 1s to started/working
775          sleep(Duration::new(1, 0));
776  
777          assert_eq!("started•1•0", timer.export_timer());
778  
779          if let Err(e) = timer.start_pause() {
780              panic!("starting error: {e}");
781          }
782  
783          // add 1s to paused
784          sleep(Duration::new(1, 0));
785  
786          assert_eq!("paused•1•1", timer.export_timer());
787  
788          // Now that we played for testing with the timer we will import and reset it
789  
790          if let Err(e) = timer.import_timer("paused•2•2".to_string()) {
791              panic!("set_timer error: {e}");
792          }
793  
794          assert_eq!(timer.state, State::Idle);
795          assert_eq!("idle•2•2", timer.export_timer());
796      }
797  }