freya_router_macro/
redirect.rs1use proc_macro2::{
2 Ident,
3 TokenStream,
4};
5use quote::{
6 format_ident,
7 quote,
8};
9use syn::LitStr;
10
11use crate::{
12 hash::HashFragment,
13 nest::NestId,
14 query::QuerySegment,
15 segment::{
16 RouteSegment,
17 create_error_type,
18 parse_route_segments,
19 },
20};
21
22#[derive(Debug)]
23pub(crate) struct Redirect {
24 pub route: LitStr,
25 pub nests: Vec<NestId>,
26 pub segments: Vec<RouteSegment>,
27 pub query: Option<QuerySegment>,
28 pub hash: Option<HashFragment>,
29 pub function: syn::ExprClosure,
30 pub index: usize,
31}
32
33impl Redirect {
34 pub fn error_ident(&self) -> Ident {
35 format_ident!("Redirect{}ParseError", self.index)
36 }
37
38 pub fn error_variant(&self) -> Ident {
39 format_ident!("Redirect{}", self.index)
40 }
41
42 pub fn error_type(&self) -> TokenStream {
43 let error_name = self.error_ident();
44
45 create_error_type(&self.route.value(), error_name, &self.segments, None)
46 }
47
48 pub fn parse_query(&self) -> TokenStream {
49 match &self.query {
50 Some(query) => query.parse(),
51 None => quote! {},
52 }
53 }
54
55 pub fn parse_hash(&self) -> TokenStream {
56 match &self.hash {
57 Some(hash) => hash.parse(),
58 None => quote! {},
59 }
60 }
61
62 pub fn parse(
63 input: syn::parse::ParseStream,
64 active_nests: Vec<NestId>,
65 index: usize,
66 ) -> syn::Result<Self> {
67 let path = input.parse::<syn::LitStr>()?;
68
69 let _ = input.parse::<syn::Token![,]>();
70 let function = input.parse::<syn::ExprClosure>()?;
71
72 let mut closure_arguments = Vec::new();
73 for arg in function.inputs.iter() {
74 match arg {
75 syn::Pat::Type(pat) => match &*pat.pat {
76 syn::Pat::Ident(ident) => {
77 closure_arguments.push((ident.ident.clone(), (*pat.ty).clone()));
78 }
79 _ => {
80 return Err(syn::Error::new_spanned(
81 arg,
82 "Expected closure argument to be a typed pattern",
83 ));
84 }
85 },
86 _ => {
87 return Err(syn::Error::new_spanned(
88 arg,
89 "Expected closure argument to be a typed pattern",
90 ));
91 }
92 }
93 }
94
95 let (segments, query, hash) = parse_route_segments(
96 path.span(),
97 #[allow(clippy::map_identity)]
98 closure_arguments.iter().map(|(name, ty)| (name, ty)),
99 &path.value(),
100 )?;
101
102 Ok(Redirect {
103 route: path,
104 nests: active_nests,
105 segments,
106 query,
107 hash,
108 function,
109 index,
110 })
111 }
112}