freya_router_macro/
nest.rs

1use 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        // Parse the route
34        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}