mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
parent
aa49ad760b
commit
66d7cb5d12
5 changed files with 179 additions and 0 deletions
|
@ -19,6 +19,7 @@ mod params;
|
|||
mod view;
|
||||
use crate::component::unmodified_fn_name_from_fn_name;
|
||||
mod component;
|
||||
mod memo;
|
||||
mod slice;
|
||||
mod slot;
|
||||
|
||||
|
@ -875,3 +876,35 @@ pub fn params_derive(
|
|||
pub fn slice(input: TokenStream) -> TokenStream {
|
||||
slice::slice_impl(input)
|
||||
}
|
||||
|
||||
/// Generates a `memo` into a struct with a default getter.
|
||||
///
|
||||
/// Can be used to access deeply nested fields within a global state object.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use leptos::prelude::*;
|
||||
/// # use leptos_macro::memo;
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// pub struct Outer {
|
||||
/// count: i32,
|
||||
/// inner: Inner,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(Default)]
|
||||
/// pub struct Inner {
|
||||
/// inner_count: i32,
|
||||
/// inner_name: String,
|
||||
/// }
|
||||
///
|
||||
/// let outer_signal = RwSignal::new(Outer::default());
|
||||
///
|
||||
/// let count = memo!(outer_signal.count);
|
||||
///
|
||||
/// let inner_count = memo!(outer_signal.inner.inner_count);
|
||||
/// let inner_name = memo!(outer_signal.inner.inner_name);
|
||||
/// ```
|
||||
#[proc_macro]
|
||||
pub fn memo(input: TokenStream) -> TokenStream {
|
||||
memo::memo_impl(input)
|
||||
}
|
||||
|
|
56
leptos_macro/src/memo.rs
Normal file
56
leptos_macro/src/memo.rs
Normal file
|
@ -0,0 +1,56 @@
|
|||
extern crate proc_macro;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
punctuated::Punctuated,
|
||||
Token,
|
||||
};
|
||||
|
||||
struct MemoMacroInput {
|
||||
root: syn::Ident,
|
||||
path: Punctuated<syn::Member, Token![.]>,
|
||||
}
|
||||
|
||||
impl Parse for MemoMacroInput {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let root: syn::Ident = input.parse()?;
|
||||
input.parse::<Token![.]>()?;
|
||||
// do not accept trailing punctuation
|
||||
let path: Punctuated<syn::Member, Token![.]> =
|
||||
Punctuated::parse_separated_nonempty(input)?;
|
||||
|
||||
if path.is_empty() {
|
||||
return Err(input.error("expected identifier"));
|
||||
}
|
||||
|
||||
if !input.is_empty() {
|
||||
return Err(input.error("unexpected token"));
|
||||
}
|
||||
|
||||
Ok(Self { root, path })
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for MemoMacroInput {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
let root = &self.root;
|
||||
let path = &self.path;
|
||||
|
||||
tokens.extend(quote! {
|
||||
::leptos::reactive_graph::computed::Memo::new(
|
||||
move |_| {
|
||||
use ::leptos::reactive_graph::traits::With;
|
||||
#root.with(|st: _| st.#path.clone())
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memo_impl(tokens: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(tokens as MemoMacroInput);
|
||||
input.into_token_stream().into()
|
||||
}
|
33
leptos_macro/tests/memo.rs
Normal file
33
leptos_macro/tests/memo.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use leptos::prelude::RwSignal;
|
||||
use leptos_macro::memo;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct OuterState {
|
||||
count: i32,
|
||||
inner: InnerState,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct InnerState {
|
||||
inner_count: i32,
|
||||
inner_tuple: InnerTuple,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct InnerTuple(String);
|
||||
|
||||
#[test]
|
||||
fn green() {
|
||||
let outer_signal = RwSignal::new(OuterState::default());
|
||||
|
||||
let _ = memo!(outer_signal.count);
|
||||
|
||||
let _ = memo!(outer_signal.inner.inner_count);
|
||||
let _ = memo!(outer_signal.inner.inner_tuple.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn red() {
|
||||
let t = trybuild::TestCases::new();
|
||||
t.compile_fail("tests/memo/red.rs")
|
||||
}
|
26
leptos_macro/tests/memo/red.rs
Normal file
26
leptos_macro/tests/memo/red.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use leptos::prelude::RwSignal;
|
||||
use leptos_macro::memo;
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub struct OuterState {
|
||||
count: i32,
|
||||
inner: InnerState,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Default)]
|
||||
pub struct InnerState {
|
||||
inner_count: i32,
|
||||
inner_name: String,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let outer_signal = RwSignal::new(OuterState::default());
|
||||
|
||||
let _ = memo!();
|
||||
|
||||
let _ = memo!(outer_signal);
|
||||
|
||||
let _ = memo!(outer_signal.);
|
||||
|
||||
let _ = memo!(outer_signal.inner.);
|
||||
}
|
31
leptos_macro/tests/memo/red.stderr
Normal file
31
leptos_macro/tests/memo/red.stderr
Normal file
|
@ -0,0 +1,31 @@
|
|||
error: unexpected end of input, expected identifier
|
||||
--> tests/memo/red.rs:19:13
|
||||
|
|
||||
19 | let _ = memo!();
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `memo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: expected `.`
|
||||
--> tests/memo/red.rs:21:13
|
||||
|
|
||||
21 | let _ = memo!(outer_signal);
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `memo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected end of input, expected identifier or integer
|
||||
--> tests/memo/red.rs:23:13
|
||||
|
|
||||
23 | let _ = memo!(outer_signal.);
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `memo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected end of input, expected identifier or integer
|
||||
--> tests/memo/red.rs:25:13
|
||||
|
|
||||
25 | let _ = memo!(outer_signal.inner.);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `memo` (in Nightly builds, run with -Z macro-backtrace for more info)
|
Loading…
Reference in a new issue