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