From c4a18bc24d8722dda6c7c432a18f11671046718a Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 11 Jan 2023 16:13:41 -0800 Subject: [PATCH 1/2] chore: clean up some clippy warnings and add clippy lints to CI --- .github/workflows/main.yml | 2 +- examples/compose.rs | 4 +- examples/custom_element.rs | 40 ---- examples/fermi.rs | 2 +- examples/multiwindow.rs | 3 +- examples/overlay.rs | 2 +- examples/simple_desktop.rs | 2 + packages/core/tests/attr_cleanup.rs | 2 +- packages/core/tests/error_boundary.rs | 36 +--- packages/core/tests/miri_stress.rs | 225 +--------------------- packages/native-core/tests/miri_native.rs | 26 +-- packages/web/src/dom.rs | 5 +- 12 files changed, 36 insertions(+), 313 deletions(-) delete mode 100644 examples/custom_element.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee5a763c7..96649c903 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -104,7 +104,7 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: --workspace -- -D warnings + args: --workspace --examples --tests -- -D warnings # Coverage is disabled until we can fix it # coverage: diff --git a/examples/compose.rs b/examples/compose.rs index fa5d6e4c2..3ee6d36ae 100644 --- a/examples/compose.rs +++ b/examples/compose.rs @@ -10,7 +10,7 @@ fn main() { fn app(cx: Scope) -> Element { let window = use_window(cx); - let emails_sent = use_ref(cx, || vec![]); + let emails_sent = use_ref(cx, Vec::new); let tx = use_coroutine(cx, |mut rx: UnboundedReceiver| { to_owned![emails_sent]; @@ -56,7 +56,7 @@ struct ComposeProps { } fn compose(cx: Scope) -> Element { - let user_input = use_state(cx, || String::new()); + let user_input = use_state(cx, String::new); let window = use_window(cx); cx.render(rsx! { diff --git a/examples/custom_element.rs b/examples/custom_element.rs deleted file mode 100644 index 6ed2e64cd..000000000 --- a/examples/custom_element.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! This example shows to wrap a webcomponent / custom element with a component. -//! -//! Oftentimes, a third party library will provide a webcomponent that you want -//! to use in your application. This example shows how to create that custom element -//! directly with the raw_element method on NodeFactory. - -use dioxus::prelude::*; - -fn main() { - let mut dom = VirtualDom::new(app); - let _ = dom.rebuild(); - - let output = dioxus_ssr::render(&dom); - - println!("{}", output); -} - -fn app(cx: Scope) -> Element { - let g = cx.component(component, (), "component"); - let c = cx.make_node(g); - cx.render(rsx! { - div { c } - }) - - // let nf = NodeFactory::new(cx); - - // let mut attrs = dioxus::core::exports::bumpalo::collections::Vec::new_in(nf.bump()); - - // attrs.push(nf.attr("client-id", format_args!("abc123"), None, false)); - - // attrs.push(nf.attr("name", format_args!("bob"), None, false)); - - // attrs.push(nf.attr("age", format_args!("47"), None, false)); - - // Some(nf.raw_element("my-element", None, &[], attrs.into_bump_slice(), &[], None)) -} - -fn component(cx: Scope) -> Element { - todo!() -} diff --git a/examples/fermi.rs b/examples/fermi.rs index 506d9fe98..001890892 100644 --- a/examples/fermi.rs +++ b/examples/fermi.rs @@ -10,7 +10,7 @@ fn main() { static NAME: Atom = |_| "world".to_string(); fn app(cx: Scope) -> Element { - use_init_atom_root(&cx); + use_init_atom_root(cx); let name = use_read(cx, NAME); cx.render(rsx! { diff --git a/examples/multiwindow.rs b/examples/multiwindow.rs index 943890f3b..e2caeba80 100644 --- a/examples/multiwindow.rs +++ b/examples/multiwindow.rs @@ -1,12 +1,11 @@ use dioxus::prelude::*; -use dioxus_desktop::{use_window, WindowBuilder}; fn main() { dioxus_desktop::launch(app); } fn app(cx: Scope) -> Element { - let window = use_window(cx); + let window = dioxus_desktop::use_window(cx); cx.render(rsx! { div { diff --git a/examples/overlay.rs b/examples/overlay.rs index 359fa5169..0afd830be 100644 --- a/examples/overlay.rs +++ b/examples/overlay.rs @@ -1,5 +1,5 @@ use dioxus::prelude::*; -use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, Config, LogicalSize, WindowBuilder}; +use dioxus_desktop::{tao::dpi::PhysicalPosition, use_window, LogicalSize, WindowBuilder}; fn main() { dioxus_desktop::launch_cfg(app, make_config()); diff --git a/examples/simple_desktop.rs b/examples/simple_desktop.rs index d8c00afac..74bfb28c6 100644 --- a/examples/simple_desktop.rs +++ b/examples/simple_desktop.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use dioxus::prelude::*; use dioxus_router::*; diff --git a/packages/core/tests/attr_cleanup.rs b/packages/core/tests/attr_cleanup.rs index 2e3cf5d17..683f02260 100644 --- a/packages/core/tests/attr_cleanup.rs +++ b/packages/core/tests/attr_cleanup.rs @@ -5,7 +5,7 @@ use bumpalo::Bump; use dioxus::core::{ElementId, Mutation::*}; use dioxus::prelude::*; -use dioxus_core::{AttributeValue, BorrowedAttributeValue}; +use dioxus_core::BorrowedAttributeValue; #[test] fn attrs_cycle() { diff --git a/packages/core/tests/error_boundary.rs b/packages/core/tests/error_boundary.rs index 7dbfca343..ce26fba31 100644 --- a/packages/core/tests/error_boundary.rs +++ b/packages/core/tests/error_boundary.rs @@ -1,13 +1,11 @@ +#![allow(non_snake_case)] + use dioxus::prelude::*; -use futures_util::Future; #[test] fn catches_panic() { let mut dom = VirtualDom::new(app); - - let a = dom.rebuild(); - - dbg!(a); + _ = dom.rebuild(); } fn app(cx: Scope) -> Element { @@ -16,43 +14,21 @@ fn app(cx: Scope) -> Element { h1 { "Title" } NoneChild {} + ThrowChild {} } }) } -fn NoneChild(cx: Scope) -> Element { +fn NoneChild(_cx: Scope) -> Element { None } -fn PanicChild(cx: Scope) -> Element { - panic!("Rendering panicked for whatever reason"); - - cx.render(rsx! { - h1 { "It works!" } - }) -} - fn ThrowChild(cx: Scope) -> Element { cx.throw(std::io::Error::new(std::io::ErrorKind::AddrInUse, "asd"))?; - let g: i32 = "123123".parse().throw(cx)?; + let _g: i32 = "123123".parse().throw(cx)?; cx.render(rsx! { div {} }) } - -fn custom_allocator(cx: Scope) -> Element { - let g = String::new(); - - let p = g.as_str(); - - let g2 = cx.use_hook(|| 123); - // cx.spawn(async move { - - // // - // // println!("Thig is {p}"); - // }); - - None -} diff --git a/packages/core/tests/miri_stress.rs b/packages/core/tests/miri_stress.rs index c73847c19..15b7ebf41 100644 --- a/packages/core/tests/miri_stress.rs +++ b/packages/core/tests/miri_stress.rs @@ -143,15 +143,15 @@ fn supports_async() { use tokio::time::sleep; fn app(cx: Scope) -> Element { - let colors = use_state(&cx, || vec!["green", "blue", "red"]); - let padding = use_state(&cx, || 10); + let colors = use_state(cx, || vec!["green", "blue", "red"]); + let padding = use_state(cx, || 10); - use_effect(&cx, colors, |colors| async move { + use_effect(cx, colors, |colors| async move { sleep(Duration::from_millis(1000)).await; colors.with_mut(|colors| colors.reverse()); }); - use_effect(&cx, padding, |padding| async move { + use_effect(cx, padding, |padding| async move { sleep(Duration::from_millis(10)).await; padding.with_mut(|padding| { if *padding < 65 { @@ -206,220 +206,9 @@ fn supports_async() { let mut dom = VirtualDom::new(app); let _ = dom.rebuild(); - for x in 0..10 { - let _ = dom.wait_for_work().await; - let edits = dom.render_immediate(); + for _ in 0..10 { + dom.wait_for_work().await; + let _edits = dom.render_immediate(); } }); } - -// #[test] -// fn old_props_arent_stale() { -// fn app(cx: Scope) -> Element { -// dbg!("rendering parent"); -// let cnt = cx.use_hook(|| 0); -// *cnt += 1; - -// if *cnt == 1 { -// render!(div { Child { a: "abcdef".to_string() } }) -// } else { -// render!(div { Child { a: "abcdef".to_string() } }) -// } -// } - -// #[derive(Props, PartialEq)] -// struct ChildProps { -// a: String, -// } -// fn Child(cx: Scope) -> Element { -// dbg!("rendering child", &cx.props.a); -// render!(div { "child {cx.props.a}" }) -// } - -// let mut dom = new_dom(app, ()); -// let _ = dom.rebuild(); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dbg!("forcing update to child"); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); -// } - -// #[test] -// fn basic() { -// fn app(cx: Scope) -> Element { -// render!(div { -// Child { a: "abcdef".to_string() } -// }) -// } - -// #[derive(Props, PartialEq)] -// struct ChildProps { -// a: String, -// } - -// fn Child(cx: Scope) -> Element { -// dbg!("rendering child", &cx.props.a); -// render!(div { "child {cx.props.a}" }) -// } - -// let mut dom = new_dom(app, ()); -// let _ = dom.rebuild(); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); -// } - -// #[test] -// fn leak_thru_children() { -// fn app(cx: Scope) -> Element { -// cx.render(rsx! { -// Child { -// name: "asd".to_string(), -// } -// }); -// cx.render(rsx! { -// div {} -// }) -// } - -// #[inline_props] -// fn Child(cx: Scope, name: String) -> Element { -// render!(div { "child {name}" }) -// } - -// let mut dom = new_dom(app, ()); -// let _ = dom.rebuild(); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); -// } - -// #[test] -// fn test_pass_thru() { -// #[inline_props] -// fn NavContainer<'a>(cx: Scope, children: Element<'a>) -> Element { -// cx.render(rsx! { -// header { -// nav { children } -// } -// }) -// } - -// fn NavMenu(cx: Scope) -> Element { -// render!( NavBrand {} -// div { -// NavStart {} -// NavEnd {} -// } -// ) -// } - -// fn NavBrand(cx: Scope) -> Element { -// render!(div {}) -// } - -// fn NavStart(cx: Scope) -> Element { -// render!(div {}) -// } - -// fn NavEnd(cx: Scope) -> Element { -// render!(div {}) -// } - -// #[inline_props] -// fn MainContainer<'a>( -// cx: Scope, -// nav: Element<'a>, -// body: Element<'a>, -// footer: Element<'a>, -// ) -> Element { -// cx.render(rsx! { -// div { -// class: "columns is-mobile", -// div { -// class: "column is-full", -// nav, -// body, -// footer, -// } -// } -// }) -// } - -// fn app(cx: Scope) -> Element { -// let nav = cx.render(rsx! { -// NavContainer { -// NavMenu {} -// } -// }); -// let body = cx.render(rsx! { -// div {} -// }); -// let footer = cx.render(rsx! { -// div {} -// }); - -// cx.render(rsx! { -// MainContainer { -// nav: nav, -// body: body, -// footer: footer, -// } -// }) -// } - -// let mut dom = new_dom(app, ()); -// let _ = dom.rebuild(); - -// for _ in 0..40 { -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(0))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(1))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(2))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(2))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(2))); -// dom.work_with_deadline(|| false); - -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(3))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(3))); -// dom.work_with_deadline(|| false); -// dom.handle_message(SchedulerMsg::Immediate(ScopeId(3))); -// dom.work_with_deadline(|| false); -// } -// } diff --git a/packages/native-core/tests/miri_native.rs b/packages/native-core/tests/miri_native.rs index 5823fb5a1..338f86915 100644 --- a/packages/native-core/tests/miri_native.rs +++ b/packages/native-core/tests/miri_native.rs @@ -1,5 +1,4 @@ use dioxus::prelude::*; -use dioxus_native_core::*; use dioxus_native_core::{ node_ref::{AttributeMask, NodeView}, real_dom::RealDom, @@ -7,13 +6,10 @@ use dioxus_native_core::{ NodeMask, SendAnyMap, }; use dioxus_native_core_macro::{sorted_str_slice, State}; -use std::{ - sync::{Arc, Mutex}, - time::Duration, -}; +use std::sync::{Arc, Mutex}; use tokio::time::sleep; -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] pub struct BlablaState {} /// Font style are inherited by default if not specified otherwise by some of the supported attributes. @@ -88,15 +84,15 @@ fn native_core_is_okay() { use std::time::Duration; fn app(cx: Scope) -> Element { - let colors = use_state(&cx, || vec!["green", "blue", "red"]); - let padding = use_state(&cx, || 10); + let colors = use_state(cx, || vec!["green", "blue", "red"]); + let padding = use_state(cx, || 10); - use_effect(&cx, colors, |colors| async move { + use_effect(cx, colors, |colors| async move { sleep(Duration::from_millis(1000)).await; colors.with_mut(|colors| colors.reverse()); }); - use_effect(&cx, padding, |padding| async move { + use_effect(cx, padding, |padding| async move { sleep(Duration::from_millis(10)).await; padding.with_mut(|padding| { if *padding < 65 { @@ -107,9 +103,9 @@ fn native_core_is_okay() { }); }); - let big = colors[0]; - let mid = colors[1]; - let small = colors[2]; + let _big = colors[0]; + let _mid = colors[1]; + let _small = colors[2]; cx.render(rsx! { blabla {} @@ -128,17 +124,15 @@ fn native_core_is_okay() { let muts = dom.rebuild(); let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(muts); - let ctx = SendAnyMap::new(); let ctx = SendAnyMap::new(); rdom.lock().unwrap().update_state(to_update, ctx); - for x in 0..10 { + for _ in 0..10 { dom.wait_for_work().await; let mutations = dom.render_immediate(); let (to_update, _diff) = rdom.lock().unwrap().apply_mutations(mutations); - let ctx = SendAnyMap::new(); let ctx = SendAnyMap::new(); rdom.lock().unwrap().update_state(to_update, ctx); } diff --git a/packages/web/src/dom.rs b/packages/web/src/dom.rs index 252add068..4497b5fef 100644 --- a/packages/web/src/dom.rs +++ b/packages/web/src/dom.rs @@ -234,7 +234,10 @@ pub fn virtual_event_from_websys_event(event: web_sys::Event, target: Element) - Rc::new(MouseData::from(event)) } "drag" | "dragend" | "dragenter" | "dragexit" | "dragleave" | "dragover" | "dragstart" - | "drop" => Rc::new(DragData::from(event)), + | "drop" => { + let mouse = MouseData::from(event); + Rc::new(DragData { mouse }) + } "pointerdown" | "pointermove" | "pointerup" | "pointercancel" | "gotpointercapture" | "lostpointercapture" | "pointerenter" | "pointerleave" | "pointerover" | "pointerout" => { From cf79ca8113d2437afe4de82a7c85c805f424149c Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Wed, 11 Jan 2023 17:12:09 -0800 Subject: [PATCH 2/2] chore: stop ignoring some doc tests --- packages/core/.vscode/settings.json | 3 ++ packages/core/README.md | 45 ++++++++++++++++++----------- packages/core/src/virtual_dom.rs | 39 +++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 packages/core/.vscode/settings.json diff --git a/packages/core/.vscode/settings.json b/packages/core/.vscode/settings.json new file mode 100644 index 000000000..eb230f7ba --- /dev/null +++ b/packages/core/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.checkOnSave.allTargets": false +} diff --git a/packages/core/README.md b/packages/core/README.md index e70872410..7659f6713 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -33,34 +33,45 @@ The `dioxus` crate exports the `rsx` macro which transforms a helpful, simpler s First, start with your app: -```rust, ignore +```rust +# use dioxus::core::Mutations; +use dioxus::prelude::*; + +// First, declare a root component fn app(cx: Scope) -> Element { - cx.render(rsx!( div { "hello world" } )) + cx.render(rsx!{ + div { "hello world" } + }) } + +fn main() { + // Next, create a new VirtualDom using this app as the root component. + let mut dom = VirtualDom::new(app); + + // The initial render of the dom will generate a stream of edits for the real dom to apply + let mutations = dom.rebuild(); + + // Somehow, you can apply these edits to the real dom + apply_edits_to_real_dom(mutations); +} + +# fn apply_edits_to_real_dom(mutations: Mutations) {} ``` -Then, we'll want to create a new VirtualDom using this app as the root component. - -```rust, ignore -let mut dom = VirtualDom::new(app); -``` - -To build the app into a stream of mutations, we'll use [`VirtualDom::rebuild`]: - -```rust, ignore -let mutations = dom.rebuild(); - -apply_edits_to_real_dom(mutations); -``` We can then wait for any asynchronous components or pending futures using the `wait_for_work()` method. If we have a deadline, then we can use render_with_deadline instead: +```rust +# #![allow(unused)] +# use dioxus::prelude::*; -```rust, ignore +# use std::time::Duration; +# async fn wait(mut dom: VirtualDom) { // Wait for the dom to be marked dirty internally dom.wait_for_work().await; // Or wait for a deadline and then collect edits -dom.render_with_deadline(tokio::time::sleep(Duration::from_millis(16))); +let mutations = dom.render_with_deadline(tokio::time::sleep(Duration::from_millis(16))); +# } ``` If an event occurs from outside the VirtualDom while waiting for work, then we can cancel the wait using a `select!` block and inject the event. diff --git a/packages/core/src/virtual_dom.rs b/packages/core/src/virtual_dom.rs index 7369386b5..d05dab347 100644 --- a/packages/core/src/virtual_dom.rs +++ b/packages/core/src/virtual_dom.rs @@ -24,7 +24,9 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future /// /// Components are defined as simple functions that take [`Scope`] and return an [`Element`]. /// -/// ```rust, ignore +/// ```rust +/// # use dioxus::prelude::*; +/// /// #[derive(Props, PartialEq)] /// struct AppProps { /// title: String @@ -39,7 +41,17 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future /// /// Components may be composed to make complex apps. /// -/// ```rust, ignore +/// ```rust +/// # #![allow(unused)] +/// # use dioxus::prelude::*; +/// +/// # #[derive(Props, PartialEq)] +/// # struct AppProps { +/// # title: String +/// # } +/// +/// static ROUTES: &str = ""; +/// /// fn App(cx: Scope) -> Element { /// cx.render(rsx!( /// NavBar { routes: ROUTES } @@ -47,12 +59,33 @@ use std::{any::Any, borrow::BorrowMut, cell::Cell, collections::BTreeSet, future /// Footer {} /// )) /// } +/// +/// #[inline_props] +/// fn NavBar(cx: Scope, routes: &'static str) -> Element { +/// cx.render(rsx! { +/// div { "Routes: {routes}" } +/// }) +/// } +/// +/// fn Footer(cx: Scope) -> Element { +/// cx.render(rsx! { div { "Footer" } }) +/// } +/// +/// #[inline_props] +/// fn Title<'a>(cx: Scope<'a>, children: Element<'a>) -> Element { +/// cx.render(rsx! { +/// div { id: "title", children } +/// }) +/// } /// ``` /// /// To start an app, create a [`VirtualDom`] and call [`VirtualDom::rebuild`] to get the list of edits required to /// draw the UI. /// -/// ```rust, ignore +/// ```rust +/// # use dioxus::prelude::*; +/// # fn App(cx: Scope) -> Element { cx.render(rsx! { div {} }) } +/// /// let mut vdom = VirtualDom::new(App); /// let edits = vdom.rebuild(); /// ```