redirect.rs 2.5 KB

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