1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{
4 parse::{Parse, ParseStream},
5 parse_macro_input, AttrStyle, Attribute, FieldsNamed, Ident, Token, Visibility,
6};
7
8struct Structure {
9 attrs: Vec<Attribute>,
10 visibility: Visibility,
11 _struct_token: Token![struct],
12 name: Ident,
13 fields: FieldsNamed,
14}
15
16impl Parse for Structure {
17 fn parse(input: ParseStream) -> syn::Result<Self> {
18 Ok(Structure {
19 attrs: input.call(Attribute::parse_outer)?,
20 visibility: input.parse()?,
21 _struct_token: input.parse()?,
22 name: input.parse()?,
23 fields: input.parse()?,
24 })
25 }
26}
27
28fn attr_has_streaming_name(attr: &Attribute) -> bool {
29 attr.style == AttrStyle::Outer && attr.path.is_ident("streaming")
30}
31
32#[proc_macro_attribute]
33pub fn streaming(_attr: TokenStream, item: TokenStream) -> TokenStream {
34 item
35}
36
37#[proc_macro]
38pub fn options(input: TokenStream) -> TokenStream {
39 let input = parse_macro_input!(input as Structure);
40
41 let fields = input.fields.named.iter().map(|field| {
42 let attrs = if field.attrs.is_empty() {
43 quote! {}
44 } else {
45 let attrs = field.attrs.iter().map(|attr| quote! { #attr });
46 quote! {
47 #(#attrs)*
48 }
49 };
50
51 let vis = &field.vis;
52 let name = &field.ident;
53 let ty = &field.ty;
54
55 quote! {
56 #attrs
57 #vis #name: #ty,
58 }
59 });
60
61 let is_streaming = input.attrs.iter().any(attr_has_streaming_name);
62
63 let kind = if is_streaming {
64 quote! {
65 crate::options::OperationKind::Streaming
66 }
67 } else {
68 quote! {
69 crate::options::OperationKind::Regular
70 }
71 };
72
73 let attrs = input.attrs.iter().map(|attr| quote! { #attr });
74 let vis = &input.visibility;
75 let name = input.name;
76
77 TokenStream::from(quote! {
78 #(#attrs)*
79 #vis struct #name {
80 #(#fields)*
81 pub(crate) common_operation_options: crate::options::CommonOperationOptions,
82 }
83
84 impl crate::options::Options for #name {
85 fn common_operation_options(&self) -> &crate::options::CommonOperationOptions {
86 &self.common_operation_options
87 }
88
89 fn kind(&self) -> crate::options::OperationKind {
90 #kind
91 }
92 }
93
94 impl #name {
95 pub fn authenticated(mut self, credentials: crate::types::Credentials) -> Self {
97 self.common_operation_options.credentials = Some(credentials);
98 self
99 }
100
101 pub fn requires_leader(mut self, requires_leader: bool) -> Self {
102 self.common_operation_options.requires_leader = requires_leader;
103 self
104 }
105
106 pub fn deadline(mut self, deadline: std::time::Duration) -> Self {
107 self.common_operation_options.deadline = Some(deadline);
108 self
109 }
110 }
111 })
112}