diff --git a/Cargo.lock b/Cargo.lock index 96004f7..6849d81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,87 +2,18 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - [[package]] name = "js-sys" version = "0.3.66" @@ -92,108 +23,18 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" -dependencies = [ - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - [[package]] name = "proc-macro2" version = "1.0.70" @@ -212,52 +53,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys", -] - [[package]] name = "syn" version = "2.0.41" @@ -269,36 +64,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tokio" -version = "1.35.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "unicode-ident" version = "1.0.12" @@ -309,7 +74,6 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" name = "viewbuilder" version = "0.9.4" dependencies = [ - "tokio", "web-sys", ] @@ -327,12 +91,6 @@ dependencies = [ "viewbuilder", ] -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "wasm-bindgen" version = "0.2.89" @@ -396,69 +154,3 @@ dependencies = [ "js-sys", "wasm-bindgen", ] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index 083f8cf..6873b72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,6 @@ members = [ full = [] [dependencies] -tokio = { version = "1.35.1", features = ["full"], optional = true } web-sys = { version = "0.3.66", features = ["Document", "HtmlElement", "Window", "Text"] } [package.metadata.docs.rs] diff --git a/README.md b/README.md index 515d492..1594a7d 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,13 @@ A cross-platform user interface framework for Rust. Viewbuilder is a moduler GUI library that can be used as an entire framework, or with individual parts. ```rust +use std::{cell::RefCell, rc::Rc, sync::Arc}; +use viewbuilder::{ + view, + web::{self, html, Web}, + Application, ControlFlow, Model, View, +}; + enum Message { Increment, Decrement, @@ -45,7 +52,7 @@ impl Model for App { } } -fn app(model: &App) -> impl View { +fn view(model: &App) -> impl View { ( format!("High five count: {}", model.count), view::once(html::div(html::on_click(|| Message::Increment), "Up high!")), @@ -55,6 +62,10 @@ fn app(model: &App) -> impl View { )), ) } + +fn main() { + web::run(App::default(), view) +} ``` ## Getting started diff --git a/src/lib.rs b/src/lib.rs index 20d5ab8..4cd9cfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,4 @@ use std::sync::Arc; -#[cfg(feature = "tokio")] -use tokio::sync::mpsc; -use web_sys::{wasm_bindgen::JsCast, Document, Element, Text}; pub mod view; pub use self::view::View; @@ -92,153 +89,3 @@ impl Application { self.model.handle(msg) } } -#[cfg(feature = "tokio")] -pub struct App { - model: T, - composable: F, - state: Option, - cx: Context, - tree: Tree, - rx: mpsc::UnboundedReceiver, -} - -#[cfg(feature = "tokio")] -impl App { - pub fn new(model: T, composable: F, tree: Tree) -> Self - where - M: Send + 'static, - { - let (tx, rx) = mpsc::unbounded_channel(); - let cx = Context::new(Arc::new(move |msg| { - tx.send(msg).unwrap(); - })); - Self { - model, - composable, - state: None, - cx, - rx, - tree, - } - } - - pub fn build(&mut self) - where - T: Model, - F: FnMut(&T) -> C, - C: View, - { - let state = (self.composable)(&self.model).build(&mut self.cx, &mut self.tree); - self.state = Some(state); - } - - pub fn rebuild(&mut self) - where - T: Model, - F: FnMut(&T) -> C, - C: View, - { - let state = self.state.as_mut().unwrap(); - (self.composable)(&self.model).rebuild(&mut self.cx, &mut self.tree, state); - } - - pub async fn handle(&mut self) -> ControlFlow - where - T: Model, - M: 'static, - { - let msg = self.rx.recv().await.unwrap(); - self.model.handle(msg) - } - - pub fn try_handle(&mut self) -> Option - where - T: Model, - M: 'static, - { - if let Ok(msg) = self.rx.try_recv() { - Some(self.model.handle(msg)) - } else { - None - } - } - - pub fn try_run(&mut self) - where - T: Model, - F: FnMut(&T) -> C, - C: View, - M: 'static, - { - match self.try_handle() { - Some(ControlFlow::Rebuild) => self.rebuild(), - Some(ControlFlow::Pending) | None => {} - } - } - - pub async fn run(&mut self) - where - T: Model, - F: FnMut(&T) -> C, - C: View, - M: 'static, - { - match self.handle().await { - ControlFlow::Rebuild => self.rebuild(), - ControlFlow::Pending => {} - } - } -} - -pub struct Web { - document: Document, - parent: Element, -} - -impl Default for Web { - fn default() -> Self { - let document = web_sys::window().unwrap().document().unwrap(); - Self { - parent: document.body().unwrap().unchecked_into(), - document, - } - } -} - -pub struct HtmlAttributes { - element: Element, -} - -impl View for &'static str { - type Element = (Self, Text); - - fn build(&mut self, _cx: &mut Context, tree: &mut Web) -> Self::Element { - let text = tree.document.create_text_node(self); - tree.parent.append_child(&text).unwrap(); - (self, text) - } - - fn rebuild(&mut self, _cx: &mut Context, _tree: &mut Web, element: &mut Self::Element) { - if *self != element.0 { - element.0 = self; - element.1.set_text_content(Some(self)); - } - } -} - -impl View for String { - type Element = (Self, Text); - - fn build(&mut self, _cx: &mut Context, tree: &mut Web) -> Self::Element { - let text = tree.document.create_text_node(self); - tree.parent.append_child(&text).unwrap(); - (self.clone(), text) - } - - fn rebuild(&mut self, _cx: &mut Context, _tree: &mut Web, element: &mut Self::Element) { - if *self != element.0 { - element.0 = self.clone(); - element.1.set_text_content(Some(self)); - } - } -} diff --git a/src/web/html.rs b/src/web/html.rs index 1ade052..5346aed 100644 --- a/src/web/html.rs +++ b/src/web/html.rs @@ -1,4 +1,5 @@ -use crate::{Context, HtmlAttributes, View, Web}; +use super::{HtmlAttributes, Web}; +use crate::{Context, View}; use std::{fmt, marker::PhantomData, mem}; use web_sys::wasm_bindgen::{closure::Closure, JsCast}; @@ -170,9 +171,9 @@ where fn rebuild( &mut self, - cx: &mut Context, - tree: &mut HtmlAttributes, - element: &mut Self::Element, + _cx: &mut Context, + _tree: &mut HtmlAttributes, + _element: &mut Self::Element, ) { todo!() } @@ -198,12 +199,17 @@ where { type Element = (K, V); - fn build(&mut self, cx: &mut Context, tree: &mut StyleTree) -> Self::Element { + fn build(&mut self, _cx: &mut Context, tree: &mut StyleTree) -> Self::Element { tree.s.push_str(&format!("{}: {};", &self.key, &self.value)); (self.key.clone(), self.value.clone()) } - fn rebuild(&mut self, cx: &mut Context, tree: &mut StyleTree, element: &mut Self::Element) { + fn rebuild( + &mut self, + _cx: &mut Context, + _tree: &mut StyleTree, + _element: &mut Self::Element, + ) { todo!() } } diff --git a/src/web/mod.rs b/src/web/mod.rs index 3d4613d..3e27a85 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -1 +1,86 @@ +use crate::{Application, Context, ControlFlow, Model, View}; +use std::{cell::RefCell, rc::Rc, sync::Arc}; +use web_sys::{wasm_bindgen::JsCast, Document, Element, Text}; + pub mod html; + +pub fn run(model: T, view_builder: VB) +where + T: Model + 'static, + VB: FnMut(&T) -> V + 'static, + V: View, + V::Element: 'static, + + M: Send + 'static, +{ + let cell = Rc::new(RefCell::new(None::>)); + let cell_clone = cell.clone(); + let mut app = Application::new( + Arc::new(move |msg| { + let mut g = cell_clone.borrow_mut(); + let app = g.as_mut().unwrap(); + if let ControlFlow::Rebuild = app.handle(msg) { + app.rebuild(); + } + }), + model, + view_builder, + Web::default(), + ); + app.build(); + + *cell.borrow_mut() = Some(app); +} + +pub struct Web { + document: Document, + parent: Element, +} + +impl Default for Web { + fn default() -> Self { + let document = web_sys::window().unwrap().document().unwrap(); + Self { + parent: document.body().unwrap().unchecked_into(), + document, + } + } +} + +pub struct HtmlAttributes { + element: Element, +} + +impl View for &'static str { + type Element = (Self, Text); + + fn build(&mut self, _cx: &mut Context, tree: &mut Web) -> Self::Element { + let text = tree.document.create_text_node(self); + tree.parent.append_child(&text).unwrap(); + (self, text) + } + + fn rebuild(&mut self, _cx: &mut Context, _tree: &mut Web, element: &mut Self::Element) { + if *self != element.0 { + element.0 = self; + element.1.set_text_content(Some(self)); + } + } +} + +impl View for String { + type Element = (Self, Text); + + fn build(&mut self, _cx: &mut Context, tree: &mut Web) -> Self::Element { + let text = tree.document.create_text_node(self); + tree.parent.append_child(&text).unwrap(); + (self.clone(), text) + } + + fn rebuild(&mut self, _cx: &mut Context, _tree: &mut Web, element: &mut Self::Element) { + if *self != element.0 { + element.0 = self.clone(); + element.1.set_text_content(Some(self)); + } + } +} diff --git a/web_examples/counter/src/main.rs b/web_examples/counter/src/main.rs index 970d021..473ff8b 100644 --- a/web_examples/counter/src/main.rs +++ b/web_examples/counter/src/main.rs @@ -1,5 +1,8 @@ -use std::{cell::RefCell, rc::Rc, sync::Arc}; -use viewbuilder::{view, web::html, Application, ControlFlow, Model, View, Web}; +use viewbuilder::{ + view, + web::{self, html, Web}, + ControlFlow, Model, View, +}; enum Message { Increment, @@ -21,7 +24,7 @@ impl Model for App { } } -fn app(model: &App) -> impl View { +fn view(model: &App) -> impl View { ( format!("High five count: {}", model.count), view::once(html::div(html::on_click(|| Message::Increment), "Up high!")), @@ -33,21 +36,5 @@ fn app(model: &App) -> impl View { } fn main() { - let cell = Rc::new(RefCell::new(None::>)); - let cell_clone = cell.clone(); - let mut app = Application::new( - Arc::new(move |msg| { - let mut g = cell_clone.borrow_mut(); - let app = g.as_mut().unwrap(); - if let ControlFlow::Rebuild = app.handle(msg) { - app.rebuild(); - } - }), - App::default(), - app, - Web::default(), - ); - app.build(); - - *cell.borrow_mut() = Some(app); + web::run(App::default(), view) } diff --git a/web_examples/todomvc/src/main.rs b/web_examples/todomvc/src/main.rs index 8d44662..2d29739 100644 --- a/web_examples/todomvc/src/main.rs +++ b/web_examples/todomvc/src/main.rs @@ -1,5 +1,7 @@ -use std::{cell::RefCell, rc::Rc, sync::Arc}; -use viewbuilder::{web::html, Application, ControlFlow, Model, View, Web}; +use viewbuilder::{ + web::{self, html, Web}, + ControlFlow, Model, View, +}; enum Message { Check { id: u64, is_checked: bool }, @@ -90,21 +92,5 @@ impl Model for App { } fn main() { - let cell = Rc::new(RefCell::new(None::>)); - let cell_clone = cell.clone(); - let mut app = Application::new( - Arc::new(move |msg| { - let mut g = cell_clone.borrow_mut(); - let app = g.as_mut().unwrap(); - if let ControlFlow::Rebuild = app.handle(msg) { - app.rebuild(); - } - }), - App::default(), - view, - Web::default(), - ); - app.build(); - - *cell.borrow_mut() = Some(app); + web::run(App::default(), view) }