From 502d670dffe1b479a08423f2d684a649cf21aa89 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Tue, 23 May 2023 17:32:40 -0500 Subject: [PATCH] improve macro ergonomics --- packages/router-macro/src/layout.rs | 6 ---- packages/router-macro/src/lib.rs | 51 ++++++++++++++++------------- packages/router-macro/src/route.rs | 26 ++------------- packages/router/src/lib.rs | 2 +- 4 files changed, 32 insertions(+), 53 deletions(-) diff --git a/packages/router-macro/src/layout.rs b/packages/router-macro/src/layout.rs index 631aacedc..859ef6c6d 100644 --- a/packages/router-macro/src/layout.rs +++ b/packages/router-macro/src/layout.rs @@ -9,7 +9,6 @@ pub struct LayoutId(pub usize); #[derive(Debug)] pub struct Layout { - pub layout_name: Ident, pub comp: Ident, pub props_name: Ident, pub active_nests: Vec, @@ -37,10 +36,6 @@ impl Layout { impl Layout { pub fn parse(input: syn::parse::ParseStream, active_nests: Vec) -> syn::Result { - // Then parse the layout name - let _ = input.parse::(); - let layout_name: syn::Ident = input.parse()?; - // Then parse the component name let _ = input.parse::(); let comp: Ident = input.parse()?; @@ -52,7 +47,6 @@ impl Layout { .unwrap_or_else(|_| format_ident!("{}Props", comp.to_string())); Ok(Self { - layout_name, comp, props_name, active_nests, diff --git a/packages/router-macro/src/lib.rs b/packages/router-macro/src/lib.rs index 5f65c5957..ca9bf690b 100644 --- a/packages/router-macro/src/lib.rs +++ b/packages/router-macro/src/lib.rs @@ -5,7 +5,7 @@ use nest::{Nest, NestId}; use proc_macro::TokenStream; use quote::{__private::Span, format_ident, quote, ToTokens}; use route::Route; -use syn::{parse::ParseStream, parse_macro_input, Ident}; +use syn::{parse::ParseStream, parse_macro_input, Ident, Token}; use proc_macro2::TokenStream as TokenStream2; @@ -18,9 +18,8 @@ mod route; mod route_tree; mod segment; -// #[proc_macro_derive(Routable, attributes(route, nest, end_nest))] -#[proc_macro_attribute] -pub fn routable(_: TokenStream, input: TokenStream) -> TokenStream { +#[proc_macro_derive(Routable, attributes(route, nest, end_nest, layout, end_layout))] +pub fn routable(input: TokenStream) -> TokenStream { let routes_enum = parse_macro_input!(input as syn::ItemEnum); let route_enum = match RouteEnum::parse(routes_enum) { @@ -48,8 +47,6 @@ pub fn routable(_: TokenStream, input: TokenStream) -> TokenStream { } struct RouteEnum { - attrs: Vec, - vis: syn::Visibility, name: Ident, routes: Vec, nests: Vec, @@ -62,13 +59,14 @@ impl RouteEnum { let mut routes = Vec::new(); - let mut layouts = Vec::new(); + let mut layouts: Vec = Vec::new(); let mut layout_stack = Vec::new(); let mut nests = Vec::new(); let mut nest_stack = Vec::new(); for variant in &data.variants { + let mut excluded = Vec::new(); // Apply the any nesting attributes in order for attr in &variant.attrs { if attr.path.is_ident("nest") { @@ -113,15 +111,31 @@ impl RouteEnum { } else if attr.path.is_ident("end_nest") { nest_stack.pop(); } else if attr.path.is_ident("layout") { - let layout_index = layouts.len(); - let parser = |input: ParseStream| { - Layout::parse(input, nest_stack.iter().rev().cloned().collect()) + let bang: Option = input.parse().ok(); + let exclude = bang.is_some(); + Ok(( + exclude, + Layout::parse(input, nest_stack.iter().rev().cloned().collect())?, + )) }; - let layout = attr.parse_args_with(parser)?; + let (exclude, layout): (bool, Layout) = attr.parse_args_with(parser)?; - layouts.push(layout); - layout_stack.push(LayoutId(layout_index)); + if exclude { + let Some(layout_index) = + layouts.iter().position(|l| l.comp == layout.comp)else{ + return Err(syn::Error::new( + Span::call_site(), + "Attempted to exclude a layout that does not exist", + )); + } + ; + excluded.push(LayoutId(layout_index)); + } else { + let layout_index = layouts.len(); + layouts.push(layout); + layout_stack.push(LayoutId(layout_index)); + } } else if attr.path.is_ident("end_layout") { layout_stack.pop(); } @@ -130,6 +144,7 @@ impl RouteEnum { let mut active_nests = nest_stack.clone(); active_nests.reverse(); let mut active_layouts = layout_stack.clone(); + active_layouts.retain(|&id| !excluded.contains(&id)); active_layouts.reverse(); let route = Route::parse(active_nests, active_layouts, variant.clone())?; @@ -139,8 +154,6 @@ impl RouteEnum { let myself = Self { name: name.clone(), - attrs: data.attrs, - vis: data.vis, routes, nests, layouts, @@ -315,16 +328,8 @@ impl RouteEnum { impl ToTokens for RouteEnum { fn to_tokens(&self, tokens: &mut quote::__private::TokenStream) { let routes = &self.routes; - let vis = &self.vis; - let name = &self.name; - let attrs = &self.attrs; - let variants = routes.iter().map(|r| r.variant()); tokens.extend(quote!( - #(#attrs)* - #vis enum #name { - #(#variants),* - } #[path = "pages"] mod pages { diff --git a/packages/router-macro/src/route.rs b/packages/router-macro/src/route.rs index a3b88275f..bf280a7a9 100644 --- a/packages/router-macro/src/route.rs +++ b/packages/router-macro/src/route.rs @@ -186,13 +186,10 @@ impl Route { } } for segment in &self.segments { - match segment { - RouteSegment::Dynamic(name, _) => { - if name == f.ident.as_ref().unwrap() { - from_route = true - } + if let RouteSegment::Dynamic(name, ..) = segment { + if name == f.ident.as_ref().unwrap() { + from_route = true } - _ => {} } } @@ -273,23 +270,6 @@ impl Route { } } - pub fn variant(&self) -> TokenStream2 { - let name = &self.route_name; - let fields = self.fields.named.iter().map(|f| { - let mut new = f.clone(); - new.attrs.retain(|a| { - !a.path.is_ident("nest") - && !a.path.is_ident("end_nest") - && !a.path.is_ident("layout") - && !a.path.is_ident("end_layout") - }); - new - }); - - quote! { - #name { #(#fields,)* } - } - } } impl ToTokens for Route { diff --git a/packages/router/src/lib.rs b/packages/router/src/lib.rs index 9426fd3a3..b057ae853 100644 --- a/packages/router/src/lib.rs +++ b/packages/router/src/lib.rs @@ -48,7 +48,7 @@ pub mod prelude { pub use crate::contexts::*; pub use crate::hooks::*; pub use crate::router_cfg::RouterConfiguration; - pub use dioxus_router_macro::routable; + pub use dioxus_router_macro::Routable; } mod utils {