Skip to content
This repository was archived by the owner on Jul 19, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 34 additions & 5 deletions crates/yew_router_macro/src/switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::switch::{
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{export::TokenStream2, parse_macro_input, Data, DeriveInput, Fields, Ident, Variant};
use syn::{export::TokenStream2, parse_macro_input, Data, DeriveInput, Fields, Ident, Variant, Generics, GenericParam};

mod attribute;
mod enum_impl;
Expand All @@ -15,6 +15,7 @@ mod struct_impl;

use self::attribute::AttrToken;
use yew_router_route_parser::FieldNamingScheme;
use syn::punctuated::Punctuated;

/// Holds data that is required to derive Switch for a struct or a single enum variant.
pub struct SwitchItem {
Expand All @@ -27,6 +28,7 @@ pub fn switch_impl(input: TokenStream) -> TokenStream {
let input: DeriveInput = parse_macro_input!(input as DeriveInput);

let ident: Ident = input.ident;
let generics = input.generics;

match input.data {
Data::Struct(ds) => {
Expand All @@ -41,12 +43,13 @@ pub fn switch_impl(input: TokenStream) -> TokenStream {
.map(|(index, at)| at.into_shadow_matcher_tokens(index, field_naming_scheme))
.flatten()
.collect::<Vec<_>>();

let switch_item = SwitchItem {
matcher,
ident,
fields: ds.fields,
};
generate_struct_impl(switch_item)
generate_struct_impl(switch_item, generics)
}
Data::Enum(de) => {
let switch_variants = de
Expand All @@ -71,7 +74,7 @@ pub fn switch_impl(input: TokenStream) -> TokenStream {
}
})
.collect::<Vec<SwitchItem>>();
generate_enum_impl(ident, switch_variants)
generate_enum_impl(ident, switch_variants, generics)
}
Data::Union(_du) => panic!("Deriving FromCaptures not supported for Unions."),
}
Expand Down Expand Up @@ -211,7 +214,7 @@ pub fn build_serializer_for_enum(
});
quote! {
use ::std::fmt::Write as __Write;
let mut state: Option<T> = None;
let mut state: Option<__T> = None;
match #match_item {
#(#variants)*,
}
Expand Down Expand Up @@ -272,7 +275,7 @@ pub fn build_serializer_for_struct(switch_item: &SwitchItem, item: &Ident) -> To
};
quote! {
use ::std::fmt::Write as _;
let mut state: Option<T> = None;
let mut state: Option<__T> = None;
#destructor_and_writers
return state;
}
Expand All @@ -284,3 +287,29 @@ pub fn build_serializer_for_struct(switch_item: &SwitchItem, item: &Ident) -> To
fn unnamed_field_index_item(index: usize) -> Ident {
Ident::new(&format!("__field_{}", index), Span::call_site())
}

/// Creates the "impl <X,Y,Z> ::yew_router::Switch for TypeName<X,Y,Z> where etc.." line.
pub fn impl_line(ident: &Ident, generics: &Generics) -> TokenStream2 {
if generics.params.is_empty() {
quote! {
impl ::yew_router::Switch for #ident
}
} else {
let params = &generics.params;
let param_idents = params
.iter()
.map(|p: &GenericParam| {
match p {
GenericParam::Type(ty) => ty.ident.clone(),
// GenericParam::Lifetime(lt) => lt.lifetime, // TODO different type here, must be handled by collecting into a new enum and defining how to convert _that_ to tokens.
_ => unimplemented!("Not all type parameter variants (lifetimes and consts) are supported in Switch")
}
})
.collect::<Punctuated<_,syn::token::Comma>>();

let where_clause = &generics.where_clause;
quote!{
impl <#params> ::yew_router::Switch for #ident <#param_idents> #where_clause
}
}
}
16 changes: 10 additions & 6 deletions crates/yew_router_macro/src/switch/enum_impl.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::switch::{build_serializer_for_enum, SwitchItem};
use crate::switch::{build_serializer_for_enum, SwitchItem, impl_line};
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::{export::TokenStream2, Field, Fields, Ident, Type};
use syn::{export::TokenStream2, Field, Fields, Ident, Type, Generics};

pub fn generate_enum_impl(enum_ident: Ident, switch_variants: Vec<SwitchItem>) -> TokenStream {
pub fn generate_enum_impl(enum_ident: Ident, switch_variants: Vec<SwitchItem>, generics: Generics) -> TokenStream {
let variant_matchers = switch_variants.iter().map(|sv| {
let SwitchItem {
matcher,
Expand All @@ -23,17 +23,21 @@ pub fn generate_enum_impl(enum_ident: Ident, switch_variants: Vec<SwitchItem>) -
let match_item = Ident::new("self", Span::call_site());
let serializer = build_serializer_for_enum(&switch_variants, &enum_ident, &match_item);


let impl_line = impl_line(&enum_ident, &generics);

let token_stream = quote! {
impl ::yew_router::Switch for #enum_ident {
fn from_route_part<T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<T>) -> (::std::option::Option<Self>, ::std::option::Option<T>) {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {
let mut state = route.state;
let route_string = route.route;
#(#variant_matchers)*

return (::std::option::Option::None, state)
}

fn build_route_section<T>(self, mut buf: &mut ::std::string::String) -> ::std::option::Option<T> {
fn build_route_section<__T>(self, mut buf: &mut ::std::string::String) -> ::std::option::Option<__T> {
#serializer
}
}
Expand Down
20 changes: 11 additions & 9 deletions crates/yew_router_macro/src/switch/struct_impl.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use crate::switch::SwitchItem;
use crate::switch::{SwitchItem, impl_line};
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{
export::{TokenStream, TokenStream2},
Field, Fields, Type,
};
use syn::{export::{TokenStream, TokenStream2}, Field, Fields, Type, Generics};

pub fn generate_struct_impl(item: SwitchItem) -> TokenStream {


pub fn generate_struct_impl(item: SwitchItem, generics: Generics) -> TokenStream {
let SwitchItem {
matcher,
ident,
Expand All @@ -18,9 +17,12 @@ pub fn generate_struct_impl(item: SwitchItem) -> TokenStream {
let match_item = Ident::new("self", Span::call_site());
let serializer = super::build_serializer_for_struct(&item, &match_item);

let impl_line = impl_line(ident, &generics);

let token_stream = quote! {
impl ::yew_router::Switch for #ident {
fn from_route_part<T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<T>) -> (::std::option::Option<Self>, ::std::option::Option<T>) {
#impl_line
{
fn from_route_part<__T: ::yew_router::route::RouteState>(route: ::yew_router::route::Route<__T>) -> (::std::option::Option<Self>, ::std::option::Option<__T>) {

#matcher
let mut state = route.state;
Expand All @@ -31,7 +33,7 @@ pub fn generate_struct_impl(item: SwitchItem) -> TokenStream {
return (::std::option::Option::None, state)
}

fn build_route_section<T>(self, mut buf: &mut ::std::string::String) -> ::std::option::Option<T> {
fn build_route_section<__T>(self, mut buf: &mut ::std::string::String) -> ::std::option::Option<__T> {
#serializer
}
}
Expand Down
8 changes: 8 additions & 0 deletions examples/switch/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,11 @@ pub struct OtherSingle(u32);
// #[to = "/bad_route/{hello}"]
// X,
//}

#[derive(Switch, Debug, Clone)]
#[to = "{*:path}#{route}"]
pub struct FragmentAdapter<W: Switch>{
path: String,
route: W
}