Skip to content

Commit

Permalink
feat: implement PatchField for Option<_> (leptos-rs#3528)
Browse files Browse the repository at this point in the history
  • Loading branch information
iradicek authored and zakstucke committed Feb 6, 2025
1 parent 0d4c0db commit d75f474
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 1 deletion.
114 changes: 113 additions & 1 deletion reactive_stores/src/option.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ where

#[cfg(test)]
mod tests {
use crate::{self as reactive_stores, Store};
use crate::{self as reactive_stores, Patch as _, Store};
use reactive_graph::{
effect::Effect,
traits::{Get, Read, ReadUntracked, Set, Write},
};
use reactive_stores_macro::Patch;
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
Expand Down Expand Up @@ -237,4 +238,115 @@ mod tests {
assert_eq!(parent_count.load(Ordering::Relaxed), 3);
assert_eq!(inner_count.load(Ordering::Relaxed), 3);
}

#[tokio::test]
async fn patch() {
use crate::OptionStoreExt;

#[derive(Debug, Clone, Store, Patch)]
struct Outer {
inner: Option<Inner>,
}

#[derive(Debug, Clone, Store, Patch)]
struct Inner {
first: String,
second: String,
}

let store = Store::new(Outer {
inner: Some(Inner {
first: "A".to_owned(),
second: "B".to_owned(),
}),
});

_ = any_spawner::Executor::init_tokio();

let parent_count = Arc::new(AtomicUsize::new(0));
let inner_first_count = Arc::new(AtomicUsize::new(0));
let inner_second_count = Arc::new(AtomicUsize::new(0));

Effect::new_sync({
let parent_count = Arc::clone(&parent_count);
move |prev: Option<()>| {
if prev.is_none() {
println!("parent: first run");
} else {
println!("parent: next run");
}

println!(" value = {:?}", store.inner().get());
parent_count.fetch_add(1, Ordering::Relaxed);
}
});
Effect::new_sync({
let inner_first_count = Arc::clone(&inner_first_count);
move |prev: Option<()>| {
if prev.is_none() {
println!("inner_first: first run");
} else {
println!("inner_first: next run");
}

println!(
" value = {:?}",
store.inner().map(|inner| inner.first().get())
);
inner_first_count.fetch_add(1, Ordering::Relaxed);
}
});
Effect::new_sync({
let inner_second_count = Arc::clone(&inner_second_count);
move |prev: Option<()>| {
if prev.is_none() {
println!("inner_second: first run");
} else {
println!("inner_second: next run");
}

println!(
" value = {:?}",
store.inner().map(|inner| inner.second().get())
);
inner_second_count.fetch_add(1, Ordering::Relaxed);
}
});

tick().await;
assert_eq!(parent_count.load(Ordering::Relaxed), 1);
assert_eq!(inner_first_count.load(Ordering::Relaxed), 1);
assert_eq!(inner_second_count.load(Ordering::Relaxed), 1);

store.patch(Outer {
inner: Some(Inner {
first: "A".to_string(),
second: "C".to_string(),
}),
});

tick().await;
assert_eq!(parent_count.load(Ordering::Relaxed), 1);
assert_eq!(inner_first_count.load(Ordering::Relaxed), 1);
assert_eq!(inner_second_count.load(Ordering::Relaxed), 2);

store.patch(Outer { inner: None });

tick().await;
assert_eq!(parent_count.load(Ordering::Relaxed), 2);
assert_eq!(inner_first_count.load(Ordering::Relaxed), 2);
assert_eq!(inner_second_count.load(Ordering::Relaxed), 3);

store.patch(Outer {
inner: Some(Inner {
first: "A".to_string(),
second: "B".to_string(),
}),
});

tick().await;
assert_eq!(parent_count.load(Ordering::Relaxed), 3);
assert_eq!(inner_first_count.load(Ordering::Relaxed), 3);
assert_eq!(inner_second_count.load(Ordering::Relaxed), 4);
}
}
29 changes: 29 additions & 0 deletions reactive_stores/src/patch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,35 @@ patch_primitives! {
NonZeroUsize
}

impl<T> PatchField for Option<T>
where
T: PatchField,
{
fn patch_field(
&mut self,
new: Self,
path: &StorePath,
notify: &mut dyn FnMut(&StorePath),
) {
match (self, new) {
(None, None) => {}
(old @ Some(_), None) => {
old.take();
notify(path);
}
(old @ None, new @ Some(_)) => {
*old = new;
notify(path);
}
(Some(old), Some(new)) => {
let mut new_path = path.to_owned();
new_path.push(0);
old.patch_field(new, &new_path, notify);
}
}
}
}

impl<T> PatchField for Vec<T>
where
T: PatchField,
Expand Down

0 comments on commit d75f474

Please sign in to comment.