rglw_codegen_utils/generics/
macro_attribute_function_arguments.rs1use proc_macro2::{Ident, Span, TokenStream};
2use quote::{quote, ToTokens};
3use syn::{FnArg, GenericArgument, ItemFn, Pat, PathArguments, PathSegment, Type};
4use crate::generics::get_type_path_segments;
5
6#[derive(Clone)]
7pub struct MacroAttributeFunctionArgument {
8 _raw: FnArg,
9 _field_name: String,
10 type_name: String,
11 argument_type: Type
12}
13
14#[derive(Clone)]
15pub struct MacroAttributeFunctionArguments {
16 arguments: Vec<MacroAttributeFunctionArgument>
17}
18
19pub fn get_function_argument_type(argument: FnArg) -> Type {
20 match argument {
21 FnArg::Receiver(receiver) => {
22 *receiver.ty.clone()
23 }
24 FnArg::Typed(typed) => {
25 *typed.ty.clone()
26 },
27 }
28}
29
30pub fn get_function_argument_field_name(argument: FnArg) -> String {
31 match argument {
32 FnArg::Receiver(_receiver) => "self".to_string(),
33 FnArg::Typed(typed) => {
34 match *typed.pat {
35 Pat::Ident(pat_ident) => {
36 pat_ident.ident.to_string()
37 },
38 _=> {
39 panic!("Argument type not supported!");
40 }
41 }
42 },
43 }
44}
45
46pub fn get_function_type_name(argument: FnArg) -> String {
47 match argument {
48 FnArg::Receiver(receiver) => {
49 receiver.ty.to_token_stream().to_string()
50 }
51 FnArg::Typed(typed) => {
52 typed.ty.clone().to_token_stream().to_string()
53 },
54 }
55}
56
57impl MacroAttributeFunctionArguments {
58 pub fn parse(input: &ItemFn) -> MacroAttributeFunctionArguments {
59 let mut arguments: Vec<MacroAttributeFunctionArgument> = Vec::new();
60 for argument in input.sig.inputs.clone() {
61 arguments.push(MacroAttributeFunctionArgument {
62 _raw: argument.clone(),
63 _field_name: get_function_argument_field_name(argument.clone()),
64 type_name: get_function_type_name(argument.clone()),
65 argument_type: get_function_argument_type(argument.clone()),
66 });
67 }
68 MacroAttributeFunctionArguments {
69 arguments,
70 }
71 }
72
73 pub fn get_path_segment_by_type_name(&self, type_name: &str) -> Option<PathSegment> {
74 let mut result: Option<PathSegment> = None;
75 for argument in self.arguments.clone() {
76 let segments = get_type_path_segments(argument.argument_type);
77 for segment in segments {
78 if segment.ident.to_string().eq(type_name) {
79 result = Some(segment.clone());
80 }
81 }
82 }
83 result
84 }
85
86 pub fn get_path_arguments_by_type_name(&self, type_name: &str) -> Option<PathArguments> {
87 let mut result: Option<PathArguments> = None;
88 for argument in self.arguments.clone() {
89 let segments = get_type_path_segments(argument.argument_type);
90 for segment in segments {
91 if segment.ident.to_string().eq(type_name) {
92 result = Some(segment.clone().arguments);
93 }
94 }
95 }
96 result
97 }
98
99 pub fn get_stream_of_argument_by_name(&self, container_type_name: &str) -> Option<TokenStream> {
100 let mut result: Option<TokenStream> = None;
101 let response_type_segment = self.get_path_segment_by_type_name(container_type_name).unwrap();
102 if response_type_segment.arguments.is_empty() {
103 panic!("Stream has to contain a generic type!");
104 }
105 let type_arguments = response_type_segment.arguments;
106 if let PathArguments::AngleBracketed(generic_arguments) = type_arguments {
107 let generic_arguments = generic_arguments.args.to_token_stream();
108 result = Some(quote! {
109 #generic_arguments
110 });
111 }
112 result
113 }
114
115 pub fn get_stream_of_argument_without_generics_by_name(&self, container_type_name: &str) -> Option<TokenStream> {
116 let mut result: Option<TokenStream> = None;
117 let response_type_segment = self.get_path_segment_by_type_name(container_type_name).unwrap();
118 if response_type_segment.arguments.is_empty() {
119 panic!("Stream has to contain a generic type!");
120 }
121 let type_arguments = response_type_segment.arguments;
122 if let PathArguments::AngleBracketed(generic_arguments) = type_arguments {
123 let generic_argument = generic_arguments.args.first()?;
124 if let GenericArgument::Type(Type::Path(type_path)) = generic_argument {
125 let generic_argument = type_path.path.segments.first()?.ident.to_token_stream();
126 result = Some(quote! {
127 #generic_argument
128 });
129 }
130 }
131 result
132 }
133
134 pub fn get_injectable_arguments(&self) -> Vec<TokenStream> {
135 let mut result: Vec<TokenStream> = Vec::new();
136 if self.arguments.len() > 2 {
137 let injectable_arguments = self.arguments[2..].to_vec();
138 for injectable_argument in injectable_arguments {
139 let injectable = Ident::new(injectable_argument.type_name.as_str(), Span::call_site());
140 result.push(quote! {
141 #injectable::inject().await.unwrap(),
142 });
143 }
144 }
145 result
146 }
147}