Merge pull request #324 from overlisted/inlineprops-generics

`#[inline_props]` generics
This commit is contained in:
Jon Kelley authored and GitHub committed 2022-03-20 20:28:06 -04:00
commit 4edaeb0aae
3 files changed
+83 -10

No files matched your search

+1
View File
@@ -41,6 +41,7 @@ These examples are not necessarily meant to be run, but rather serve as a refere
| [Anti-patterns](./antipatterns.rs) | A collection of discouraged patterns | ✅ | | [Anti-patterns](./antipatterns.rs) | A collection of discouraged patterns | ✅ |
| [Complete rsx reference](./rsx_usage.rs) | A complete reference for all rsx! usage | ✅ | | [Complete rsx reference](./rsx_usage.rs) | A complete reference for all rsx! usage | ✅ |
| [Event Listeners](./listener.rs) | Attach closures to events on elements | ✅ | | [Event Listeners](./listener.rs) | Attach closures to events on elements | ✅ |
| [Inline Props](./inlineprops.rs) | Using the `#[inline_props]` macro | ✅ |
## Show me some examples! ## Show me some examples!
+41
View File
@@ -0,0 +1,41 @@
//! Run with `cargo-expand` to see what each one expands to
#![allow(non_snake_case)]
use dioxus::prelude::*;
#[inline_props]
fn Thing1<T>(cx: Scope, _a: T) -> Element {
cx.render(rsx! { "" })
}
#[inline_props]
fn Thing2(cx: Scope, _a: u32) -> Element<'a> {
cx.render(rsx! { "" })
}
#[inline_props]
fn Thing3<'a, T>(cx: Scope<'a>, _a: &'a T) -> Element<'a> {
cx.render(rsx! { "" })
}
#[inline_props]
fn Thing4<'a>(cx: Scope<'a>, _a: &'a u32) -> Element<'a> {
cx.render(rsx! { "" })
}
fn main() {
dioxus::desktop::launch(app);
}
fn app(cx: Scope) -> Element {
let state = use_state(&cx, || 1);
cx.render(rsx! {
div {
Thing1 { _a: 1 },
Thing2 { _a: 1 },
Thing3 { _a: state },
Thing4 { _a: state },
}
})
}
+41 -10
View File
@@ -3,7 +3,7 @@ use quote::{quote, ToTokens, TokenStreamExt};
use syn::{ use syn::{
parse::{Parse, ParseStream}, parse::{Parse, ParseStream},
punctuated::Punctuated, punctuated::Punctuated,
token, Block, FnArg, Generics, Ident, Pat, Result, ReturnType, Token, Visibility, *,
}; };
pub struct InlinePropsBody { pub struct InlinePropsBody {
@@ -34,7 +34,7 @@ impl Parse for InlinePropsBody {
let first_arg: FnArg = content.parse()?; let first_arg: FnArg = content.parse()?;
let cx_token = { let cx_token = {
match first_arg { match first_arg {
FnArg::Receiver(_) => panic!("first argument must not be a reciver argument"), FnArg::Receiver(_) => panic!("first argument must not be a receiver argument"),
FnArg::Typed(f) => f.pat, FnArg::Typed(f) => f.pat,
} }
}; };
@@ -86,26 +86,57 @@ impl ToTokens for InlinePropsBody {
FnArg::Typed(t) => Some(&t.pat), FnArg::Typed(t) => Some(&t.pat),
}); });
let modifiers = if generics.params.is_empty() { let first_lifetime = if let Some(GenericParam::Lifetime(lt)) = generics.params.first() {
quote! { #[derive(Props, PartialEq)] } Some(lt)
} else { } else {
quote! { #[derive(Props)] } None
}; };
let lifetime = if generics.params.is_empty() { let modifiers = if first_lifetime.is_some() {
quote! {} quote! { #[derive(Props)] }
} else { } else {
quote! { 'a, } quote! { #[derive(Props, PartialEq)] }
};
let (scope_lifetime, fn_generics, struct_generics) = if let Some(lt) = first_lifetime {
let struct_generics: Punctuated<_, token::Comma> = generics
.params
.iter()
.map(|it| match it {
GenericParam::Type(tp) => {
let mut tp = tp.clone();
tp.bounds.push(parse_quote!( 'a ));
GenericParam::Type(tp)
}
_ => it.clone(),
})
.collect();
(
quote! { #lt, },
generics.clone(),
quote! { <#struct_generics> },
)
} else {
let lifetime: LifetimeDef = parse_quote! { 'a };
let mut fn_generics = generics.clone();
fn_generics
.params
.insert(0, GenericParam::Lifetime(lifetime.clone()));
(quote! { #lifetime, }, fn_generics, quote! { #generics })
}; };
out_tokens.append_all(quote! { out_tokens.append_all(quote! {
#modifiers #modifiers
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
#vis struct #struct_name #generics { #vis struct #struct_name #struct_generics {
#(#fields),* #(#fields),*
} }
#vis fn #ident #generics (#cx_token: Scope<#lifetime #struct_name #generics>) #output { #vis fn #ident #fn_generics (#cx_token: Scope<#scope_lifetime #struct_name #generics>) #output {
let #struct_name { #(#field_names),* } = &cx.props; let #struct_name { #(#field_names),* } = &cx.props;
#block #block
} }