risingwave_common_proc_macro/
config.rs1use bae::FromAttributes;
16use proc_macro_error::{ResultExt, abort};
17use proc_macro2::TokenStream;
18use quote::quote;
19use syn::DeriveInput;
20
21#[derive(FromAttributes)]
22pub struct OverrideOpts {
23 pub path: syn::Expr,
25
26 pub if_absent: Option<()>,
30}
31
32fn type_is_option(ty: &syn::Type) -> bool {
34 if let syn::Type::Path(syn::TypePath { path, .. }) = ty {
35 if let Some(segment) = path.segments.last() {
36 if segment.ident == "Option" {
37 return true;
38 }
39 }
40 }
41 false
42}
43
44pub fn produce_override_config(input: DeriveInput) -> TokenStream {
45 let syn::Data::Struct(syn::DataStruct { fields, .. }) = input.data else {
46 abort!(input, "Only struct is supported");
47 };
48
49 let mut override_stmts = Vec::new();
50
51 for field in fields {
52 let field_type_is_option = type_is_option(&field.ty);
53 let field_ident = field.ident;
54
55 for attr in &field.attrs {
57 let attributes = OverrideOpts::try_from_attributes(std::slice::from_ref(attr))
58 .expect_or_abort("Failed to parse attribute");
59 let Some(OverrideOpts { path, if_absent }) = attributes else {
60 continue;
62 };
63
64 let mut override_stmt = if field_type_is_option {
66 quote! {
67 if let Some(v) = self.#field_ident.clone() {
68 config.#path = v.into();
69 }
70 }
71 } else {
72 quote! {
73 config.#path = self.#field_ident.clone().into();
74 }
75 };
76
77 if if_absent.is_some() {
78 override_stmt = quote! {
79 if config.#path.is_none() {
80 #override_stmt
81 }
82 }
83 }
84
85 override_stmts.push(override_stmt);
86 }
87 }
88
89 let struct_ident = input.ident;
90
91 quote! {
92 impl ::risingwave_common::config::OverrideConfig for #struct_ident {
93 fn r#override(&self, config: &mut ::risingwave_common::config::RwConfig) {
94 #(#override_stmts)*
95 }
96 }
97 }
98}