Skip to content

Commit 0369fe7

Browse files
authored
Merge pull request #111 from DioxusLabs/jk/props-attrs
Flatten optional prop attributes
2 parents 20a2940 + c8535fb commit 0369fe7

File tree

4 files changed

+79
-118
lines changed

4 files changed

+79
-118
lines changed

examples/optional_props.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Example: README.md showcase
2+
//!
3+
//! The example from the README.md.
4+
5+
use dioxus::prelude::*;
6+
7+
fn main() {
8+
dioxus::desktop::launch(app);
9+
}
10+
11+
fn app(cx: Scope) -> Element {
12+
cx.render(rsx! {
13+
Button {
14+
a: "asd".to_string(),
15+
c: Some("asd".to_string()),
16+
d: "asd".to_string(),
17+
}
18+
})
19+
}
20+
21+
#[derive(Props, PartialEq)]
22+
struct ButtonProps {
23+
a: String,
24+
25+
#[props(default)]
26+
b: Option<String>,
27+
28+
#[props(default)]
29+
c: Option<String>,
30+
31+
#[props(default, strip_option)]
32+
d: Option<String>,
33+
}
34+
35+
fn Button(cx: Scope<ButtonProps>) -> Element {
36+
todo!()
37+
}

packages/core-macro/src/props/mod.rs

