diff --git a/README.md b/README.md index 4b28b99..e20e2dc 100644 --- a/README.md +++ b/README.md @@ -17,21 +17,23 @@

- OSUI is a customizable terminal user interface (TUI) library written in Rust. It provides a set of components and rsx to build interactive command-line interfaces with ease. + OSUI is a customizable terminal user interface (TUI) library written in Rust.

```rust use osui::prelude::*; -fn main() -> std::io::Result<()> { - let screen = Screen::new(); +pub fn main() { + let engine = Console::new(); + engine.run(App {}).expect("Failed to run engine"); +} +#[component] +fn App(cx: &Arc) -> View { rsx! { - "Hello, World" + "Hello World" } - .draw(&screen); - - screen.run() + .view(&cx) } ``` diff --git a/benchmark.csv b/benchmark.csv index 65d5940..50f08bb 100644 --- a/benchmark.csv +++ b/benchmark.csv @@ -1,227 +1,227 @@ Iterx72,Nestingx72,Time µs -14,14,14236 -11,8,10608 -8,13,7793 -13,7,12073 -11,6,10495 -5,2,5135 -6,12,6144 -6,3,6341 -12,7,11304 -11,5,10622 -0,9,497 -3,2,3303 -5,1,5186 -10,8,9781 -1,11,1358 -2,9,2341 -10,11,9788 -14,5,13036 -9,1,8807 -4,12,4249 -8,1,8306 -14,4,12985 -5,0,419 -4,13,4234 -10,1,9793 -3,13,3255 -0,4,625 -7,6,7066 -8,12,7954 -10,12,9876 -8,11,8015 -6,8,6104 -0,11,514 -2,10,2373 -8,2,7891 -2,14,2337 -2,13,2337 -7,12,7006 -3,10,3300 -11,10,10772 -4,5,4299 -10,14,9909 -12,5,11532 -9,10,8809 -12,12,11954 -14,11,13452 -8,8,7965 -4,0,449 -5,6,5127 -7,8,6921 -4,4,4244 -1,10,1370 -5,9,5122 -1,7,1369 -0,3,844 -8,3,7937 -9,9,8777 -13,6,12476 -9,3,8961 -2,5,2368 -1,12,1363 -5,12,5075 -13,11,12363 -6,13,5963 -0,8,484 -2,12,2370 -8,5,7946 -14,9,13504 -12,1,11839 -12,2,11601 -2,6,2329 -10,10,9602 -7,3,6970 -14,6,13394 -0,7,628 -6,9,6100 -12,13,11391 -0,12,458 -1,14,1370 -12,10,11719 -9,8,8807 -4,7,4235 -1,0,462 -3,11,3538 -11,7,10786 -11,13,10710 -11,2,10394 -3,9,3315 -4,6,4174 -13,8,12538 -9,11,8710 -12,14,11814 -13,2,12647 -8,7,8019 -3,1,3287 -4,8,4591 -4,3,4197 -6,10,5985 -5,7,5171 -12,9,11579 -10,4,9714 -12,4,11811 -2,3,2391 -8,9,7997 -9,7,8853 -11,1,10700 -11,11,10798 -13,4,12644 -6,4,6290 -6,2,5916 -2,0,427 -2,8,2355 -10,2,9637 -6,5,6069 -6,11,6048 -12,11,11921 -9,4,8754 -5,4,5111 -13,10,12518 -8,14,7837 -5,8,5127 -8,10,8085 -0,2,1028 -2,1,2400 -0,13,408 -6,14,6027 -12,8,11785 -2,2,2326 -1,2,1394 -4,1,4251 -1,1,1446 -3,0,433 -10,13,9693 -9,0,432 -1,3,1441 -9,13,8858 -9,14,8795 -11,9,10632 -12,0,417 -7,1,7013 -6,1,6097 -10,7,10114 -10,9,9876 -10,5,9802 -2,4,2363 -11,12,10781 -11,14,10677 -3,7,3262 -6,7,6201 -4,9,4380 -3,8,3345 -13,9,12485 -0,14,419 -1,6,1347 -4,2,4216 -4,14,4209 -7,9,6976 -13,0,458 -0,1,361 -5,14,5204 -14,2,13169 -5,10,5096 -1,5,1370 -8,0,431 -6,6,6031 -8,4,7809 -9,12,11983 -3,4,3276 -12,6,11921 -6,0,485 -1,13,1375 -4,11,4237 -0,10,481 -13,13,12545 -14,12,13253 -3,5,3210 -5,5,5158 -7,7,6992 -5,11,5076 -7,13,7056 -11,3,10584 -3,3,3302 -14,13,13280 -13,3,12771 -14,0,429 -7,5,7065 -7,14,6952 -8,6,7835 -2,7,2334 -2,11,2367 -11,4,10606 -7,11,6845 -14,8,13736 -0,5,844 -1,9,1333 -10,6,9721 -9,6,8769 -7,10,6998 -10,3,9810 -14,7,13311 -14,14,13481 -11,0,426 -5,3,5102 -1,4,1457 -13,14,12431 -12,3,11717 -13,5,12523 -14,10,13457 -0,6,705 -3,14,3335 -13,12,12714 -7,4,6951 -3,6,3247 -9,5,8713 -3,12,3401 -14,1,13199 -4,10,4260 -10,0,428 -5,13,5103 -0,0,421 -14,3,13070 -9,2,8816 -7,0,451 -7,2,6974 -1,8,1363 -13,1,12699 \ No newline at end of file +14,14,11964 +0,1,1078 +5,8,1818 +10,13,2632 +14,2,3392 +0,9,520 +9,3,2360 +10,5,2551 +10,11,2548 +6,8,1738 +12,12,2922 +0,8,601 +12,4,2919 +0,11,521 +6,4,1942 +11,7,2741 +9,4,2496 +5,9,1764 +13,9,3069 +2,5,1053 +5,11,1790 +14,1,3581 +5,0,962 +0,3,845 +1,3,868 +7,8,2013 +12,3,2987 +9,8,2328 +10,7,2533 +11,1,2766 +7,1,1938 +0,5,687 +6,9,1830 +10,14,2628 +6,12,1786 +4,0,835 +4,14,2464 +10,1,2633 +12,7,2948 +2,9,1066 +4,6,2646 +7,11,1999 +5,13,1748 +13,4,3110 +13,13,3094 +3,5,1166 +11,12,2745 +1,2,814 +9,5,2419 +2,11,1117 +1,13,835 +11,11,2759 +1,12,882 +9,1,2457 +0,6,680 +5,12,1794 +9,11,2326 +10,9,2546 +10,10,2604 +13,2,3250 +13,7,3113 +7,10,1959 +1,14,833 +6,6,1886 +14,7,3339 +6,7,1824 +11,6,2756 +12,6,3007 +14,6,3315 +4,3,11464 +2,14,924 +7,12,1966 +11,14,2817 +9,10,2367 +1,11,827 +8,14,2184 +14,0,643 +11,3,2781 +2,4,1123 +12,8,2950 +13,6,3160 +3,13,1289 +7,7,1989 +3,9,1142 +3,6,1168 +4,8,2788 +14,12,3346 +1,1,805 +5,10,1781 +7,13,1988 +5,5,2015 +0,14,520 +11,8,2890 +3,10,1140 +13,10,3235 +3,14,1185 +8,10,2183 +12,10,2896 +2,8,1072 +9,6,2358 +13,1,3066 +3,8,1133 +11,10,2758 +4,13,2550 +1,0,643 +4,2,5482 +3,7,1155 +1,4,726 +3,3,1192 +4,11,2576 +8,0,619 +9,2,2444 +10,3,2581 +4,5,5400 +5,3,2444 +1,10,804 +10,2,2563 +0,7,592 +0,2,802 +1,5,741 +2,7,984 +10,0,755 +13,14,3112 +5,14,1811 +8,12,2180 +6,11,1723 +4,7,2897 +10,8,2536 +1,7,813 +6,0,699 +8,2,2187 +5,7,1811 +14,8,3304 +2,0,661 +8,13,2185 +1,9,786 +3,0,623 +12,5,3012 +8,1,2203 +8,11,2285 +14,10,3413 +4,10,2613 +11,5,2729 +6,1,2035 +12,1,2891 +5,4,2036 +2,3,1083 +14,3,3312 +3,2,1278 +5,2,2392 +8,7,2151 +5,6,2072 +3,12,1230 +2,10,954 +2,13,932 +13,8,3128 +0,12,521 +11,4,2769 +7,2,1947 +4,1,1802 +8,8,2163 +7,3,1966 +13,3,3207 +1,8,746 +12,9,2955 +10,12,2570 +9,9,2388 +4,12,2566 +7,0,619 +7,9,2004 +13,0,607 +14,9,3355 +3,4,1154 +11,2,2753 +11,13,2739 +6,13,1735 +7,6,1983 +8,3,2166 +7,14,1958 +6,2,2101 +13,5,3221 +8,4,2120 +10,4,2716 +14,5,3264 +14,13,3299 +11,9,2725 +13,11,3132 +1,6,809 +2,2,1155 +4,4,2242 +8,6,2218 +12,0,645 +7,4,1925 +2,6,1054 +9,13,2340 +13,12,3112 +14,4,3334 +3,11,1139 +12,14,3004 +4,9,2649 +0,13,527 +12,11,2976 +0,0,1559 +12,13,2952 +6,10,1749 +14,11,3365 +11,0,647 +2,12,1024 +10,6,2562 +8,5,2227 +9,12,2363 +2,1,1023 +0,10,528 +6,3,2005 +8,9,2195 +7,5,1966 +6,14,1755 +9,0,608 +14,14,3389 +9,7,2391 +0,4,688 +5,1,2574 +9,14,2353 +12,2,2975 +3,1,1276 +6,5,1804 \ No newline at end of file diff --git a/macros/src/emit.rs b/macros/src/emit.rs index bd31d80..60884ca 100644 --- a/macros/src/emit.rs +++ b/macros/src/emit.rs @@ -76,15 +76,13 @@ fn emit_node_scope(node: &RsxNode) -> TokenStream { { #deps_emit r.dynamic_scope(move |scope| { - scope.access_children(|children| { - if #cond { - if children.is_empty() { - #(#kids)* - } - } else { - .children.clear(); + if #cond { + if scope.children.lock().unwrap().is_empty() { + #(#kids)* } - }) + } else { + scope.children.lock().unwrap().clear(); + } }, #deps_vec_emit); } } @@ -105,7 +103,7 @@ fn emit_node_scope(node: &RsxNode) -> TokenStream { #deps_emit #[allow(unused_parens)] r.dynamic_scope(move |scope| { - scope.access_children(|children| children.clear()); + scope.children.lock().unwrap().clear(); for #pat in #expr { #(#kids)* } diff --git a/src/component/context.rs b/src/component/context.rs index de08664..636cf5f 100644 --- a/src/component/context.rs +++ b/src/component/context.rs @@ -20,7 +20,7 @@ pub struct Context { component: AccessCell, view: AccessCell, event_handlers: AccessCell>>, - scopes: AccessCell>>, + pub(crate) scopes: Mutex>>, executor: Arc, } @@ -33,7 +33,7 @@ impl Context { component: AccessCell::new(Arc::new(component)), view: AccessCell::new(Arc::new(|_| {})), event_handlers: AccessCell::new(HashMap::new()), - scopes: AccessCell::new(Vec::new()), + scopes: Mutex::new(Vec::new()), executor, }) } @@ -111,16 +111,11 @@ impl Context { (h.lock().unwrap())(self, event.as_ref()); } - self.scopes.access(move |scopes| { - for scope in scopes { - let event = event.clone(); - scope.access_children(move |children| { - for (child, _) in children { - child.emit_event(event.clone()); - } - }); + for scope in self.scopes.lock().unwrap().iter() { + for (child, _) in scope.children.lock().unwrap().iter() { + child.emit_event(event.clone()); } - }); + } } pub fn emit_event_threaded( @@ -139,26 +134,16 @@ impl Context { }); } - let event = event.clone(); - self.scopes.access(move |scopes| { - for scope in scopes { - let event = event.clone(); - scope.access_children(move |children| { - for (child, _) in children { - child.emit_event_threaded(&event); - } - }); + for scope in self.scopes.lock().unwrap().iter() { + for (child, _) in scope.children.lock().unwrap().iter() { + child.emit_event_threaded(event); } - }); + } } pub fn scope(self: &Arc) -> Arc { let scope = Scope::new(self.executor.clone()); - - self.scopes.access({ - let scope = scope.clone(); - move |scopes| scopes.push(scope) - }); + self.scopes.lock().unwrap().push(scope.clone()); scope } @@ -169,11 +154,7 @@ impl Context { dependencies: &[&dyn HookDependency], ) -> Arc { let scope = Scope::new(self.executor.clone()); - - self.scopes.access({ - let scope = scope.clone(); - move |scopes| scopes.push(scope) - }); + self.scopes.lock().unwrap().push(scope.clone()); drawer(&scope); @@ -191,34 +172,21 @@ impl Context { } pub fn add_scope(self: &Arc, scope: Arc) { - self.scopes.access(|scopes| scopes.push(scope)); + self.scopes.lock().unwrap().push(scope); } pub fn draw_children(self: &Arc, ctx: &mut DrawContext) { - let c = ctx.clone(); + for scope in self.scopes.lock().unwrap().iter() { + for (child, view_wrapper) in scope.children.lock().unwrap().iter() { + let view = child.get_view(); - let (tx, rx) = std::sync::mpsc::channel::(); - - self.scopes.access(move |scopes| { - for scope in scopes { - let mut c = c.clone(); - let tx = tx.clone(); - scope.access_children(move |children| { - for (child, view_wrapper) in children { - let view = child.get_view(); - - if let Some(view_wrapper) = view_wrapper { - view_wrapper(&mut c, view) - } else { - c.draw_view(c.area.clone(), view); - } - } - tx.send(c.clone()).expect("Failed transmitting DrawContext"); - }); + if let Some(view_wrapper) = view_wrapper { + view_wrapper(ctx, view) + } else { + ctx.draw_view(ctx.area.clone(), view); + } } - }); - - *ctx = rx.recv().expect("Failed receiving DrawContext"); + } } pub fn get_executor(self: &Arc) -> Arc { diff --git a/src/component/scope.rs b/src/component/scope.rs index 83201ce..6cfe6e5 100644 --- a/src/component/scope.rs +++ b/src/component/scope.rs @@ -1,19 +1,18 @@ -use super::{context::Context, ComponentImpl}; -use crate::{engine::CommandExecutor, View, ViewWrapper}; -use access_cell::AccessCell; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; -pub type ScopeChildren = Vec<(Arc, Option)>; +use crate::{engine::CommandExecutor, View, ViewWrapper}; + +use super::{context::Context, ComponentImpl}; pub struct Scope { - children: AccessCell, + pub children: Mutex, Option)>>, executor: Arc, } impl Scope { pub fn new(executor: Arc) -> Arc { Arc::new(Self { - children: AccessCell::new(Vec::new()), + children: Mutex::new(Vec::new()), executor, }) } @@ -27,8 +26,7 @@ impl Scope { ctx.refresh(); - self.children - .access(|children| children.push((ctx, view_wrapper))); + self.children.lock().unwrap().push((ctx, view_wrapper)); } pub fn view(self: &Arc, view: View) { @@ -36,19 +34,6 @@ impl Scope { ctx.refresh(); - self.children.access(|children| children.push((ctx, None))); - } - - pub fn view_wrapper(self: &Arc, view: View, view_wrapper: Option) { - let ctx = Context::new(view, self.executor.clone()); - - ctx.refresh(); - - self.children - .access(|children| children.push((ctx, view_wrapper))); - } - - pub fn access_children(self: &Arc, f: impl FnOnce(&mut ScopeChildren) + Send + 'static) { - self.children.access(f); + self.children.lock().unwrap().push((ctx, None)); } }