Merge pull request #324 from overlisted/inlineprops-generics
`#[inline_props]` generics
This commit is contained in:
3 files changed
+91
-18
No files matched your search
+9
-8
@@ -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!
|
||||||
@@ -51,7 +52,7 @@ In our collection of examples, guides, and tutorials, we have:
|
|||||||
- The reference (a collection of examples with heavy documentation)
|
- The reference (a collection of examples with heavy documentation)
|
||||||
- The general examples
|
- The general examples
|
||||||
- The platform-specific examples (web, ssr, desktop, mobile, server)
|
- The platform-specific examples (web, ssr, desktop, mobile, server)
|
||||||
|
|
||||||
Here's what a few common tasks look like in Dioxus:
|
Here's what a few common tasks look like in Dioxus:
|
||||||
|
|
||||||
Nested components with children and internal state:
|
Nested components with children and internal state:
|
||||||
@@ -80,7 +81,7 @@ Controlled inputs:
|
|||||||
```rust
|
```rust
|
||||||
fn App(cx: Scope) -> Element {
|
fn App(cx: Scope) -> Element {
|
||||||
let value = use_state(&cx, String::new);
|
let value = use_state(&cx, String::new);
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
input {
|
input {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
value: "{value}",
|
value: "{value}",
|
||||||
@@ -96,16 +97,16 @@ fn App(cx: Scope) -> Element {
|
|||||||
let list = (0..10).map(|i| {
|
let list = (0..10).map(|i| {
|
||||||
rsx!(li { key: "{i}", "Value: {i}" })
|
rsx!(li { key: "{i}", "Value: {i}" })
|
||||||
});
|
});
|
||||||
|
|
||||||
let title = match list.len() {
|
let title = match list.len() {
|
||||||
0 => rsx!("Not enough"),
|
0 => rsx!("Not enough"),
|
||||||
_ => rsx!("Plenty!"),
|
_ => rsx!("Plenty!"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_show {
|
if should_show {
|
||||||
cx.render(rsx!(
|
cx.render(rsx!(
|
||||||
title,
|
title,
|
||||||
ul { list }
|
ul { list }
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -165,18 +166,18 @@ fn App(cx: Scope) -> Element {
|
|||||||
Route::Home => rsx!( Home {} ),
|
Route::Home => rsx!( Home {} ),
|
||||||
Route::Post(id) => rsx!( Post { id: id })
|
Route::Post(id) => rsx!( Post { id: id })
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Suspense
|
Suspense
|
||||||
```rust
|
```rust
|
||||||
fn App(cx: Scope) -> Element {
|
fn App(cx: Scope) -> Element {
|
||||||
let doggo = use_suspense(cx,
|
let doggo = use_suspense(cx,
|
||||||
|| async { reqwest::get("https://dog.ceo/api/breeds/image/random").await.unwrap().json::<Response>().await.unwrap() },
|
|| async { reqwest::get("https://dog.ceo/api/breeds/image/random").await.unwrap().json::<Response>().await.unwrap() },
|
||||||
|response| cx.render(rsx!( img { src: "{response.message}" }))
|
|response| cx.render(rsx!( img { src: "{response.message}" }))
|
||||||
);
|
);
|
||||||
|
|
||||||
cx.render(rsx!{
|
cx.render(rsx!{
|
||||||
div {
|
div {
|
||||||
"One doggo coming right up:",
|
"One doggo coming right up:",
|
||||||
|
|||||||
@@ -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 },
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user