Преглед изворни кода

and mut bound to mut methods on signals

Jonathan Kelley пре 1 година
родитељ
комит
8559984e9d

+ 2 - 2
examples/all_events.rs

@@ -41,9 +41,9 @@ const RECT_STYLE: &str = r#"
     "#;
 
 fn app() -> Element {
-    let events = use_signal(std::collections::VecDeque::new);
+    let mut events = use_signal(std::collections::VecDeque::new);
 
-    let log_event = move |event: Event| {
+    let mut log_event = move |event: Event| {
         let mut events = events.write();
 
         if events.len() >= MAX_EVENTS {

+ 9 - 9
examples/calculator.rs

@@ -19,9 +19,9 @@ fn main() {
 }
 
 fn app() -> Element {
-    let val = use_signal(|| String::from("0"));
+    let mut val = use_signal(|| String::from("0"));
 
-    let input_digit = move |num: u8| {
+    let mut input_digit = move |num: u8| {
         if val.cloned() == "0" {
             val.set(String::new());
         }
@@ -29,11 +29,11 @@ fn app() -> Element {
         val.write().push_str(num.to_string().as_str());
     };
 
-    let input_operator = move |key: &str| val.write().push_str(key);
+    let mut input_operator = move |key: &str| val.write().push_str(key);
 
-    let handle_key_down_event = move |evt: KeyboardEvent| match evt.key() {
+    let mut handle_key_down_event = move |evt: KeyboardEvent| match evt.key() {
         Key::Backspace => {
-            if !val().is_empty() {
+            if !val.cloned().is_empty() {
                 val.write().pop();
             }
         }
@@ -72,16 +72,16 @@ fn app() -> Element {
                                     class: "calculator-key key-clear",
                                     onclick: move |_| {
                                         val.set(String::new());
-                                        if !val().is_empty(){
+                                        if !val.cloned().is_empty(){
                                             val.set("0".into());
                                         }
                                     },
-                                    if val().is_empty() { "C" } else { "AC" }
+                                    if val.cloned().is_empty() { "C" } else { "AC" }
                                 }
                                 button {
                                     class: "calculator-key key-sign",
                                     onclick: move |_| {
-                                        let temp = calc_val(val().as_str());
+                                        let temp = calc_val(val.cloned().as_str());
                                         if temp > 0.0 {
                                             val.set(format!("-{temp}"));
                                         } else {
@@ -120,7 +120,7 @@ fn app() -> Element {
                             button { class: "calculator-key key-add", onclick: move |_| input_operator("+"), "+" }
                             button {
                                 class: "calculator-key key-equals",
-                                onclick: move |_| val.set(format!("{}", calc_val(val().as_str()))),
+                                onclick: move |_| val.set(format!("{}", calc_val(val.cloned().as_str()))),
                                 "="
                             }
                         }

+ 2 - 2
examples/compose.rs

@@ -10,7 +10,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let emails_sent = use_signal(|| Vec::new() as Vec<String>);
+    let mut emails_sent = use_signal(|| Vec::new() as Vec<String>);
 
     // Wait for responses to the compose channel, and then push them to the emails_sent signal.
     let handle = use_coroutine(|mut rx: UnboundedReceiver<String>| async move {
@@ -42,7 +42,7 @@ fn app() -> Element {
 }
 
 fn compose(send: Rc<dyn Fn(String)>) -> Element {
-    let user_input = use_signal(String::new);
+    let mut user_input = use_signal(String::new);
 
     rsx! {
         div {

+ 2 - 2
examples/control_focus.rs

@@ -7,8 +7,8 @@ fn main() {
 }
 
 fn app() -> Element {
-    let elements = use_signal(Vec::<Rc<MountedData>>::new);
-    let running = use_signal(|| true);
+    let mut elements = use_signal(Vec::<Rc<MountedData>>::new);
+    let mut running = use_signal(|| true);
 
     use_future(move || async move {
         let mut focused = 0;

+ 2 - 2
examples/counter.rs

@@ -8,8 +8,8 @@ fn main() {
 }
 
 fn app() -> Element {
-    let counters = use_signal(|| vec![0, 0, 0]);
-    let sum = use_selector(move || counters.read().iter().copied().sum::<usize>());
+    let mut counters = use_signal(|| vec![0, 0, 0]);
+    let mut sum = use_selector(move || counters.read().iter().copied().sum::<usize>());
 
     render! {
         div {

+ 4 - 4
examples/crm.rs

@@ -58,7 +58,7 @@ pub struct Client {
 
 #[component]
 fn ClientList() -> Element {
-    let clients = use_context::<Clients>();
+    let mut clients = use_context::<Clients>();
 
     rsx! {
         h2 { "List of Clients" }
@@ -75,9 +75,9 @@ fn ClientList() -> Element {
 
 #[component]
 fn ClientAdd() -> Element {
-    let first_name = use_signal(String::new);
-    let last_name = use_signal(String::new);
-    let description = use_signal(String::new);
+    let mut first_name = use_signal(String::new);
+    let mut last_name = use_signal(String::new);
+    let mut description = use_signal(String::new);
 
     let submit_client = move |_: FormEvent| {
         consume_context::<Clients>().write().push(Client {

+ 1 - 1
examples/disabled.rs

@@ -5,7 +5,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let disabled = use_signal(|| false);
+    let mut disabled = use_signal(|| false);
 
     rsx! {
         div {

+ 2 - 2
examples/dog_app.rs

@@ -6,8 +6,8 @@ fn main() {
 }
 
 fn app() -> Element {
-    let breed = use_signal(|| "deerhound".to_string());
-    let breed_list = use_future(|| async move {
+    let mut breed = use_signal(|| "deerhound".to_string());
+    let mut breed_list = use_future(|| async move {
         let list = reqwest::get("https://dog.ceo/api/breeds/list/all")
             .await
             .unwrap()

+ 1 - 1
examples/file_explorer.rs

@@ -20,7 +20,7 @@ fn main() {
 const _STYLE: &str = manganis::mg!(file("./examples/assets/fileexplorer.css"));
 
 fn app() -> Element {
-    let files = use_signal(Files::new);
+    let mut files = use_signal(Files::new);
 
     rsx! {
         div {

+ 2 - 2
examples/file_upload.rs

@@ -8,8 +8,8 @@ fn main() {
 }
 
 fn App() -> Element {
-    let enable_directory_upload = use_signal(|| false);
-    let files_uploaded = use_signal(|| Vec::new() as Vec<String>);
+    let mut enable_directory_upload = use_signal(|| false);
+    let mut files_uploaded = use_signal(|| Vec::new() as Vec<String>);
 
     let upload_files = move |evt: FormEvent| async move {
         for file_name in evt.files().unwrap().files() {

+ 1 - 1
examples/pattern_model.rs

@@ -38,7 +38,7 @@ fn main() {
 const STYLE: &str = include_str!("./assets/calculator.css");
 
 fn app() -> Element {
-    let state = use_signal(Calculator::new);
+    let mut state = use_signal(Calculator::new);
 
     rsx! {
         style { {STYLE} }

+ 1 - 1
examples/pattern_reducer.rs

@@ -12,7 +12,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let state = use_signal(|| PlayerState { is_playing: false });
+    let mut state = use_signal(|| PlayerState { is_playing: false });
 
     rsx!(
         div {

+ 3 - 3
examples/read_size.rs

@@ -26,10 +26,10 @@ fn main() {
 }
 
 fn app() -> Element {
-    let div_element = use_signal(|| None as Option<Rc<MountedData>>);
-    let dimensions = use_signal(Rect::zero);
+    let mut div_element = use_signal(|| None as Option<Rc<MountedData>>);
+    let mut dimensions = use_signal(Rect::zero);
 
-    let read_dims = move |_| async move {
+    let mut read_dims = move |_| async move {
         let read = div_element.read();
         let client_rect = read.as_ref().map(|el| el.get_client_rect());
         if let Some(client_rect) = client_rect {

+ 1 - 1
examples/scroll_to_top.rs

@@ -5,7 +5,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let header_element = use_signal(|| None);
+    let mut header_element = use_signal(|| None);
 
     rsx! {
         div {

+ 1 - 1
examples/shortcut.rs

@@ -6,7 +6,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let toggled = use_signal(|| false);
+    let mut toggled = use_signal(|| false);
 
     _ = use_global_shortcut("ctrl+s", move || toggled.toggle());
 

+ 3 - 3
examples/signals.rs

@@ -6,9 +6,9 @@ fn main() {
 }
 
 fn app() -> Element {
-    let running = dioxus_signals::use_signal(|| true);
-    let mut count = dioxus_signals::use_signal(|| 0);
-    let saved_values = dioxus_signals::use_signal(|| vec![0.to_string()]);
+    let mut running = use_signal(|| true);
+    let mut count = use_signal(|| 0);
+    let mut saved_values = use_signal(|| vec![0.to_string()]);
 
     // Signals can be used in async functions without an explicit clone since they're 'static and Copy
     // Signals are backed by a runtime that is designed to deeply integrate with Dioxus apps

+ 1 - 1
examples/streams.rs

@@ -8,7 +8,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let count = use_signal(|| 10);
+    let mut count = use_signal(|| 10);
 
     use_future(|| async move {
         let mut stream = some_stream();

+ 1 - 1
examples/svg.rs

@@ -30,7 +30,7 @@ fn Dice() -> Element {
         [Y, Y, Y, Y, Y, Y, N],
     ];
 
-    let value = use_signal(|| 5);
+    let mut value = use_signal(|| 5);
     let active_dots = use_selector(move || &DOTS_FOR_VALUE[(value() - 1) as usize]);
 
     rsx! {

+ 1 - 3
examples/textarea.rs

@@ -7,9 +7,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let model = use_signal(|| String::from("asd"));
-
-    println!("{model}");
+    let mut model = use_signal(|| String::from("asd"));
 
     rsx! {
         textarea {

+ 13 - 9
examples/todomvc.rs

@@ -22,8 +22,8 @@ pub struct TodoItem {
 }
 
 pub fn app() -> Element {
-    let todos = use_signal(|| HashMap::<u32, TodoItem>::new());
-    let filter = use_signal(|| FilterState::All);
+    let mut todos = use_signal(|| HashMap::<u32, TodoItem>::new());
+    let mut filter = use_signal(|| FilterState::All);
 
     let active_todo_count =
         use_selector(move || todos.read().values().filter(|item| !item.checked).count());
@@ -56,17 +56,17 @@ pub fn app() -> Element {
                         class: "toggle-all",
                         r#type: "checkbox",
                         onchange: move |_| {
-                            let check = *active_todo_count() != 0;
+                            let check = active_todo_count() != 0;
                             for (_, item) in todos.write().iter_mut() {
                                 item.checked = check;
                             }
                         },
-                        checked: *active_todo_count() == 0,
+                        checked: active_todo_count() == 0,
                     }
                     label { r#for: "toggle-all" }
                 }
                 ul { class: "todo-list",
-                    for id in filtered_todos().iter().copied() {
+                    for id in filtered_todos.read().iter().copied() {
                         TodoEntry { key: "{id}", id, todos }
                     }
                 }
@@ -81,7 +81,8 @@ pub fn app() -> Element {
 
 #[component]
 pub fn TodoHeader(todos: Signal<HashMap<u32, TodoItem>>) -> Element {
-    let draft = use_signal(|| "".to_string());
+    let mut todos = todos;
+    let mut draft = use_signal(|| "".to_string());
     let mut todo_id = use_signal(|| 0);
 
     let onkeydown = move |evt: KeyboardEvent| {
@@ -115,7 +116,8 @@ pub fn TodoHeader(todos: Signal<HashMap<u32, TodoItem>>) -> Element {
 
 #[component]
 pub fn TodoEntry(todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
-    let is_editing = use_signal(|| false);
+    let mut todos = todos;
+    let mut is_editing = use_signal(|| false);
     let checked = use_selector(move || todos.read().get(&id).unwrap().checked);
     let contents = use_selector(move || todos.read().get(&id).unwrap().contents.clone());
 
@@ -166,6 +168,8 @@ pub fn ListFooter(
     active_todo_count: ReadOnlySignal<usize>,
     filter: Signal<FilterState>,
 ) -> Element {
+    let mut todos = todos;
+    let mut filter = filter;
     let show_clear_completed = use_selector(move || todos.read().values().any(|todo| todo.checked));
 
     rsx! {
@@ -173,7 +177,7 @@ pub fn ListFooter(
             span { class: "todo-count",
                 strong { "{active_todo_count} " }
                 span {
-                    match *active_todo_count() {
+                    match active_todo_count() {
                         1 => "item",
                         _ => "items",
                     }
@@ -197,7 +201,7 @@ pub fn ListFooter(
                     }
                 }
             }
-            if *show_clear_completed() {
+            if show_clear_completed() {
                 button {
                     class: "clear-completed",
                     onclick: move |_| todos.write().retain(|_, todo| !todo.checked),

+ 3 - 3
examples/window_event.rs

@@ -12,9 +12,9 @@ fn main() {
 }
 
 fn app() -> Element {
-    let fullscreen = use_signal(|| false);
-    let always_on_top = use_signal(|| false);
-    let decorations = use_signal(|| false);
+    let mut fullscreen = use_signal(|| false);
+    let mut always_on_top = use_signal(|| false);
+    let mut decorations = use_signal(|| false);
 
     rsx!(
         link { href:"https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", rel:"stylesheet" }

+ 1 - 1
examples/window_focus.rs

@@ -11,7 +11,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let focused = use_signal(|| false);
+    let mut focused = use_signal(|| false);
 
     use_wry_event_handler(move |event, _| match event {
         WryEvent::WindowEvent {

+ 1 - 1
examples/window_zoom.rs

@@ -5,7 +5,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let level = use_signal(|| 1.0);
+    let mut level = use_signal(|| 1.0);
 
     rsx! {
         input {

+ 1 - 1
examples/xss_safety.rs

@@ -9,7 +9,7 @@ fn main() {
 }
 
 fn app() -> Element {
-    let contents = use_signal(|| String::from("<script>alert(\"hello world\")</script>"));
+    let mut contents = use_signal(|| String::from("<script>alert(\"hello world\")</script>"));
 
     rsx! {
         div {

+ 14 - 11
packages/generational-box/src/lib.rs

@@ -477,13 +477,13 @@ impl Display for AlreadyBorrowedError {
 impl std::error::Error for AlreadyBorrowedError {}
 
 /// A reference to a value in a generational box.
-pub struct GenerationalRef<T: 'static> {
-    inner: Ref<'static, T>,
+pub struct GenerationalRef<'a, T: 'static> {
+    inner: Ref<'a, T>,
     #[cfg(any(debug_assertions, feature = "debug_borrows"))]
     borrow: GenerationalRefBorrowInfo,
 }
 
-impl<T: 'static> GenerationalRef<T> {
+impl<'a, T: 'static> GenerationalRef<'a, T> {
     /// Map one ref type to another.
     pub fn map<U, F>(orig: GenerationalRef<T>, f: F) -> GenerationalRef<U>
     where
@@ -500,7 +500,7 @@ impl<T: 'static> GenerationalRef<T> {
     }
 
     /// Filter one ref type to another.
-    pub fn filter_map<U, F>(orig: GenerationalRef<T>, f: F) -> Option<GenerationalRef<U>>
+    pub fn filter_map<U, F>(orig: GenerationalRef<'a, T>, f: F) -> Option<GenerationalRef<'a, U>>
     where
         F: FnOnce(&T) -> Option<&U>,
     {
@@ -520,7 +520,7 @@ impl<T: 'static> GenerationalRef<T> {
     }
 }
 
-impl<T: 'static> Deref for GenerationalRef<T> {
+impl<T: 'static> Deref for GenerationalRef<'_, T> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -545,13 +545,13 @@ impl Drop for GenerationalRefBorrowInfo {
 }
 
 /// A mutable reference to a value in a generational box.
-pub struct GenerationalRefMut<T: 'static> {
-    inner: RefMut<'static, T>,
+pub struct GenerationalRefMut<'a, T: 'static> {
+    inner: RefMut<'a, T>,
     #[cfg(any(debug_assertions, feature = "debug_borrows"))]
     borrow: GenerationalRefMutBorrowInfo,
 }
 
-impl<T: 'static> GenerationalRefMut<T> {
+impl<'a, T: 'static> GenerationalRefMut<'a, T> {
     /// Map one ref type to another.
     pub fn map<U, F>(orig: GenerationalRefMut<T>, f: F) -> GenerationalRefMut<U>
     where
@@ -565,7 +565,10 @@ impl<T: 'static> GenerationalRefMut<T> {
     }
 
     /// Filter one ref type to another.
-    pub fn filter_map<U, F>(orig: GenerationalRefMut<T>, f: F) -> Option<GenerationalRefMut<U>>
+    pub fn filter_map<U, F>(
+        orig: GenerationalRefMut<'a, T>,
+        f: F,
+    ) -> Option<GenerationalRefMut<'a, U>>
     where
         F: FnOnce(&mut T) -> Option<&mut U>,
     {
@@ -584,7 +587,7 @@ impl<T: 'static> GenerationalRefMut<T> {
     }
 }
 
-impl<T: 'static> Deref for GenerationalRefMut<T> {
+impl<'a, T: 'static> Deref for GenerationalRefMut<'a, T> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -592,7 +595,7 @@ impl<T: 'static> Deref for GenerationalRefMut<T> {
     }
 }
 
-impl<T: 'static> DerefMut for GenerationalRefMut<T> {
+impl<'a, T: 'static> DerefMut for GenerationalRefMut<'a, T> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         self.inner.deref_mut()
     }

+ 1 - 1
packages/hooks/src/use_coroutine.rs

@@ -125,7 +125,7 @@ impl<T> Coroutine<T> {
     /// Restart this coroutine
     ///
     /// Forces the component to re-render, which will re-invoke the coroutine.
-    pub fn restart(&self) {
+    pub fn restart(&mut self) {
         self.needs_regen.set(true);
         self.task().stop();
     }

+ 3 - 3
packages/hooks/src/use_future.rs

@@ -25,8 +25,8 @@ where
     T: 'static,
     F: Future<Output = T> + 'static,
 {
-    let value = use_signal(|| None);
-    let state = use_signal(|| UseFutureState::Pending);
+    let mut value = use_signal(|| None);
+    let mut state = use_signal(|| UseFutureState::Pending);
 
     let task = use_signal(|| {
         // Create the user's task
@@ -84,7 +84,7 @@ impl<T> UseFuture<T> {
     }
 
     // Manually set the value in the future slot without starting the future over
-    pub fn set(&self, new_value: T) {
+    pub fn set(&mut self, new_value: T) {
         self.value.set(Some(new_value));
     }
 

+ 20 - 17
packages/signals/src/impls.rs

@@ -120,78 +120,81 @@ macro_rules! write_impls {
 
         impl<T: 'static> $ty<Vec<T>> {
             /// Pushes a new value to the end of the vector.
-            pub fn push(&self, value: T) {
+            pub fn push(&mut self, value: T) {
                 self.with_mut(|v| v.push(value))
             }
 
             /// Pops the last value from the vector.
-            pub fn pop(&self) -> Option<T> {
+            pub fn pop(&mut self) -> Option<T> {
                 self.with_mut(|v| v.pop())
             }
 
             /// Inserts a new value at the given index.
-            pub fn insert(&self, index: usize, value: T) {
+            pub fn insert(&mut self, index: usize, value: T) {
                 self.with_mut(|v| v.insert(index, value))
             }
 
             /// Removes the value at the given index.
-            pub fn remove(&self, index: usize) -> T {
+            pub fn remove(&mut self, index: usize) -> T {
                 self.with_mut(|v| v.remove(index))
             }
 
             /// Clears the vector, removing all values.
-            pub fn clear(&self) {
+            pub fn clear(&mut self) {
                 self.with_mut(|v| v.clear())
             }
 
             /// Extends the vector with the given iterator.
-            pub fn extend(&self, iter: impl IntoIterator<Item = T>) {
+            pub fn extend(&mut self, iter: impl IntoIterator<Item = T>) {
                 self.with_mut(|v| v.extend(iter))
             }
 
             /// Truncates the vector to the given length.
-            pub fn truncate(&self, len: usize) {
+            pub fn truncate(&mut self, len: usize) {
                 self.with_mut(|v| v.truncate(len))
             }
 
             /// Swaps two values in the vector.
-            pub fn swap_remove(&self, index: usize) -> T {
+            pub fn swap_remove(&mut self, index: usize) -> T {
                 self.with_mut(|v| v.swap_remove(index))
             }
 
             /// Retains only the values that match the given predicate.
-            pub fn retain(&self, f: impl FnMut(&T) -> bool) {
+            pub fn retain(&mut self, f: impl FnMut(&T) -> bool) {
                 self.with_mut(|v| v.retain(f))
             }
 
             /// Splits the vector into two at the given index.
-            pub fn split_off(&self, at: usize) -> Vec<T> {
+            pub fn split_off(&mut self, at: usize) -> Vec<T> {
                 self.with_mut(|v| v.split_off(at))
             }
         }
 
         impl<T: 'static> $ty<Option<T>> {
             /// Takes the value out of the Option.
-            pub fn take(&self) -> Option<T> {
+            pub fn take(&mut self) -> Option<T> {
                 self.with_mut(|v| v.take())
             }
 
             /// Replace the value in the Option.
-            pub fn replace(&self, value: T) -> Option<T> {
+            pub fn replace(&mut self, value: T) -> Option<T> {
                 self.with_mut(|v| v.replace(value))
             }
 
             /// Gets the value out of the Option, or inserts the given value if the Option is empty.
-            pub fn get_or_insert(&self, default: T) -> GenerationalRef<T> {
+            pub fn get_or_insert(&mut self, default: T) -> GenerationalRef<T> {
                 self.get_or_insert_with(|| default)
             }
 
             /// Gets the value out of the Option, or inserts the value returned by the given function if the Option is empty.
-            pub fn get_or_insert_with(&self, default: impl FnOnce() -> T) -> GenerationalRef<T> {
+            pub fn get_or_insert_with(
+                &mut self,
+                default: impl FnOnce() -> T,
+            ) -> GenerationalRef<T> {
                 let borrow = self.read();
                 if borrow.is_none() {
                     drop(borrow);
-                    self.with_mut(|v| *v = Some(default()));
+                    self.write_unchecked().replace(default());
                     GenerationalRef::map(self.read(), |v| v.as_ref().unwrap())
                 } else {
                     GenerationalRef::map(borrow, |v| v.as_ref().unwrap())
@@ -281,14 +284,14 @@ impl<T: Clone + 'static> IntoIterator for Signal<Vec<T>> {
 
 impl<T: 'static> Signal<Vec<T>> {
     /// Returns a reference to an element or `None` if out of bounds.
-    pub fn get_mut(&self, index: usize) -> Option<Write<T, Vec<T>>> {
+    pub fn get_mut(&mut self, index: usize) -> Option<Write<T, Vec<T>>> {
         Write::filter_map(self.write(), |v| v.get_mut(index))
     }
 }
 
 impl<T: 'static> Signal<Option<T>> {
     /// Returns a reference to an element or `None` if out of bounds.
-    pub fn as_mut(&self) -> Option<Write<T, Option<T>>> {
+    pub fn as_mut(&mut self) -> Option<Write<T, Option<T>>> {
         Write::filter_map(self.write(), |v| v.as_mut())
     }
 }

+ 7 - 3
packages/signals/src/rt.rs

@@ -151,6 +151,10 @@ impl<T: 'static> CopyValue<T> {
         self.value.try_write()
     }
 
+    pub fn write_unchecked(&self) -> GenerationalRefMut<T> {
+        self.value.write()
+    }
+
     /// Write the value. If the value has been dropped, this will panic.
     #[track_caller]
     pub fn write(&self) -> GenerationalRefMut<T> {
@@ -188,8 +192,8 @@ impl<T: 'static> PartialEq for CopyValue<T> {
     }
 }
 
-impl<T> Deref for CopyValue<T> {
-    type Target = dyn Fn() -> GenerationalRef<T>;
+impl<T: 'static + Clone> Deref for CopyValue<T> {
+    type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {
         // https://github.com/dtolnay/case-studies/tree/master/callable-types
@@ -197,7 +201,7 @@ impl<T> Deref for CopyValue<T> {
         // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
         let uninit_callable = MaybeUninit::<Self>::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);

+ 1 - 39
packages/signals/src/selector.rs

@@ -26,49 +26,11 @@ pub fn use_selector<R: PartialEq>(f: impl FnMut() -> R + 'static) -> ReadOnlySig
     use_hook(|| selector(f))
 }
 
-/// Creates a new Selector with some local dependencies. The selector will be run immediately and whenever any signal it reads or any dependencies it tracks changes
-///
-/// Selectors can be used to efficiently compute derived data from signals.
-///
-/// ```rust
-/// use dioxus::prelude::*;
-/// use dioxus_signals::*;
-///
-/// fn App() -> Element {
-///     let mut local_state = use_signal(|| 0);
-///     let double = use_selector_with_dependencies((local_state.get(),), move |(local_state,)| local_state * 2);
-///     local_state.set(1);
-///
-///     render! { "{double}" }
-/// }
-/// ```
-#[must_use = "Consider using `use_effect` to rerun a callback when dependencies change"]
-pub fn use_selector_with_dependencies<R: PartialEq, D: Dependency>(
-    dependencies: D,
-    mut f: impl FnMut(D::Out) -> R + 'static,
-) -> ReadOnlySignal<R>
-where
-    D::Out: 'static,
-{
-    let dependencies_signal = use_signal(|| dependencies.out());
-    let selector = use_hook(|| {
-        selector(move || {
-            let deref = &*dependencies_signal.read();
-            f(deref.clone())
-        })
-    });
-    let changed = { dependencies.changed(&*dependencies_signal.read()) };
-    if changed {
-        dependencies_signal.set(dependencies.out());
-    }
-    selector
-}
-
 /// Creates a new Selector. The selector will be run immediately and whenever any signal it reads changes.
 ///
 /// Selectors can be used to efficiently compute derived data from signals.
 pub fn selector<R: PartialEq>(mut f: impl FnMut() -> R + 'static) -> ReadOnlySignal<R> {
-    let state = Signal::<R> {
+    let mut state = Signal::<R> {
         inner: CopyValue::invalid(),
     };
     let effect = Effect {

+ 24 - 22
packages/signals/src/signal.rs

@@ -210,7 +210,7 @@ impl<T: 'static> Signal<T> {
     ///
     /// If the signal has been dropped, this will panic.
     #[track_caller]
-    pub fn read(&self) -> GenerationalRef<T> {
+    pub fn read<'a>(&'a self) -> GenerationalRef<'a, T> {
         let inner = self.inner.read();
         if let Some(effect) = inner.effect_stack.current() {
             let mut effect_subscribers = inner.effect_subscribers.borrow_mut();
@@ -245,11 +245,8 @@ impl<T: 'static> Signal<T> {
         GenerationalRef::map(inner, |v| &v.value)
     }
 
-    /// Get a mutable reference to the signal's value.
-    ///
-    /// If the signal has been dropped, this will panic.
-    #[track_caller]
-    pub fn write(&self) -> Write<T> {
+    /// Write to the value through an immutable reference.
+    pub fn write_unchecked(&self) -> Write<T> {
         let inner = self.inner.write();
         let borrow = GenerationalRefMut::map(inner, |v| &mut v.value);
         Write {
@@ -258,6 +255,14 @@ impl<T: 'static> Signal<T> {
         }
     }
 
+    /// Get a mutable reference to the signal's value.
+    ///
+    /// If the signal has been dropped, this will panic.
+    #[track_caller]
+    pub fn write<'a>(&'a mut self) -> Write<'a, T> {
+        self.write_unchecked()
+    }
+
     fn update_subscribers(&self) {
         {
             let inner = self.inner.read();
@@ -288,7 +293,7 @@ impl<T: 'static> Signal<T> {
 
     /// Set the value of the signal. This will trigger an update on all subscribers.
     #[track_caller]
-    pub fn set(&self, value: T) {
+    pub fn set(&mut self, value: T) {
         *self.write() = value;
     }
 
@@ -311,7 +316,7 @@ impl<T: 'static> Signal<T> {
     /// Run a closure with a mutable reference to the signal's value.
     /// If the signal has been dropped, this will panic.
     #[track_caller]
-    pub fn with_mut<O>(&self, f: impl FnOnce(&mut T) -> O) -> O {
+    pub fn with_mut<O>(&mut self, f: impl FnOnce(&mut T) -> O) -> O {
         let mut write = self.write();
         f(&mut *write)
     }
@@ -337,7 +342,7 @@ impl<T: Clone + 'static> Signal<T> {
 
 impl Signal<bool> {
     /// Invert the boolean value of the signal. This will trigger an update on all subscribers.
-    pub fn toggle(&self) {
+    pub fn toggle(&mut self) {
         self.set(!self.cloned());
     }
 }
@@ -351,7 +356,7 @@ impl<T: 'static> PartialEq for Signal<T> {
 /// Allow calling a signal with signal() syntax
 ///
 /// Currently only limited to copy types, though could probably specialize for string/arc/rc
-impl<T: Copy + Clone> Deref for Signal<T> {
+impl<T: Copy> Deref for Signal<T> {
     type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {
@@ -360,10 +365,7 @@ impl<T: Copy + Clone> Deref for Signal<T> {
         // First we create a closure that captures something with the Same in memory layout as Self (MaybeUninit<Self>).
         let uninit_callable = MaybeUninit::<Self>::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 || {
-            let res = Self::read(unsafe { &*uninit_callable.as_ptr() });
-            res.clone()
-        };
+        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);
@@ -398,14 +400,14 @@ impl<T: 'static> Drop for SignalSubscriberDrop<T> {
 }
 
 /// A mutable reference to a signal's value.
-pub struct Write<T: 'static, I: 'static = T> {
-    write: GenerationalRefMut<T>,
+pub struct Write<'a, T: 'static, I: 'static = T> {
+    write: GenerationalRefMut<'a, T>,
     signal: SignalSubscriberDrop<I>,
 }
 
-impl<T: 'static, I: 'static> Write<T, I> {
+impl<'a, T: 'static, I: 'static> Write<'a, T, I> {
     /// Map the mutable reference to the signal's value to a new type.
-    pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<O, I> {
+    pub fn map<O>(myself: Self, f: impl FnOnce(&mut T) -> &mut O) -> Write<'a, O, I> {
         let Self { write, signal } = myself;
         Write {
             write: GenerationalRefMut::map(write, f),
@@ -417,14 +419,14 @@ impl<T: 'static, I: 'static> Write<T, I> {
     pub fn filter_map<O>(
         myself: Self,
         f: impl FnOnce(&mut T) -> Option<&mut O>,
-    ) -> Option<Write<O, I>> {
+    ) -> Option<Write<'a, O, I>> {
         let Self { write, signal } = myself;
         let write = GenerationalRefMut::filter_map(write, f);
         write.map(|write| Write { write, signal })
     }
 }
 
-impl<T: 'static, I: 'static> Deref for Write<T, I> {
+impl<'a, T: 'static, I: 'static> Deref for Write<'a, T, I> {
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
@@ -432,7 +434,7 @@ impl<T: 'static, I: 'static> Deref for Write<T, I> {
     }
 }
 
-impl<T, I> DerefMut for Write<T, I> {
+impl<'a, T, I> DerefMut for Write<'a, T, I> {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.write
     }
@@ -489,7 +491,7 @@ impl<T: 'static> PartialEq for ReadOnlySignal<T> {
     }
 }
 
-impl<T: Copy + Clone> Deref for ReadOnlySignal<T> {
+impl<T: Copy> Deref for ReadOnlySignal<T> {
     type Target = dyn Fn() -> T;
 
     fn deref(&self) -> &Self::Target {