From 33bba24867e2a452f504b4bb7e14dc42c8f95242 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Mon, 15 Jan 2024 21:12:44 -0800 Subject: [PATCH] Experiment with call syntax only working for copy types --- examples/calculator.rs | 4 ++-- examples/compose.rs | 4 ++-- examples/control_focus.rs | 2 +- examples/disabled.rs | 2 +- examples/dog_app.rs | 4 +++- examples/heavy_compute.rs | 28 ----------------------- examples/login_form.rs | 2 +- examples/read_size.rs | 2 +- examples/scroll_to_top.rs | 2 +- examples/signals.rs | 6 ++--- examples/spread.rs | 5 ++-- examples/ssr.rs | 5 ++-- examples/svg.rs | 2 +- examples/todomvc.rs | 27 +++++++++++----------- examples/window_event.rs | 8 +++---- examples/window_focus.rs | 2 +- packages/signals/examples/dependancies.rs | 2 +- packages/signals/src/signal.rs | 19 ++++++++------- packages/signals/tests/selector.rs | 2 +- 19 files changed, 52 insertions(+), 76 deletions(-) delete mode 100644 examples/heavy_compute.rs diff --git a/examples/calculator.rs b/examples/calculator.rs index 23cd1284a..574a8eb5c 100644 --- a/examples/calculator.rs +++ b/examples/calculator.rs @@ -22,7 +22,7 @@ fn app() -> Element { let val = use_signal(|| String::from("0")); let input_digit = move |num: u8| { - if *val() == "0" { + if val.cloned() == "0" { val.set(String::new()); } @@ -94,7 +94,7 @@ fn app() -> Element { class: "calculator-key key-percent", onclick: move |_| { val.set( - format!("{}", calc_val(val().as_str()) / 100.0) + format!("{}", calc_val(val.cloned().as_str()) / 100.0) ); }, "%" diff --git a/examples/compose.rs b/examples/compose.rs index 6ddda19dc..63362d517 100644 --- a/examples/compose.rs +++ b/examples/compose.rs @@ -22,7 +22,7 @@ fn app() -> Element { let open_compose_window = move |evt: MouseEvent| { let tx = handle.tx(); dioxus_desktop::window().new_window( - VirtualDom::new_with_props(compose, Rc::new(move |s| tx.unbounded_send(s))), + VirtualDom::new_with_props(compose, Rc::new(move |s| tx.unbounded_send(s).unwrap())), Default::default(), ); }; @@ -50,7 +50,7 @@ fn compose(send: Rc) -> Element { button { onclick: move |_| { - send(user_input.get().clone()); + send(user_input.cloned()); dioxus_desktop::window().close(); }, "Click to send" diff --git a/examples/control_focus.rs b/examples/control_focus.rs index 28b411165..9129018f6 100644 --- a/examples/control_focus.rs +++ b/examples/control_focus.rs @@ -12,7 +12,7 @@ fn app() -> Element { use_future(move || async move { let mut focused = 0; - if *running() { + if running() { loop { tokio::time::sleep(std::time::Duration::from_millis(10)).await; if let Some(element) = elements.with(|f| f.get(focused).cloned()) { diff --git a/examples/disabled.rs b/examples/disabled.rs index dd3f91597..5e6e7ba2a 100644 --- a/examples/disabled.rs +++ b/examples/disabled.rs @@ -11,7 +11,7 @@ fn app() -> Element { div { button { onclick: move |_| disabled.toggle(), "click to " - if *disabled() { "enable" } else { "disable" } + if disabled() { "enable" } else { "disable" } " the lower button" } diff --git a/examples/dog_app.rs b/examples/dog_app.rs index fa616692b..fd08b59b6 100644 --- a/examples/dog_app.rs +++ b/examples/dog_app.rs @@ -33,7 +33,9 @@ fn app() -> Element { Some(resp) => rsx! { h1 { "Select a dog breed!" } div { height: "500px", display: "flex", - ul { flex: "50%", {breed_list} } + ul { flex: "50%", {breed_list.value().cloned().unwrap_or_else(|| rsx! { + "loading breeds..." + })} } div { flex: "50%", BreedPic { breed } } } }, diff --git a/examples/heavy_compute.rs b/examples/heavy_compute.rs deleted file mode 100644 index 7ea2b0650..000000000 --- a/examples/heavy_compute.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! This example shows that you can place heavy work on the main thread, and then -//! -//! You *should* be using `tokio::spawn_blocking` instead. -//! -//! Your app runs in an async runtime (Tokio), so you should avoid blocking -//! the rendering of the VirtualDom. -//! -//! - -use dioxus::prelude::*; - -fn main() { - dioxus_desktop::launch(app); -} - -fn app() -> Element { - // This is discouraged - std::thread::sleep(std::time::Duration::from_millis(2_000)); - - // This is suggested - tokio::task::spawn_blocking(move || { - std::thread::sleep(std::time::Duration::from_millis(2_000)); - }); - - rsx! { - div { "Hello, world!" } - } -} diff --git a/examples/login_form.rs b/examples/login_form.rs index 5fec39760..5c778ee81 100644 --- a/examples/login_form.rs +++ b/examples/login_form.rs @@ -31,7 +31,7 @@ fn app() -> Element { rsx! { h1 { "Login" } - form { onsubmit: onsubmit, + form { onsubmit, input { r#type: "text", id: "username", name: "username" } label { "Username" } br {} diff --git a/examples/read_size.rs b/examples/read_size.rs index 16eda6c13..752d0fdaf 100644 --- a/examples/read_size.rs +++ b/examples/read_size.rs @@ -45,7 +45,7 @@ fn app() -> Element { height: "50%", background_color: "red", onmounted: move |cx| div_element.set(Some(cx.inner().clone())), - "This element is {*dimensions():?}" + "This element is {dimensions():?}" } button { diff --git a/examples/scroll_to_top.rs b/examples/scroll_to_top.rs index cc13fca85..f45bc0101 100644 --- a/examples/scroll_to_top.rs +++ b/examples/scroll_to_top.rs @@ -20,7 +20,7 @@ fn app() -> Element { button { onclick: move |_| async move { - if let Some(header) = header_element.read().as_ref().cloned() { + if let Some(header) = header_element.cloned() { let _ = header.scroll_to(ScrollBehavior::Smooth).await; } }, diff --git a/examples/signals.rs b/examples/signals.rs index 1235f3651..a595fca7a 100644 --- a/examples/signals.rs +++ b/examples/signals.rs @@ -14,7 +14,7 @@ fn app() -> Element { // Signals are backed by a runtime that is designed to deeply integrate with Dioxus apps use_future(|| async move { loop { - if running.value() { + if running.cloned() { count += 1; } tokio::time::sleep(Duration::from_millis(400)).await; @@ -26,11 +26,11 @@ fn app() -> Element { button { onclick: move |_| count += 1, "Up high!" } button { onclick: move |_| count -= 1, "Down low!" } button { onclick: move |_| running.toggle(), "Toggle counter" } - button { onclick: move |_| saved_values.push(count.value().to_string()), "Save this value" } + button { onclick: move |_| saved_values.push(count.cloned().to_string()), "Save this value" } button { onclick: move |_| saved_values.write().clear(), "Clear saved values" } // We can do boolean operations on the current signal value - if count.value() > 5 { + if count() > 5 { h2 { "High five!" } } diff --git a/examples/spread.rs b/examples/spread.rs index ed204d54b..25a4c7ad7 100644 --- a/examples/spread.rs +++ b/examples/spread.rs @@ -1,8 +1,7 @@ -use dioxus::{dioxus_core::NoOpMutations, prelude::*}; +use dioxus::prelude::*; fn main() { - let mut dom = VirtualDom::new(app); - let _ = dom.rebuild(&mut NoOpMutations); + let mut dom = VirtualDom::prebuilt(app); let html = dioxus_ssr::render(&dom); println!("{}", html); diff --git a/examples/ssr.rs b/examples/ssr.rs index 38dc3b1c1..c356222b3 100644 --- a/examples/ssr.rs +++ b/examples/ssr.rs @@ -2,12 +2,11 @@ //! //! This example shows how we can render the Dioxus Virtualdom using SSR. -use dioxus::{core::NoOpMutations, prelude::*}; +use dioxus::prelude::*; fn main() { // We can render VirtualDoms - let mut vdom = VirtualDom::new(app); - let _ = vdom.rebuild(&mut NoOpMutations); + let mut vdom = VirtualDom::prebuilt(app); println!("{}", dioxus_ssr::render(&vdom)); // Or we can render rsx! calls themselves diff --git a/examples/svg.rs b/examples/svg.rs index 4297bee61..bfafac889 100644 --- a/examples/svg.rs +++ b/examples/svg.rs @@ -31,7 +31,7 @@ fn Dice() -> Element { ]; let value = use_signal(|| 5); - let active_dots = use_selector(move || &DOTS_FOR_VALUE[(*value() - 1) as usize]); + let active_dots = use_selector(move || &DOTS_FOR_VALUE[(value() - 1) as usize]); rsx! { svg { diff --git a/examples/todomvc.rs b/examples/todomvc.rs index 7d34d6286..4d61d23d0 100644 --- a/examples/todomvc.rs +++ b/examples/todomvc.rs @@ -26,12 +26,13 @@ pub fn app() -> Element { let filter = use_signal(|| FilterState::All); let active_todo_count = - use_selector(move || todos().values().filter(|item| !item.checked).count()); + use_selector(move || todos.read().values().filter(|item| !item.checked).count()); let filtered_todos = use_selector(move || { - let mut filtered_todos = todos() + let mut filtered_todos = todos + .read() .iter() - .filter(|(_, item)| match *filter() { + .filter(|(_, item)| match filter() { FilterState::All => true, FilterState::Active => !item.checked, FilterState::Completed => item.checked, @@ -49,7 +50,7 @@ pub fn app() -> Element { style { {include_str!("./assets/todomvc.css")} } TodoHeader { todos } section { class: "main", - if !todos().is_empty() { + if !todos.read().is_empty() { input { id: "toggle-all", class: "toggle-all", @@ -69,7 +70,7 @@ pub fn app() -> Element { TodoEntry { key: "{id}", id, todos } } } - if !todos().is_empty() { + if !todos.read().is_empty() { ListFooter { active_todo_count, todos, filter } } } @@ -84,8 +85,8 @@ pub fn TodoHeader(todos: Signal>) -> Element { let mut todo_id = use_signal(|| 0); let onkeydown = move |evt: KeyboardEvent| { - if evt.key() == Key::Enter && !draft().is_empty() { - let id = *todo_id(); + if evt.key() == Key::Enter && !draft.read().is_empty() { + let id = todo_id(); let todo = TodoItem { id, checked: false, @@ -115,11 +116,11 @@ pub fn TodoHeader(todos: Signal>) -> Element { #[component] pub fn TodoEntry(todos: Signal>, id: u32) -> Element { let is_editing = use_signal(|| false); - let checked = use_selector(move || todos().get(&id).unwrap().checked); - let contents = use_selector(move || todos().get(&id).unwrap().contents.clone()); + let checked = use_selector(move || todos.read().get(&id).unwrap().checked); + let contents = use_selector(move || todos.read().get(&id).unwrap().contents.clone()); rsx! { - li { class: if *checked() { "completed" }, class: if *is_editing() { "editing"}, + li { class: if checked() { "completed" }, class: if is_editing() { "editing"}, div { class: "view", input { class: "toggle", @@ -140,7 +141,7 @@ pub fn TodoEntry(todos: Signal>, id: u32) -> Element { prevent_default: "onclick" } } - if *is_editing() { + if is_editing() { input { class: "edit", value: "{contents}", @@ -165,7 +166,7 @@ pub fn ListFooter( active_todo_count: ReadOnlySignal, filter: Signal, ) -> Element { - let show_clear_completed = use_selector(move || todos().values().any(|todo| todo.checked)); + let show_clear_completed = use_selector(move || todos.read().values().any(|todo| todo.checked)); rsx! { footer { class: "footer", @@ -188,7 +189,7 @@ pub fn ListFooter( li { a { href: url, - class: if *filter() == state { "selected" }, + class: if filter() == state { "selected" }, onclick: move |_| filter.set(state), prevent_default: "onclick", {state_text} diff --git a/examples/window_event.rs b/examples/window_event.rs index 126d5fa8a..6d6f790b7 100644 --- a/examples/window_event.rs +++ b/examples/window_event.rs @@ -34,8 +34,8 @@ fn app() -> Element { class: "inline-flex items-center bg-gray-800 border-0 py-1 px-3 focus:outline-none hover:bg-gray-700 rounded text-base mt-4 md:mt-0", onmousedown: |evt| evt.stop_propagation(), onclick: move |_| { - window().set_fullscreen(!*fullscreen()); - window().set_resizable(*fullscreen()); + window().set_fullscreen(!fullscreen()); + window().set_resizable(fullscreen()); fullscreen.toggle(); }, "Fullscreen" @@ -58,7 +58,7 @@ fn app() -> Element { class: "inline-flex items-center text-white bg-green-500 border-0 py-1 px-3 hover:bg-green-700 rounded", onmousedown: |evt| evt.stop_propagation(), onclick: move |_| { - window().set_always_on_top(!*always_on_top()); + window().set_always_on_top(!always_on_top()); always_on_top.toggle(); }, "Always On Top" @@ -69,7 +69,7 @@ fn app() -> Element { class: "inline-flex items-center text-white bg-blue-500 border-0 py-1 px-3 hover:bg-green-700 rounded", onmousedown: |evt| evt.stop_propagation(), onclick: move |_| { - window().set_decorations(!*decorations()); + window().set_decorations(!decorations()); decorations.toggle(); }, "Set Decorations" diff --git a/examples/window_focus.rs b/examples/window_focus.rs index 93a373da9..a6f7120cd 100644 --- a/examples/window_focus.rs +++ b/examples/window_focus.rs @@ -28,7 +28,7 @@ fn app() -> Element { display: "flex", flex_direction: "column", align_items: "center", - if *focused() { + if focused() { "This window is focused!" } else { "This window is not focused!" diff --git a/packages/signals/examples/dependancies.rs b/packages/signals/examples/dependancies.rs index 35182e416..fcd913781 100644 --- a/packages/signals/examples/dependancies.rs +++ b/packages/signals/examples/dependancies.rs @@ -19,7 +19,7 @@ fn app() -> Element { let local_state = use_signal(|| 0); let computed = use_selector_with_dependencies((local_state.get(),), move |(local_state,)| { - local_state * 2 + signal.value() + local_state * 2 + signal.cloned() }); println!("Running app"); diff --git a/packages/signals/src/signal.rs b/packages/signals/src/signal.rs index 8e3b70469..18444c2b4 100644 --- a/packages/signals/src/signal.rs +++ b/packages/signals/src/signal.rs @@ -330,7 +330,7 @@ impl Signal { /// Get the current value of the signal. This will subscribe the current scope to the signal. /// If the signal has been dropped, this will panic. #[track_caller] - pub fn value(&self) -> T { + pub fn cloned(&self) -> T { self.read().clone() } } @@ -338,7 +338,7 @@ impl Signal { impl Signal { /// Invert the boolean value of the signal. This will trigger an update on all subscribers. pub fn toggle(&self) { - self.set(!self.value()); + self.set(!self.cloned()); } } @@ -348,8 +348,8 @@ impl PartialEq for Signal { } } -impl Deref for Signal { - type Target = dyn Fn() -> GenerationalRef; +impl Deref for Signal { + type Target = dyn Fn() -> T; fn deref(&self) -> &Self::Target { // https://github.com/dtolnay/case-studies/tree/master/callable-types @@ -357,7 +357,10 @@ impl Deref for Signal { // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit). let uninit_callable = MaybeUninit::::uninit(); // Then move that value into the closure. We assume that the closure now has a in memory layout of Self. - let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }); + let uninit_closure = move || { + let res = Self::read(unsafe { &*uninit_callable.as_ptr() }); + res.clone() + }; // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure. let size_of_closure = std::mem::size_of_val(&uninit_closure); @@ -483,8 +486,8 @@ impl PartialEq for ReadOnlySignal { } } -impl Deref for ReadOnlySignal { - type Target = dyn Fn() -> GenerationalRef; +impl Deref for ReadOnlySignal { + type Target = dyn Fn() -> T; fn deref(&self) -> &Self::Target { // https://github.com/dtolnay/case-studies/tree/master/callable-types @@ -492,7 +495,7 @@ impl Deref for ReadOnlySignal { // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit). let uninit_callable = MaybeUninit::::uninit(); // Then move that value into the closure. We assume that the closure now has a in memory layout of Self. - let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }); + let uninit_closure = move || Self::read(unsafe { &*uninit_callable.as_ptr() }).clone(); // Check that the size of the closure is the same as the size of Self in case the compiler changed the layout of the closure. let size_of_closure = std::mem::size_of_val(&uninit_closure); diff --git a/packages/signals/tests/selector.rs b/packages/signals/tests/selector.rs index e798ec2dd..1b4d6b45c 100644 --- a/packages/signals/tests/selector.rs +++ b/packages/signals/tests/selector.rs @@ -29,7 +29,7 @@ fn memos_rerun() { selector(move || { counter.borrow_mut().effect += 1; println!("Signal: {:?}", signal); - signal.value() + signal.cloned() }) }); assert_eq!(memo.value(), 0);