Files
dioxus/packages/stores/tests/marco.rs
T
Evan AlmloffandJonathan Kelley 58c41f8561 Stores: Externally tracked state and reactive collections (#4483)
* map signals mutably

* boxed signals

* remove mutable borrow type from boxed writable

* improve map mut example

* restore boxed_mut helper

* make boxed readable/writable types copy

* Move away from the ReadOnlySignal alias in examples

* automatically convert Write

* Fix some tests

* ReadSignal and WriteSignal

* move read only signal alias

* make maps copy

* store prototype

* implement derive macro

* Handle generics in the derive macro

* Make Selector boxable

* derive boxed conversion

* Get rid of store type

* Remove hardcoded type from derive macro

* selector -> store

* Refactor store implementation

* more vec methods

* todo mvc store example

* Implement Storable for HashMap

* fix write

* restore sorting logic in todomvc

* derive readable and writable

* improve todomvc store example

* Result store

* Option store

* collect dead subscribers

* fix clippy and formatting

* recognize some common foreign types automatically

* fix foreign stores in props

* slice and array selectors

* clean up store example

* writable is child owned

* box selector

* read and write to builtins

* re-use the proc macro in the derive macro

* Switch to a extension trait based approach

* switch to extension traits in the derive macro

* transposed method

* derive enums

* Expose Store::new

* remove stores from the prelude

* More consistent naming scheme for SelectorScope methods

* document hashmap methods

* document index extension

* document option ext

* document result ext

* document slice extension

* document the vec extension

* make more methods borrow the store mutably

* Move to impls to have higher priority over the builtin write extension traits

* fix deadlock

* finish stores documentation

* Document the store macro

* cleanup docs and organization

* finish derive docs

* fix typo

* fix clippy

* fix doc tests

* fix derive macro with generics

* fix clippy

* test and fix empty structs

* clean up todomvc store example

* default to a boxed store writer to make it easier to type when providing to the context api

* fix cargo doc

* fix clippy in store example

* relax generational box lifetime bounds

* relax bounds

* relax signal bounds

* fix compilation

* read store

* relax bounds on default store impls

* fix enum derive

* Convert to readsignal and writesignal automatically

* simplify type matching logic

* add write store

* unsized stores

* shrink the path vec type

* use more concrete types

* remove opaque types

* remove copy bounds

* use lens as generic name everywhere

* more consistent borrow semantics

* use a concrete type for the signal metadata and mention references in the map docs

* improve todomvc store docs

* document store derive macro internals

* refactor macro

* improve selector node documentation

* fix clippy

* add btreemap

* fix doc tests

* more option methods

* fix doc

* fix clippy

* add a bunch more result methods

* add a bunch of bounds to the iterators

* fix clippy

* remove option from subscribers

* add store macro to generate extension traits

* fix store example

* fix deadlock

* fix docs

* fix doc tests

* fix clippy

* add stores to public api

* add store macro, and then update todomvc_store example

---------

Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
2025-08-05 11:30:21 -07:00

236 lines
6.3 KiB
Rust

#[allow(unused)]
#[allow(clippy::disallowed_names)]
mod macro_tests {
use dioxus_signals::*;
use dioxus_stores::*;
use std::collections::HashMap;
fn derive_unit() {
#[derive(Store)]
struct TodoItem;
}
fn derive_struct() {
#[derive(Store)]
struct TodoItem {
checked: bool,
contents: String,
}
#[store]
impl Store<TodoItem> {
fn is_checked(&self) -> bool {
self.checked().cloned()
}
fn check(&mut self) {
self.checked().set(true);
}
}
let mut store = use_store(|| TodoItem {
checked: false,
contents: "Learn about stores".to_string(),
});
// The store macro creates an extension trait with methods for each field
// that returns a store scoped to that field.
let checked: Store<bool, _> = store.checked();
let contents: Store<String, _> = store.contents();
let checked: bool = checked();
let contents: String = contents();
// It also generates a `transpose` method returns a variant of your structure
// with stores wrapping each of your data types. This can be very useful when destructuring
// or matching your type
let TodoItemStoreTransposed { checked, contents } = store.transpose();
let checked: bool = checked();
let contents: String = contents();
let is_checked = store.is_checked();
store.check();
}
fn derive_generic_struct() {
#[derive(Store)]
struct Item<T> {
checked: bool,
contents: T,
}
#[store]
impl<T> Store<Item<T>> {
fn is_checked(&self) -> bool
where
T: 'static,
{
self.checked().cloned()
}
fn check(&mut self)
where
T: 'static,
{
self.checked().set(true);
}
}
let mut store = use_store(|| Item {
checked: false,
contents: "Learn about stores".to_string(),
});
let checked: Store<bool, _> = store.checked();
let contents: Store<String, _> = store.contents();
let checked: bool = checked();
let contents: String = contents();
let ItemStoreTransposed { checked, contents } = store.transpose();
let checked: bool = checked();
let contents: String = contents();
let is_checked = store.is_checked();
store.check();
}
fn derive_tuple() {
#[derive(Store, PartialEq, Clone, Debug)]
struct Item(bool, String);
let store = use_store(|| Item(true, "Hello".to_string()));
let first = store.field_0();
let first: bool = first();
let transposed = store.transpose();
let first = transposed.0;
let second = transposed.1;
let first: bool = first();
let second: String = second();
}
fn derive_enum() {
#[derive(Store, PartialEq, Clone, Debug)]
#[non_exhaustive]
enum Enum {
Foo,
Bar(String),
Baz { foo: i32, bar: String },
FooBar(u32, String),
BarFoo { foo: String },
}
#[store]
impl Store<Enum> {
fn is_foo_or_bar(&self) -> bool {
matches!(self.cloned(), Enum::Foo | Enum::Bar(_))
}
fn make_foo(&mut self) {
self.set(Enum::Foo);
}
}
let mut store = use_store(|| Enum::Bar("Hello".to_string()));
let foo = store.is_foo();
let bar = store.is_bar();
let baz = store.is_baz();
let foobar = store.is_foo_bar();
let barfoo = store.is_bar_foo();
let foo = store.bar().unwrap();
let foo: String = foo();
let bar = store.bar_foo().unwrap();
let bar: String = bar();
let transposed = store.transpose();
use EnumStoreTransposed::*;
match transposed {
EnumStoreTransposed::Foo => {}
Bar(bar) => {
let bar: String = bar();
}
Baz { foo, bar } => {
let foo: i32 = foo();
let bar: String = bar();
}
FooBar(foo, bar) => {
let foo: u32 = foo();
let bar: String = bar();
}
BarFoo { foo } => {
let foo: String = foo();
}
}
let is_foo_or_bar = store.is_foo_or_bar();
store.make_foo();
}
fn derive_generic_enum() {
#[derive(Store, PartialEq, Clone, Debug)]
#[non_exhaustive]
enum Enum<T> {
Foo,
Bar(T),
Baz { foo: i32, bar: T },
FooBar(u32, T),
BarFoo { foo: T },
}
#[store]
impl<T> Store<Enum<T>> {
fn is_foo_or_bar(&self) -> bool
where
T: Clone + 'static,
{
matches!(self.cloned(), Enum::Foo | Enum::Bar(_))
}
fn make_foo(&mut self)
where
T: 'static,
{
self.set(Enum::Foo);
}
}
let mut store = use_store(|| Enum::Bar("Hello".to_string()));
let foo = store.is_foo();
let bar = store.is_bar();
let baz = store.is_baz();
let foobar = store.is_foo_bar();
let barfoo = store.is_bar_foo();
let foo = store.bar().unwrap();
let foo: String = foo();
let bar = store.bar_foo().unwrap();
let bar: String = bar();
let transposed = store.transpose();
use EnumStoreTransposed::*;
match transposed {
EnumStoreTransposed::Foo => {}
Bar(bar) => {
let bar: String = bar();
}
Baz { foo, bar } => {
let foo: i32 = foo();
let bar: String = bar();
}
FooBar(foo, bar) => {
let foo: u32 = foo();
let bar: String = bar();
}
BarFoo { foo } => {
let foo: String = foo();
}
}
let is_foo_or_bar = store.is_foo_or_bar();
store.make_foo();
}
}