Lines changed: 38 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,6 @@ mod field_info {
267267
#[derive(Debug, Default, Clone)]
268268
pub struct FieldBuilderAttr {
269269
pub default: Option<syn::Expr>,
270-
pub setter: SetterSettings,
271-
}
272-
273-
#[derive(Debug, Clone, Default)]
274-
pub struct SetterSettings {
275270
pub doc: Option<syn::Expr>,
276271
pub skip: bool,
277272
pub auto_into: bool,
@@ -305,12 +300,12 @@ mod field_info {
305300
}
306301
}
307302
// Stash its span for later (we don’t yet know if it’ll be an error)
308-
if self.setter.skip && skip_tokens.is_none() {
303+
if self.skip && skip_tokens.is_none() {
309304
skip_tokens = Some(attr.tokens.clone());
310305
}
311306
}
312307

313-
if self.setter.skip && self.default.is_none() {
308+
if self.skip && self.default.is_none() {
314309
return Err(Error::new_spanned(
315310
skip_tokens.unwrap(),
316311
"#[props(skip)] must be accompanied by default or default_code",
@@ -331,6 +326,10 @@ mod field_info {
331326
self.default = Some(*assign.right);
332327
Ok(())
333328
}
329+
"doc" => {
330+
self.doc = Some(*assign.right);
331+
Ok(())
332+
}
334333
"default_code" => {
335334
if let syn::Expr::Lit(syn::ExprLit {
336335
lit: syn::Lit::Str(code),
@@ -355,7 +354,7 @@ mod field_info {
355354
}
356355
}
357356

358-
// uh not sure
357+
// #[props(default)]
359358
syn::Expr::Path(path) => {
360359
let name = path_to_single_string(&path.path)
361360
.ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
@@ -365,39 +364,33 @@ mod field_info {
365364
Some(syn::parse(quote!(Default::default()).into()).unwrap());
366365
Ok(())
367366
}
368-
_ => Err(Error::new_spanned(
369-
&path,
370-
format!("Unknown parameter {:?}", name),
371-
)),
372-
}
373-
}
374-
375-
//
376-
syn::Expr::Call(call) => {
377-
let subsetting_name = if let syn::Expr::Path(path) = &*call.func {
378-
path_to_single_string(&path.path)
379-
} else {
380-
None
381-
}
382-
.ok_or_else(|| {
383-
let call_func = &call.func;
384-
let call_func = quote!(#call_func);
385-
Error::new_spanned(
386-
&call.func,
387-
format!("Illegal builder setting group {}", call_func),
388-
)
389-
})?;
390-
match subsetting_name.as_ref() {
391-
"setter" => {
392-
for arg in call.args {
393-
self.setter.apply_meta(arg)?;
367+
_ => {
368+
macro_rules! handle_fields {
369+
( $( $flag:expr, $field:ident, $already:expr; )* ) => {
370+
match name.as_str() {
371+
$(
372+
$flag => {
373+
if self.$field {
374+
Err(Error::new(path.span(), concat!("Illegal setting - field is already ", $already)))
375+
} else {
376+
self.$field = true;
377+
Ok(())
378+
}
379+
}
380+
)*
381+
_ => Err(Error::new_spanned(
382+
&path,
383+
format!("Unknown setter parameter {:?}", name),
384+
))
385+
}
386+
}
394387
}
395-
Ok(())
388+
handle_fields!(
389+
"skip", skip, "skipped";
390+
"into", auto_into, "calling into() on the argument";
391+
"strip_option", strip_option, "putting the argument in Some(...)";
392+
)
396393
}
397-
_ => Err(Error::new_spanned(
398-
&call.func,
399-
format!("Illegal builder setting group name {}", subsetting_name),
400-
)),
401394
}
402395
}
403396

@@ -414,75 +407,6 @@ mod field_info {
414407
self.default = None;
415408
Ok(())
416409
}
417-
_ => Err(Error::new_spanned(path, "Unknown setting".to_owned())),
418-
}
419-
} else {
420-
Err(Error::new_spanned(
421-
expr,
422-
"Expected simple identifier".to_owned(),
423-
))
424-
}
425-
}
426-
_ => Err(Error::new_spanned(expr, "Expected (<...>=<...>)")),
427-
}
428-
}
429-
}
430-
431-
impl SetterSettings {
432-
fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
433-
match expr {
434-
syn::Expr::Assign(assign) => {
435-
let name = expr_to_single_string(&assign.left)
436-
.ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
437-
match name.as_str() {
438-
"doc" => {
439-
self.doc = Some(*assign.right);
440-
Ok(())
441-
}
442-
_ => Err(Error::new_spanned(
443-
&assign,
444-
format!("Unknown parameter {:?}", name),
445-
)),
446-
}
447-
}
448-
syn::Expr::Path(path) => {
449-
let name = path_to_single_string(&path.path)
450-
.ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
451-
macro_rules! handle_fields {
452-
( $( $flag:expr, $field:ident, $already:expr; )* ) => {
453-
match name.as_str() {
454-
$(
455-
$flag => {
456-
if self.$field {
457-
Err(Error::new(path.span(), concat!("Illegal setting - field is already ", $already)))
458-
} else {
459-
self.$field = true;
460-
Ok(())
461-
}
462-
}
463-
)*
464-
_ => Err(Error::new_spanned(
465-
&path,
466-
format!("Unknown setter parameter {:?}", name),
467-
))
468-
}
469-
}
470-
}
471-
handle_fields!(
472-
"skip", skip, "skipped";
473-
"into", auto_into, "calling into() on the argument";
474-
"strip_option", strip_option, "putting the argument in Some(...)";
475-
)
476-
}
477-
syn::Expr::Unary(syn::ExprUnary {
478-
op: syn::UnOp::Not(_),
479-
expr,
480-
..
481-
}) => {
482-
if let syn::Expr::Path(path) = *expr {
483-
let name = path_to_single_string(&path.path)
484-
.ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
485-
match name.as_str() {
486410
"doc" => {
487411
self.doc = None;
488412
Ok(())
@@ -540,7 +464,7 @@ mod struct_info {
540464

541465
impl<'a> StructInfo<'a> {
542466
pub fn included_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
543-
self.fields.iter().filter(|f| !f.builder_attr.setter.skip)
467+
self.fields.iter().filter(|f| !f.builder_attr.skip)
544468
}
545469

546470
pub fn new(
@@ -826,14 +750,14 @@ Finally, call `.build()` to create the instance of `{name}`.
826750
syn::GenericArgument::Type(ty_generics_tuple.into()),
827751
);
828752
let (impl_generics, _, where_clause) = generics.split_for_impl();
829-
let doc = match field.builder_attr.setter.doc {
753+
let doc = match field.builder_attr.doc {
830754
Some(ref doc) => quote!(#[doc = #doc]),
831755
None => quote!(),
832756
};
833757

834758
// NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of
835759
// nesting is different so we have to do this little dance.
836-
let arg_type = if field.builder_attr.setter.strip_option {
760+
let arg_type = if field.builder_attr.strip_option {
837761
let internal_type = field.type_from_inside_option().ok_or_else(|| {
838762
Error::new_spanned(
839763
&field_type,
@@ -844,15 +768,15 @@ Finally, call `.build()` to create the instance of `{name}`.
844768
} else {
845769
field_type
846770
};
847-
let (arg_type, arg_expr) = if field.builder_attr.setter.auto_into {
771+
let (arg_type, arg_expr) = if field.builder_attr.auto_into {
848772
(
849773
quote!(impl core::convert::Into<#arg_type>),
850774
quote!(#field_name.into()),
851775
)
852776
} else {
853777
(quote!(#arg_type), quote!(#field_name))
854778
};
855-
let arg_expr = if field.builder_attr.setter.strip_option {
779+
let arg_expr = if field.builder_attr.strip_option {
856780
quote!(Some(#arg_expr))
857781
} else {
858782
arg_expr
@@ -1076,7 +1000,7 @@ Finally, call `.build()` to create the instance of `{name}`.
10761000
let assignments = self.fields.iter().map(|field| {
10771001
let name = &field.name;
10781002
if let Some(ref default) = field.builder_attr.default {
1079-
if field.builder_attr.setter.skip {
1003+
if field.builder_attr.skip {
10801004
quote!(let #name = #default;)
10811005
} else {
10821006
quote!(let #name = #helper_trait_name::into_value(#name, || #default);)

packages/router/src/components/link.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ pub struct LinkProps<'a> {
2222
/// Link { to: Route::Home, href: Route::as_url }
2323
///
2424
/// ```
25-
#[props(default, setter(strip_option))]
25+
#[props(default, strip_option)]
2626
href: Option<&'a str>,
2727

28-
#[props(default, setter(strip_option))]
28+
#[props(default, strip_option)]
2929
class: Option<&'a str>,
3030

31-
#[props(default, setter(strip_option))]
31+
#[props(default, strip_option)]
3232
id: Option<&'a str>,
3333

3434
children: Element<'a>,

packages/router/src/components/router.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::RouterService;
1111
pub struct RouterProps<'a> {
1212
children: Element<'a>,
1313

14-
#[props(default, setter(strip_option))]
14+
#[props(default, strip_option)]
1515
onchange: Option<&'a Fn(&'a str)>,
1616
}
1717

0 commit comments

Comments
 (0)