freya_router_macro/
hash.rs1use proc_macro2::TokenStream as TokenStream2;
2use quote::quote;
3use syn::{
4 Ident,
5 Type,
6};
7
8#[derive(Debug)]
9pub struct HashFragment {
10 pub ident: Ident,
11 pub ty: Type,
12}
13
14impl HashFragment {
15 pub fn contains_ident(&self, ident: &Ident) -> bool {
16 self.ident == *ident
17 }
18
19 pub fn parse(&self) -> TokenStream2 {
20 let ident = &self.ident;
21 let ty = &self.ty;
22 quote! {
23 let #ident = <#ty as freya_router::routable::FromHashFragment>::from_hash_fragment(&*hash);
24 }
25 }
26
27 pub fn write(&self) -> TokenStream2 {
28 let ident = &self.ident;
29 quote! {
30 {
31 let __hash = #ident.to_string();
32 if !__hash.is_empty() {
33 write!(f, "#{}", __hash)?;
34 }
35 }
36 }
37 }
38
39 pub fn parse_from_str<'a>(
40 route_span: proc_macro2::Span,
41 mut fields: impl Iterator<Item = (&'a Ident, &'a Type)>,
42 hash: &str,
43 ) -> syn::Result<Self> {
44 let Some(hash) = hash.strip_prefix(':') else {
46 return Err(syn::Error::new(
47 route_span,
48 "Failed to parse `:`. Hash fragments must be in the format '#:<field>'",
49 ));
50 };
51
52 let hash_ident = Ident::new(hash, proc_macro2::Span::call_site());
53 let field = fields.find(|(name, _)| *name == &hash_ident);
54
55 let ty = if let Some((_, ty)) = field {
56 ty.clone()
57 } else {
58 return Err(syn::Error::new(
59 route_span,
60 format!("Could not find a field with the name '{hash_ident}'",),
61 ));
62 };
63
64 Ok(Self {
65 ident: hash_ident,
66 ty,
67 })
68 }
69}