vncrs 0.1.2

A pure Rust VNC server library for Windows
Documentation
use std::collections::VecDeque;
use std::time::{Duration, Instant};

pub struct FpsCounter {
    times: VecDeque<Instant>,
    sizes: VecDeque<usize>,
    dirty: VecDeque<usize>,
    total: u64,
    start: Instant,
    last_print: Instant,
}

impl FpsCounter {
    pub fn new() -> Self {
        let now = Instant::now();
        Self {
            times: VecDeque::with_capacity(300),
            sizes: VecDeque::with_capacity(300),
            dirty: VecDeque::with_capacity(300),
            total: 0,
            start: now,
            last_print: now,
        }
    }

    pub fn frame(&mut self, bytes: usize, dirty_count: usize) {
        let now = Instant::now();
        self.times.push_back(now);
        self.sizes.push_back(bytes);
        self.dirty.push_back(dirty_count);
        self.total += 1;

        let window = Duration::from_secs(2);
        while self
            .times
            .front()
            .is_some_and(|t| now.duration_since(*t) > window)
        {
            self.times.pop_front();
            self.sizes.pop_front();
            self.dirty.pop_front();
        }

        if now.duration_since(self.last_print) >= Duration::from_secs(1) {
            self.print_stats();
            self.last_print = now;
        }
    }

    pub fn fps(&self) -> f64 {
        if self.times.len() < 2 {
            return 0.0;
        }
        let elapsed = self
            .times
            .back()
            .unwrap()
            .duration_since(*self.times.front().unwrap())
            .as_secs_f64();
        if elapsed > 0.0 {
            (self.times.len() - 1) as f64 / elapsed
        } else {
            0.0
        }
    }

    pub fn print_stats(&self) {
        let fps = self.fps();
        let avg_size = if self.sizes.is_empty() {
            0
        } else {
            self.sizes.iter().sum::<usize>() / self.sizes.len()
        };
        let avg_dirty = if self.dirty.is_empty() {
            0.0
        } else {
            self.dirty.iter().sum::<usize>() as f64 / self.dirty.len() as f64
        };
        let mbps = if self.times.len() < 2 {
            0.0
        } else {
            let elapsed = self
                .times
                .back()
                .unwrap()
                .duration_since(*self.times.front().unwrap())
                .as_secs_f64();
            if elapsed > 0.0 {
                self.sizes.iter().sum::<usize>() as f64 * 8.0 / elapsed / 1_000_000.0
            } else {
                0.0
            }
        };

        let icon = if fps >= 25.0 {
            ""
        } else if fps >= 15.0 {
            ""
        } else {
            ""
        };
        let size = if avg_size >= 1_048_576 {
            format!("{:.1}MB", avg_size as f64 / 1_048_576.0)
        } else if avg_size >= 1024 {
            format!("{:.0}KB", avg_size as f64 / 1024.0)
        } else {
            format!("{}B", avg_size)
        };

        println!(
            "{} {:5.1}fps {:>7} {:5.1}Mbps d:{:.0} #{} {}s",
            icon,
            fps,
            size,
            mbps,
            avg_dirty,
            self.total,
            self.start.elapsed().as_secs()
        );
    }
}