1mod attr_parsing;
2mod config;
3mod controller;
4mod injectable;
5mod module;
6mod route;
7
8use proc_macro::TokenStream;
9use syn::{parse_macro_input, DeriveInput, Type};
10
11#[proc_macro_attribute]
12pub fn controller(args: TokenStream, input: TokenStream) -> TokenStream {
13 controller::expand(input.into(), args.into())
14 .unwrap_or_else(|e| e)
15 .into()
16}
17
18#[proc_macro_derive(Injectable, attributes(injectable))]
19pub fn injectable(item: TokenStream) -> TokenStream {
20 let item = parse_macro_input!(item as syn::Item);
21
22 injectable::expand(item)
23 .unwrap_or_else(|e| e.into_compile_error().into())
24 .into()
25}
26
27#[proc_macro_derive(Module, attributes(module))]
28pub fn module(item: TokenStream) -> TokenStream {
29 let item = parse_macro_input!(item as DeriveInput);
30
31 module::expand(item)
32 .unwrap_or_else(|e| e.into_compile_error().into())
33 .into()
34}
35
36fn infer_state_types<'a, I>(types: I) -> impl Iterator<Item = Type> + 'a
37where
38 I: Iterator<Item = &'a Type> + 'a,
39{
40 types
41 .filter_map(|ty| {
42 if let Type::Path(path) = ty {
43 Some(&path.path)
44 } else {
45 None
46 }
47 })
48 .filter_map(|path| {
49 if let Some(last_segment) = path.segments.last() {
50 if last_segment.ident != "State" {
51 return None;
52 }
53
54 match &last_segment.arguments {
55 syn::PathArguments::AngleBracketed(args) if args.args.len() == 1 => {
56 Some(args.args.first().unwrap())
57 }
58 _ => None,
59 }
60 } else {
61 None
62 }
63 })
64 .filter_map(|generic_arg| {
65 if let syn::GenericArgument::Type(ty) = generic_arg {
66 Some(ty)
67 } else {
68 None
69 }
70 })
71 .cloned()
72}