use proc_macro2::{Ident, TokenStream}; use quote::{format_ident, quote}; use syn::LitStr; use crate::{ hash::HashFragment, nest::NestId, query::QuerySegment, segment::{create_error_type, parse_route_segments, RouteSegment}, }; #[derive(Debug)] pub(crate) struct Redirect { pub route: LitStr, pub nests: Vec, pub segments: Vec, pub query: Option, pub hash: Option, pub function: syn::ExprClosure, pub index: usize, } impl Redirect { pub fn error_ident(&self) -> Ident { format_ident!("Redirect{}ParseError", self.index) } pub fn error_variant(&self) -> Ident { format_ident!("Redirect{}", self.index) } pub fn error_type(&self) -> TokenStream { let error_name = self.error_ident(); create_error_type(error_name, &self.segments, None) } pub fn parse_query(&self) -> TokenStream { match &self.query { Some(query) => query.parse(), None => quote! {}, } } pub fn parse_hash(&self) -> TokenStream { match &self.hash { Some(hash) => hash.parse(), None => quote! {}, } } pub fn parse( input: syn::parse::ParseStream, active_nests: Vec, index: usize, ) -> syn::Result { let path = input.parse::()?; let _ = input.parse::(); let function = input.parse::()?; let mut closure_arguments = Vec::new(); for arg in function.inputs.iter() { match arg { syn::Pat::Type(pat) => match &*pat.pat { syn::Pat::Ident(ident) => { closure_arguments.push((ident.ident.clone(), (*pat.ty).clone())); } _ => { return Err(syn::Error::new_spanned( arg, "Expected closure argument to be a typed pattern", )) } }, _ => { return Err(syn::Error::new_spanned( arg, "Expected closure argument to be a typed pattern", )) } } } let (segments, query, hash) = parse_route_segments( path.span(), #[allow(clippy::map_identity)] closure_arguments.iter().map(|(name, ty)| (name, ty)), &path.value(), )?; Ok(Redirect { route: path, nests: active_nests, segments, query, hash, function, index, }) } }