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
44#[cfg_attr(coverage, coverage(off))]
45pub fn produce_override_config(input: DeriveInput) -> TokenStream {
46 let syn::Data::Struct(syn::DataStruct { fields, .. }) = input.data else {
47 abort!(input, "Only struct is supported");
48 };
49
50 let mut override_stmts = Vec::new();
51
52 for field in fields {
53 let field_type_is_option = type_is_option(&field.ty);
54 let field_ident = field.ident;
55
56 for attr in &field.attrs {
58 let attributes = OverrideOpts::try_from_attributes(std::slice::from_ref(attr))
59 .expect_or_abort("Failed to parse attribute");
60 let Some(OverrideOpts { path, if_absent }) = attributes else {
61 continue;
63 };
64
65 let mut override_stmt = if field_type_is_option {
67 quote! {
68 if let Some(v) = self.#field_ident.clone() {
69 config.#path = v.into();
70 }
71 }
72 } else {
73 quote! {
74 config.#path = self.#field_ident.clone().into();
75 }
76 };
77
78 if if_absent.is_some() {
79 override_stmt = quote! {
80 if config.#path.is_none() {
81 #override_stmt
82 }
83 }
84 }
85
86 override_stmts.push(override_stmt);
87 }
88 }
89
90 let struct_ident = input.ident;
91
92 quote! {
93 impl ::risingwave_common::config::OverrideConfig for #struct_ident {
94 fn r#override(&self, config: &mut ::risingwave_common::config::RwConfig) {
95 #(#override_stmts)*
96 }
97 }
98 }
99}