Fix issue with mutability in component macro

This commit is contained in:
Jonathan Kelley committed 2024-01-15 23:57:10 -08:00
1 parent 8559984e9d
commit 98bd78de43
5 files changed
+47 -22

No files matched your search

+5
View File
@@ -17,7 +17,12 @@ fn app() -> Element {
if running() { if running() {
count += 1; count += 1;
} }
let val = running.read();
tokio::time::sleep(Duration::from_millis(400)).await; tokio::time::sleep(Duration::from_millis(400)).await;
println!("Running: {}", *val);
} }
}); });
+4 -8
View File
@@ -80,8 +80,7 @@ pub fn app() -> Element {
} }
#[component] #[component]
pub fn TodoHeader(todos: Signal<HashMap<u32, TodoItem>>) -> Element { pub fn TodoHeader(mut todos: Signal<HashMap<u32, TodoItem>>) -> Element {
let mut todos = todos;
let mut draft = use_signal(|| "".to_string()); let mut draft = use_signal(|| "".to_string());
let mut todo_id = use_signal(|| 0); let mut todo_id = use_signal(|| 0);
@@ -115,8 +114,7 @@ pub fn TodoHeader(todos: Signal<HashMap<u32, TodoItem>>) -> Element {
} }
#[component] #[component]
pub fn TodoEntry(todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element { pub fn TodoEntry(mut todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
let mut todos = todos;
let mut is_editing = use_signal(|| false); let mut is_editing = use_signal(|| false);
let checked = use_selector(move || todos.read().get(&id).unwrap().checked); let checked = use_selector(move || todos.read().get(&id).unwrap().checked);
let contents = use_selector(move || todos.read().get(&id).unwrap().contents.clone()); let contents = use_selector(move || todos.read().get(&id).unwrap().contents.clone());
@@ -164,12 +162,10 @@ pub fn TodoEntry(todos: Signal<HashMap<u32, TodoItem>>, id: u32) -> Element {
#[component] #[component]
pub fn ListFooter( pub fn ListFooter(
todos: Signal<HashMap<u32, TodoItem>>, mut todos: Signal<HashMap<u32, TodoItem>>,
active_todo_count: ReadOnlySignal<usize>, active_todo_count: ReadOnlySignal<usize>,
filter: Signal<FilterState>, mut filter: Signal<FilterState>,
) -> Element { ) -> Element {
let mut todos = todos;
let mut filter = filter;
let show_clear_completed = use_selector(move || todos.read().values().any(|todo| todo.checked)); let show_clear_completed = use_selector(move || todos.read().values().any(|todo| todo.checked));
rsx! { rsx! {
@@ -46,12 +46,20 @@ fn get_props_struct(component_body: &ComponentBody) -> ItemStruct {
.. ..
} = sig; } = sig;
// Skip first arg since that's the context
let struct_fields = inputs.iter().map(move |f| { let struct_fields = inputs.iter().map(move |f| {
match f { match f {
FnArg::Receiver(_) => unreachable!(), // Unreachable because of ComponentBody parsing FnArg::Receiver(_) => unreachable!(), // Unreachable because of ComponentBody parsing
FnArg::Typed(pt) => { FnArg::Typed(pt) => {
let arg_pat = &pt.pat; // Pattern (identifier) let arg_pat = match pt.pat.as_ref() {
// rip off mutability
Pat::Ident(f) => {
let mut f = f.clone();
f.mutability = None;
quote! { #f }
}
a => quote! { #a },
};
let arg_colon = &pt.colon_token; let arg_colon = &pt.colon_token;
let arg_ty = &pt.ty; // Type let arg_ty = &pt.ty; // Type
let arg_attrs = &pt.attrs; // Attributes let arg_attrs = &pt.attrs; // Attributes
@@ -247,7 +255,21 @@ fn get_function(component_body: &ComponentBody) -> ItemFn {
// Skip first arg since that's the context // Skip first arg since that's the context
let struct_field_names = inputs.iter().filter_map(|f| match f { let struct_field_names = inputs.iter().filter_map(|f| match f {
FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters. FnArg::Receiver(_) => unreachable!(), // ComponentBody prohibits receiver parameters.
FnArg::Typed(pt) => Some(&pt.pat), FnArg::Typed(pt) => {
let pat = &pt.pat;
let mut pat = pat.clone();
// rip off mutability, but still write it out eventually
match pat.as_mut() {
Pat::Ident(ref mut pat_ident) => {
pat_ident.mutability = None;
}
_ => {}
}
Some(quote!(mut #pat))
}
}); });
let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() { let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
@@ -293,7 +315,7 @@ fn get_function(component_body: &ComponentBody) -> ItemFn {
parse_quote! { parse_quote! {
#(#fn_attrs)* #(#fn_attrs)*
#(#props_docs)* #(#props_docs)*
#asyncness #vis fn #fn_ident #fn_generics (__props: #struct_ident #generics_no_bounds) #fn_output #asyncness #vis fn #fn_ident #fn_generics (mut __props: #struct_ident #generics_no_bounds) #fn_output
#where_clause #where_clause
{ {
let #struct_ident { #(#struct_field_names),* } = __props; let #struct_ident { #(#struct_field_names),* } = __props;
@@ -57,7 +57,7 @@ pub struct HistoryButtonProps {
#[component] #[component]
pub fn GoBackButton( pub fn GoBackButton(
/// The props... /// The props...
props: HistoryButtonProps, mut props: HistoryButtonProps,
) -> Element { ) -> Element {
let HistoryButtonProps { children } = props; let HistoryButtonProps { children } = props;
@@ -127,7 +127,7 @@ pub fn GoBackButton(
#[component] #[component]
pub fn GoForwardButton( pub fn GoForwardButton(
/// Props... /// Props...
props: HistoryButtonProps, mut props: HistoryButtonProps,
) -> Element { ) -> Element {
let HistoryButtonProps { children } = props; let HistoryButtonProps { children } = props;
+10 -8
View File
@@ -245,7 +245,17 @@ impl<T: 'static> Signal<T> {
GenerationalRef::map(inner, |v| &v.value) 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<'a>(&'a mut self) -> Write<'a, T> {
self.write_unchecked()
}
/// Write to the value through an immutable reference. /// Write to the value through an immutable reference.
///
/// This is public since it's useful in many scenarios, but we generally recommend mutation through [`Self::write`] instead.
pub fn write_unchecked(&self) -> Write<T> { pub fn write_unchecked(&self) -> Write<T> {
let inner = self.inner.write(); let inner = self.inner.write();
let borrow = GenerationalRefMut::map(inner, |v| &mut v.value); let borrow = GenerationalRefMut::map(inner, |v| &mut v.value);
@@ -255,14 +265,6 @@ 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) { fn update_subscribers(&self) {
{ {
let inner = self.inner.read(); let inner = self.inner.read();