Engine structure
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use osui::prelude::*;
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let engine = Benchmark::new(Console::new());
|
||||||
|
engine.run(app);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn app(cx: &Arc<Context>) -> View {
|
||||||
|
rsx! {
|
||||||
|
"Hello, world!"
|
||||||
|
}
|
||||||
|
.view(cx.clone())
|
||||||
|
}
|
||||||
+3
-56
@@ -1,68 +1,15 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use osui::{prelude::*, rsx};
|
use osui::prelude::*;
|
||||||
|
|
||||||
pub struct Count(pub State<u16>);
|
pub fn main() {
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let console = Console::new();
|
let console = Console::new();
|
||||||
console.run(app);
|
console.run(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app(cx: &Arc<Context>) -> View {
|
fn app(cx: &Arc<Context>) -> View {
|
||||||
let count = use_state(0);
|
|
||||||
let mount = use_mount_manual();
|
|
||||||
|
|
||||||
// Sync state with children
|
|
||||||
use_sync_effect(cx, &count, |v| Count(v.clone()), &[&mount, &count]);
|
|
||||||
|
|
||||||
use_effect(
|
|
||||||
{
|
|
||||||
let count = count.clone();
|
|
||||||
move || loop {
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
|
||||||
let mut count = count.get();
|
|
||||||
if *count > 5 {
|
|
||||||
*count = 0;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*count += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
&[&mount],
|
|
||||||
);
|
|
||||||
|
|
||||||
rsx! {
|
rsx! {
|
||||||
// Static scope
|
"Hello, world!"
|
||||||
my_component (ctx, view) {
|
|
||||||
let area = ctx.allocate(5, 0, 10, 10);
|
|
||||||
ctx.draw_view(area, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamic scope
|
|
||||||
if %count (*count.get() > 5) {
|
|
||||||
my_component (ctx, view) {
|
|
||||||
let area = ctx.allocate(18, 0, 10, 10);
|
|
||||||
ctx.draw_view(area, view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamic scope
|
|
||||||
for %count (i in 0..count.get_dl()) {
|
|
||||||
"{i}" @Point { x: 0, y: i };
|
|
||||||
}
|
|
||||||
|
|
||||||
!mount mount
|
|
||||||
}
|
|
||||||
.view(cx.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn my_component(cx: &Arc<Context>) -> View {
|
|
||||||
// Sync state with parent
|
|
||||||
let count = use_sync_state(cx, 0, |Count(v)| v.get_dl());
|
|
||||||
|
|
||||||
rsx! {
|
|
||||||
"Count: {count}"
|
|
||||||
}
|
}
|
||||||
.view(cx.clone())
|
.view(cx.clone())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
use std::{io::stdout, sync::Arc, time::Instant};
|
||||||
|
|
||||||
|
use crossterm::{cursor::MoveTo, execute, terminal::Clear};
|
||||||
|
|
||||||
|
use crate::{prelude::Context, render::Area, DrawContext, View};
|
||||||
|
|
||||||
|
use super::Engine;
|
||||||
|
|
||||||
|
pub struct Benchmark<T: Engine>(T);
|
||||||
|
|
||||||
|
impl<T: Engine> Benchmark<T> {
|
||||||
|
pub fn new(engine: T) -> Self {
|
||||||
|
Self(engine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Engine> Engine for Benchmark<T> {
|
||||||
|
fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(&self, component: F) {
|
||||||
|
let mut times: Vec<usize> = Vec::new();
|
||||||
|
let cx = self.init(component);
|
||||||
|
|
||||||
|
let start = Instant::now();
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
let start = Instant::now();
|
||||||
|
self.render(&cx);
|
||||||
|
let end = Instant::now();
|
||||||
|
times.push(end.duration_since(start).as_millis() as usize);
|
||||||
|
self.0.render_delay();
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = Instant::now();
|
||||||
|
|
||||||
|
execute!(stdout(), Clear(crossterm::terminal::ClearType::Purge)).unwrap();
|
||||||
|
execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap();
|
||||||
|
execute!(stdout(), MoveTo(0, 0)).unwrap();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Average time: {}ms",
|
||||||
|
if times.len() > 0 {
|
||||||
|
times.iter().sum::<usize>() / times.len()
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
println!("Min time: {}ms", times.iter().min().unwrap_or(&0));
|
||||||
|
println!("Max time: {}ms", times.iter().max().unwrap_or(&0));
|
||||||
|
println!(
|
||||||
|
"Median time: {}ms",
|
||||||
|
times.iter().nth(times.len() / 2).unwrap_or(&0)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"90th percentile: {}ms",
|
||||||
|
times.iter().nth(times.len() * 90 / 100).unwrap_or(&0)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"95th percentile: {}ms",
|
||||||
|
times.iter().nth(times.len() * 95 / 100).unwrap_or(&0)
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"99th percentile: {}ms",
|
||||||
|
times.iter().nth(times.len() * 99 / 100).unwrap_or(&0)
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("Total time: {}ms", end.duration_since(start).as_millis());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
|
||||||
|
&self,
|
||||||
|
component: F,
|
||||||
|
) -> Arc<Context> {
|
||||||
|
self.0.init(component)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw_context(&self, ctx: &DrawContext) {
|
||||||
|
self.0.draw_context(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render(&self, cx: &Arc<Context>) {
|
||||||
|
self.0.render(cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_view(&self, area: &Area, view: &View) -> DrawContext {
|
||||||
|
self.0.render_view(area, view)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_delay(&self) {
|
||||||
|
self.0.render_delay();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,10 +7,7 @@ use crossterm::{cursor::MoveTo, execute, terminal::Clear};
|
|||||||
|
|
||||||
use crate::{prelude::Context, render::Area, DrawContext, View};
|
use crate::{prelude::Context, render::Area, DrawContext, View};
|
||||||
|
|
||||||
pub trait Engine {
|
use super::Engine;
|
||||||
fn render_view(&self, area: &Area, view: &View) -> DrawContext;
|
|
||||||
fn draw_context(&self, ctx: &DrawContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Console {
|
pub struct Console {
|
||||||
threads: Mutex<Vec<Arc<dyn Fn(Arc<Context>) + Send + Sync>>>,
|
threads: Mutex<Vec<Arc<dyn Fn(Arc<Context>) + Send + Sync>>>,
|
||||||
@@ -26,39 +23,6 @@ impl Console {
|
|||||||
pub fn thread<F: Fn(Arc<Context>) + Send + Sync + 'static>(&self, run: F) {
|
pub fn thread<F: Fn(Arc<Context>) + Send + Sync + 'static>(&self, run: F) {
|
||||||
self.threads.lock().unwrap().push(Arc::new(run));
|
self.threads.lock().unwrap().push(Arc::new(run));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(&self, component: F) {
|
|
||||||
let cx = Context::new(component);
|
|
||||||
cx.refresh();
|
|
||||||
|
|
||||||
for thread in self.threads.lock().unwrap().iter() {
|
|
||||||
let thread = thread.clone();
|
|
||||||
|
|
||||||
std::thread::spawn({
|
|
||||||
let cx = cx.clone();
|
|
||||||
move || thread(cx)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let (width, height) = crossterm::terminal::size().unwrap();
|
|
||||||
|
|
||||||
execute!(stdout(), Clear(crossterm::terminal::ClearType::Purge)).unwrap();
|
|
||||||
execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap();
|
|
||||||
|
|
||||||
self.draw_context(&self.render_view(
|
|
||||||
&Area {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
},
|
|
||||||
&cx.get_view(),
|
|
||||||
));
|
|
||||||
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(16));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine for Console {
|
impl Engine for Console {
|
||||||
@@ -84,4 +48,40 @@ impl Engine for Console {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render(&self, cx: &Arc<Context>) {
|
||||||
|
let (width, height) = crossterm::terminal::size().unwrap();
|
||||||
|
|
||||||
|
execute!(stdout(), Clear(crossterm::terminal::ClearType::Purge)).unwrap();
|
||||||
|
execute!(stdout(), Clear(crossterm::terminal::ClearType::All)).unwrap();
|
||||||
|
|
||||||
|
self.draw_context(&self.render_view(
|
||||||
|
&Area {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
},
|
||||||
|
&cx.get_view(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
|
||||||
|
&self,
|
||||||
|
component: F,
|
||||||
|
) -> Arc<Context> {
|
||||||
|
let cx = Context::new(component);
|
||||||
|
cx.refresh();
|
||||||
|
|
||||||
|
for thread in self.threads.lock().unwrap().iter() {
|
||||||
|
let thread = thread.clone();
|
||||||
|
|
||||||
|
std::thread::spawn({
|
||||||
|
let cx = cx.clone();
|
||||||
|
move || thread(cx)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
pub mod benchmark;
|
||||||
|
pub mod console;
|
||||||
|
|
||||||
|
pub use benchmark::*;
|
||||||
|
pub use console::*;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{prelude::Context, render::Area, DrawContext, View};
|
||||||
|
|
||||||
|
pub trait Engine {
|
||||||
|
fn run<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(&self, component: F) {
|
||||||
|
let cx = self.init(component);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
self.render(&cx);
|
||||||
|
self.render_delay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init<F: Fn(&Arc<Context>) -> View + Send + Sync + 'static>(
|
||||||
|
&self,
|
||||||
|
component: F,
|
||||||
|
) -> Arc<Context>;
|
||||||
|
fn render(&self, cx: &Arc<Context>);
|
||||||
|
fn render_delay(&self) {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(16))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn render_view(&self, area: &Area, view: &View) -> DrawContext;
|
||||||
|
fn draw_context(&self, ctx: &DrawContext);
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ pub mod prelude {
|
|||||||
pub use crate::component::*;
|
pub use crate::component::*;
|
||||||
pub use crate::engine::*;
|
pub use crate::engine::*;
|
||||||
pub use crate::render::*;
|
pub use crate::render::*;
|
||||||
|
pub use crate::rsx;
|
||||||
pub use crate::state::*;
|
pub use crate::state::*;
|
||||||
pub use crate::View;
|
pub use crate::View;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user