hash.rs 1.7 KB

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