1
0

nest.rs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. use proc_macro2::TokenStream;
  2. use quote::{format_ident, quote};
  3. use syn::{Ident, LitStr};
  4. use crate::segment::{parse_route_segments, RouteSegment};
  5. #[derive(Debug, Clone, Copy)]
  6. pub struct NestId(pub usize);
  7. #[derive(Debug, Clone)]
  8. pub struct Nest {
  9. pub route: String,
  10. pub segments: Vec<RouteSegment>,
  11. index: usize,
  12. }
  13. impl Nest {
  14. pub fn parse(
  15. input: syn::parse::ParseStream,
  16. children_routes: Vec<syn::FieldsNamed>,
  17. index: usize,
  18. ) -> syn::Result<Self> {
  19. // Parse the route
  20. let route: LitStr = input.parse()?;
  21. let route_segments = parse_route_segments(
  22. route.span(),
  23. children_routes.iter().flat_map(|f| f.named.iter()),
  24. &route.value(),
  25. )?
  26. .0;
  27. for seg in &route_segments {
  28. if let RouteSegment::CatchAll(name, _) = seg {
  29. return Err(syn::Error::new_spanned(
  30. name,
  31. format!(
  32. "Catch-all segments are not allowed in nested routes: {}",
  33. route.value()
  34. ),
  35. ));
  36. }
  37. }
  38. Ok(Self {
  39. route: route.value(),
  40. segments: route_segments,
  41. index,
  42. })
  43. }
  44. }
  45. impl Nest {
  46. pub fn dynamic_segments(&self) -> impl Iterator<Item = TokenStream> + '_ {
  47. self.segments
  48. .iter()
  49. .filter_map(|seg| seg.name())
  50. .map(|i| quote! {#i})
  51. }
  52. pub fn write(&self) -> TokenStream {
  53. let write_segments = self.segments.iter().map(|s| s.write_segment());
  54. quote! {
  55. {
  56. #(#write_segments)*
  57. }
  58. }
  59. }
  60. pub fn error_ident(&self) -> Ident {
  61. format_ident!("Nest{}ParseError", self.index)
  62. }
  63. pub fn error_variant(&self) -> Ident {
  64. format_ident!("Nest{}", self.index)
  65. }
  66. pub fn error_type(&self) -> TokenStream {
  67. let error_name = self.error_ident();
  68. let mut error_variants = Vec::new();
  69. let mut display_match = Vec::new();
  70. for (i, segment) in self.segments.iter().enumerate() {
  71. let error_name = segment.error_name(i);
  72. match segment {
  73. RouteSegment::Static(index) => {
  74. error_variants.push(quote! { #error_name });
  75. display_match.push(quote! { Self::#error_name => write!(f, "Static segment '{}' did not match", #index)? });
  76. }
  77. RouteSegment::Dynamic(ident, ty) => {
  78. let missing_error = segment.missing_error_name().unwrap();
  79. error_variants.push(quote! { #error_name(<#ty as dioxus_router_core::router::FromRouteSegment>::Err) });
  80. display_match.push(quote! { Self::#error_name(err) => write!(f, "Dynamic segment '({}:{})' did not match: {}", stringify!(#ident), stringify!(#ty), err)? });
  81. error_variants.push(quote! { #missing_error });
  82. display_match.push(quote! { Self::#missing_error => write!(f, "Dynamic segment '({}:{})' was missing", stringify!(#ident), stringify!(#ty))? });
  83. }
  84. _ => todo!(),
  85. }
  86. }
  87. quote! {
  88. #[allow(non_camel_case_types)]
  89. #[derive(Debug, PartialEq)]
  90. pub enum #error_name {
  91. #(#error_variants,)*
  92. }
  93. impl std::fmt::Display for #error_name {
  94. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  95. match self {
  96. #(#display_match,)*
  97. }
  98. Ok(())
  99. }
  100. }
  101. }
  102. }
  103. }