linfeng 7c28051e8c
chore: update toolchain version to 2024-11-05 (#1031)
* chore: update toolchain version to 2024-11-05

* update dragon reach to e945c217b3

* update dog to 6f2c0c8f12

---------

Co-authored-by: longjin <longjin@DragonOS.org>
2024-11-11 21:29:15 +08:00

213 lines
4.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use std::error;
use rand::{distributions::Uniform, prelude::Distribution, rngs::ThreadRng};
use ratatui::widgets::ListState;
/// Application result type.
pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;
/// Application.
#[derive(Debug)]
pub struct App<'a> {
/// APP的标题
pub title: &'a str,
/// Is the application running?
pub running: bool,
pub enhanced_graphics: bool,
/// counter
pub counter: u8,
pub tabs: TabsState<'a>,
pub memory_log_sparkline: Signal<RandomSignal>,
logs: Vec<String>,
pub stateful_logs: StatefulList<(&'a str, &'a str)>,
backend_log_receiver: Option<std::sync::mpsc::Receiver<String>>,
}
impl<'a> App<'a> {
/// Constructs a new instance of [`App`].
pub fn new(title: &'a str) -> Self {
let mut rand_signal = RandomSignal::new(0, 100);
let sparkline_points = rand_signal.by_ref().take(300).collect();
let sparkline = Signal {
source: rand_signal,
points: sparkline_points,
tick_rate: 1,
};
Self {
title,
running: true,
enhanced_graphics: true,
counter: 0,
tabs: TabsState::new(vec!["Tab0", "Tab1", "Tab2"]),
memory_log_sparkline: sparkline,
logs: Vec::new(),
stateful_logs: StatefulList::with_items(vec![]),
backend_log_receiver: None,
}
}
pub fn set_backend_log_receiver(&mut self, receiver: std::sync::mpsc::Receiver<String>) {
self.backend_log_receiver = Some(receiver);
}
/// Handles the tick event of the terminal.
pub fn tick(&mut self) {
self.memory_log_sparkline.on_tick();
self.handle_logs_on_tick();
}
/// 当到达tick时处理日志
fn handle_logs_on_tick(&mut self) {
let logs_to_push = self
.backend_log_receiver
.as_ref()
.map(|rv| rv.try_iter().collect::<Vec<String>>());
if let Some(logs) = logs_to_push {
for log in logs {
self.push_log(log);
}
}
}
/// Set running to false to quit the application.
pub fn quit(&mut self) {
self.running = false;
}
pub fn increment_counter(&mut self) {
if let Some(res) = self.counter.checked_add(1) {
self.counter = res;
}
}
pub fn decrement_counter(&mut self) {
if let Some(res) = self.counter.checked_sub(1) {
self.counter = res;
}
}
pub fn push_log(&mut self, log: String) {
self.logs.push(log);
}
pub fn logs(&self) -> &Vec<String> {
&self.logs
}
}
#[derive(Debug)]
pub struct TabsState<'a> {
pub titles: Vec<&'a str>,
pub index: usize,
}
impl<'a> TabsState<'a> {
pub fn new(titles: Vec<&'a str>) -> TabsState<'a> {
TabsState { titles, index: 0 }
}
pub fn next(&mut self) {
self.index = (self.index + 1) % self.titles.len();
}
pub fn previous(&mut self) {
if self.index > 0 {
self.index -= 1;
} else {
self.index = self.titles.len() - 1;
}
}
}
#[derive(Clone, Debug)]
pub struct Signal<S: Iterator> {
source: S,
pub points: Vec<S::Item>,
tick_rate: usize,
}
impl<S> Signal<S>
where
S: Iterator,
{
fn on_tick(&mut self) {
for _ in 0..self.tick_rate {
self.points.remove(0);
}
self.points
.extend(self.source.by_ref().take(self.tick_rate));
}
}
#[derive(Clone, Debug)]
pub struct RandomSignal {
distribution: Uniform<u64>,
rng: ThreadRng,
}
impl RandomSignal {
pub fn new(lower: u64, upper: u64) -> RandomSignal {
RandomSignal {
distribution: Uniform::new(lower, upper),
rng: rand::thread_rng(),
}
}
}
impl Iterator for RandomSignal {
type Item = u64;
fn next(&mut self) -> Option<u64> {
Some(self.distribution.sample(&mut self.rng))
}
}
#[derive(Debug)]
pub struct StatefulList<T> {
pub state: ListState,
pub items: Vec<T>,
}
impl<T> StatefulList<T> {
pub fn with_items(items: Vec<T>) -> StatefulList<T> {
StatefulList {
state: ListState::default(),
items,
}
}
pub fn next(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i >= self.items.len() - 1 {
0
} else {
i + 1
}
}
None => 0,
};
self.state.select(Some(i));
}
pub fn previous(&mut self) {
let i = match self.state.selected() {
Some(i) => {
if i == 0 {
self.items.len() - 1
} else {
i - 1
}
}
None => 0,
};
self.state.select(Some(i));
}
}