i_am_not_away/
lib.rs

1use std::{
2    f64::consts::E,
3    thread,
4    time::{Duration, Instant},
5};
6
7pub struct Animator {
8    pub config: AnimatorConfig,
9}
10pub struct AnimatorConfig {
11    pub target_fps: u32,
12    pub speed: u32,
13}
14
15impl Animator {
16    pub fn new(config: Option<AnimatorConfig>) -> Self {
17        if let Some(config) = config {
18            Self { config }
19        } else {
20            Self {
21                config: AnimatorConfig {
22                    target_fps: 1,
23                    speed: 100,
24                },
25            }
26        }
27    }
28
29    fn run<F>(&self, mut on_tick: F)
30    where
31        F: FnMut(),
32    {
33        let target_fps = self.config.target_fps;
34        let speed = self.config.speed as f64 / 100_f64;
35        let actual_target_fps: u8 = ((target_fps as f64 * speed).floor() as f64) as u8;
36        println!("{} {}", actual_target_fps, speed);
37        let target_sleep_time = Duration::from_micros(1_000_000 / actual_target_fps.max(1) as u64);
38
39        loop {
40            on_tick();
41
42            let frame_start = Instant::now();
43            let frame_time = frame_start.elapsed();
44            if frame_time < target_sleep_time {
45                thread::sleep(target_sleep_time - frame_time);
46            }
47        }
48    }
49
50    // TODO: use the power
51    pub fn oscillate<F>(&self, min: u8, max: u8, power: u8, mut on_tick: F)
52    where
53        F: FnMut(u8),
54    {
55        let mut current: f64 = min.into();
56        let mut x: f64 = 0.0;
57        let mut is_going_up = false;
58
59        Self::run(self, || {
60            let modo = Self::log(x, 1.0, 1.0, 0.5);
61
62            if !is_going_up && current > min.into() {
63                x -= 0.1;
64            } else if is_going_up && current < max.into() {
65                x += 0.1;
66            } else {
67                is_going_up = !is_going_up;
68            }
69
70            current = (max as f64 * modo).round();
71            on_tick(current as u8);
72        });
73    }
74
75    // TODO: improve the param names
76    pub fn log(x: f64, L: f64, k: f64, x0: f64) -> f64 {
77        L / (1.0 + E.powf(-1.0 * k * (x - x0)))
78    }
79
80    pub fn clean_screen() {
81        print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
82    }
83}