diff --git a/Cargo.lock b/Cargo.lock index b3a7608151..9812859e0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1921,7 +1921,6 @@ dependencies = [ "quote", "snafu 0.8.3", "static_assertions", - "syn 1.0.109", "syn 2.0.66", ] diff --git a/src/common/function/src/system/procedure_state.rs b/src/common/function/src/system/procedure_state.rs index 1eeffe63d4..3a15cbd011 100644 --- a/src/common/function/src/system/procedure_state.rs +++ b/src/common/function/src/system/procedure_state.rs @@ -44,10 +44,10 @@ struct ProcedureStateJson { /// A function to query procedure state by its id. /// Such as `procedure_state(pid)`. #[admin_fn( - name = "ProcedureStateFunction", - display_name = "procedure_state", - sig_fn = "signature", - ret = "string" + name = ProcedureStateFunction, + display_name = procedure_state, + sig_fn = signature, + ret = string )] pub(crate) async fn procedure_state( procedure_service_handler: &ProcedureServiceHandlerRef, diff --git a/src/common/function/src/table/flush_compact_region.rs b/src/common/function/src/table/flush_compact_region.rs index 7be1c68a2c..099fe3f86c 100644 --- a/src/common/function/src/table/flush_compact_region.rs +++ b/src/common/function/src/table/flush_compact_region.rs @@ -35,7 +35,7 @@ use crate::helper::cast_u64; macro_rules! define_region_function { ($name: expr, $display_name_str: expr, $display_name: ident) => { /// A function to $display_name - #[admin_fn(name = $name, display_name = $display_name_str, sig_fn = "signature", ret = "uint64")] + #[admin_fn(name = $name, display_name = $display_name_str, sig_fn = signature, ret = uint64)] pub(crate) async fn $display_name( table_mutation_handler: &TableMutationHandlerRef, query_ctx: &QueryContextRef, @@ -53,7 +53,7 @@ macro_rules! define_region_function { let Some(region_id) = cast_u64(¶ms[0])? else { return UnsupportedInputDataTypeSnafu { - function: $display_name_str, + function: stringify!($display_name_str), datatypes: params.iter().map(|v| v.data_type()).collect::>(), } .fail(); @@ -68,9 +68,9 @@ macro_rules! define_region_function { }; } -define_region_function!("FlushRegionFunction", "flush_region", flush_region); +define_region_function!(FlushRegionFunction, flush_region, flush_region); -define_region_function!("CompactRegionFunction", "compact_region", compact_region); +define_region_function!(CompactRegionFunction, compact_region, compact_region); fn signature() -> Signature { Signature::uniform(1, ConcreteDataType::numerics(), Volatility::Immutable) diff --git a/src/common/function/src/table/flush_compact_table.rs b/src/common/function/src/table/flush_compact_table.rs index 968f5a99e8..52837184c2 100644 --- a/src/common/function/src/table/flush_compact_table.rs +++ b/src/common/function/src/table/flush_compact_table.rs @@ -40,10 +40,10 @@ use crate::handlers::TableMutationHandlerRef; const COMPACT_TYPE_STRICT_WINDOW: &str = "strict_window"; #[admin_fn( - name = "FlushTableFunction", - display_name = "flush_table", - sig_fn = "flush_signature", - ret = "uint64" + name = FlushTableFunction, + display_name = flush_table, + sig_fn = flush_signature, + ret = uint64 )] pub(crate) async fn flush_table( table_mutation_handler: &TableMutationHandlerRef, @@ -87,10 +87,10 @@ pub(crate) async fn flush_table( } #[admin_fn( - name = "CompactTableFunction", - display_name = "compact_table", - sig_fn = "compact_signature", - ret = "uint64" + name = CompactTableFunction, + display_name = compact_table, + sig_fn = compact_signature, + ret = uint64 )] pub(crate) async fn compact_table( table_mutation_handler: &TableMutationHandlerRef, diff --git a/src/common/function/src/table/migrate_region.rs b/src/common/function/src/table/migrate_region.rs index b208b258d7..88e9516943 100644 --- a/src/common/function/src/table/migrate_region.rs +++ b/src/common/function/src/table/migrate_region.rs @@ -46,10 +46,10 @@ const DEFAULT_REPLAY_TIMEOUT_SECS: u64 = 10; /// - `from_peer`: the source peer id /// - `to_peer`: the target peer id #[admin_fn( - name = "MigrateRegionFunction", - display_name = "migrate_region", - sig_fn = "signature", - ret = "string" + name = MigrateRegionFunction, + display_name = migrate_region, + sig_fn = signature, + ret = string )] pub(crate) async fn migrate_region( procedure_service_handler: &ProcedureServiceHandlerRef, diff --git a/src/common/macro/Cargo.toml b/src/common/macro/Cargo.toml index 64080739aa..d474d4b5e9 100644 --- a/src/common/macro/Cargo.toml +++ b/src/common/macro/Cargo.toml @@ -13,8 +13,7 @@ workspace = true [dependencies] proc-macro2 = "1.0.66" quote = "1.0" -syn = "1.0" -syn2 = { version = "2.0", package = "syn", features = [ +syn = { version = "2.0", features = [ "derive", "parsing", "printing", diff --git a/src/common/macro/src/admin_fn.rs b/src/common/macro/src/admin_fn.rs index 3faa06d933..be6b77a5eb 100644 --- a/src/common/macro/src/admin_fn.rs +++ b/src/common/macro/src/admin_fn.rs @@ -16,11 +16,11 @@ use proc_macro::TokenStream; use quote::quote; use syn::spanned::Spanned; use syn::{ - parse_macro_input, Attribute, AttributeArgs, Ident, ItemFn, Signature, Type, TypePath, - TypeReference, Visibility, + parse_macro_input, Attribute, Ident, ItemFn, Signature, Type, TypePath, TypeReference, + Visibility, }; -use crate::utils::{extract_arg_map, extract_input_types, get_ident}; +use crate::utils::extract_input_types; /// Internal util macro to early return on error. macro_rules! ok { @@ -40,12 +40,31 @@ macro_rules! error { } pub(crate) fn process_admin_fn(args: TokenStream, input: TokenStream) -> TokenStream { - let mut result = TokenStream::new(); + let mut name: Option = None; + let mut display_name: Option = None; + let mut sig_fn: Option = None; + let mut ret: Option = None; + + let parser = syn::meta::parser(|meta| { + if meta.path.is_ident("name") { + name = Some(meta.value()?.parse()?); + Ok(()) + } else if meta.path.is_ident("display_name") { + display_name = Some(meta.value()?.parse()?); + Ok(()) + } else if meta.path.is_ident("sig_fn") { + sig_fn = Some(meta.value()?.parse()?); + Ok(()) + } else if meta.path.is_ident("ret") { + ret = Some(meta.value()?.parse()?); + Ok(()) + } else { + Err(meta.error("unsupported property")) + } + }); // extract arg map - let arg_pairs = parse_macro_input!(args as AttributeArgs); - let arg_span = arg_pairs[0].span(); - let arg_map = ok!(extract_arg_map(arg_pairs)); + parse_macro_input!(args with parser); // decompose the fn block let compute_fn = parse_macro_input!(input as ItemFn); @@ -72,16 +91,17 @@ pub(crate) fn process_admin_fn(args: TokenStream, input: TokenStream) -> TokenSt } let handler_type = ok!(extract_handler_type(&arg_types)); + let mut result = TokenStream::new(); // build the struct and its impl block // only do this when `display_name` is specified - if let Ok(display_name) = get_ident(&arg_map, "display_name", arg_span) { + if let Some(display_name) = display_name { let struct_code = build_struct( attrs, vis, fn_name, - ok!(get_ident(&arg_map, "name", arg_span)), - ok!(get_ident(&arg_map, "sig_fn", arg_span)), - ok!(get_ident(&arg_map, "ret", arg_span)), + name.expect("name required"), + sig_fn.expect("sig_fn required"), + ret.expect("ret required"), handler_type, display_name, ); diff --git a/src/common/macro/src/print_caller.rs b/src/common/macro/src/print_caller.rs index c4510ddfa9..7b6b012b48 100644 --- a/src/common/macro/src/print_caller.rs +++ b/src/common/macro/src/print_caller.rs @@ -14,28 +14,24 @@ use proc_macro::TokenStream; use quote::{quote, ToTokens}; -use syn::{parse_macro_input, AttributeArgs, ItemFn, Lit, Meta, NestedMeta}; +use syn::{parse_macro_input, ItemFn, LitInt}; pub(crate) fn process_print_caller(args: TokenStream, input: TokenStream) -> TokenStream { let mut depth = 1; - - let args = parse_macro_input!(args as AttributeArgs); - for meta in args.iter() { - if let NestedMeta::Meta(Meta::NameValue(name_value)) = meta { - let ident = name_value - .path - .get_ident() - .expect("Expected an ident!") - .to_string(); - if ident == "depth" { - let Lit::Int(i) = &name_value.lit else { - panic!("Expected 'depth' to be a valid int!") - }; - depth = i.base10_parse::().expect("Invalid 'depth' value"); - break; - } + let parser = syn::meta::parser(|meta| { + if meta.path.is_ident("depth") { + depth = meta + .value()? + .parse::() + .and_then(|v| v.base10_parse::()) + .expect("Invalid 'depth' value"); + Ok(()) + } else { + Err(meta.error("unsupported property")) } - } + }); + + parse_macro_input!(args with parser); let tokens: TokenStream = quote! { { diff --git a/src/common/macro/src/range_fn.rs b/src/common/macro/src/range_fn.rs index ce68e8aaee..882de64aa4 100644 --- a/src/common/macro/src/range_fn.rs +++ b/src/common/macro/src/range_fn.rs @@ -16,11 +16,10 @@ use proc_macro::TokenStream; use quote::quote; use syn::spanned::Spanned; use syn::{ - parse_macro_input, Attribute, AttributeArgs, Ident, ItemFn, Signature, Type, TypeReference, - Visibility, + parse_macro_input, Attribute, Ident, ItemFn, Signature, Type, TypeReference, Visibility, }; -use crate::utils::{extract_arg_map, extract_input_types, get_ident}; +use crate::utils::extract_input_types; macro_rules! ok { ($item:expr) => { @@ -32,12 +31,27 @@ macro_rules! ok { } pub(crate) fn process_range_fn(args: TokenStream, input: TokenStream) -> TokenStream { - let mut result = TokenStream::new(); + let mut name: Option = None; + let mut display_name: Option = None; + let mut ret: Option = None; + + let parser = syn::meta::parser(|meta| { + if meta.path.is_ident("name") { + name = Some(meta.value()?.parse()?); + Ok(()) + } else if meta.path.is_ident("display_name") { + display_name = Some(meta.value()?.parse()?); + Ok(()) + } else if meta.path.is_ident("ret") { + ret = Some(meta.value()?.parse()?); + Ok(()) + } else { + Err(meta.error("unsupported property")) + } + }); // extract arg map - let arg_pairs = parse_macro_input!(args as AttributeArgs); - let arg_span = arg_pairs[0].span(); - let arg_map = ok!(extract_arg_map(arg_pairs)); + parse_macro_input!(args with parser); // decompose the fn block let compute_fn = parse_macro_input!(input as ItemFn); @@ -68,25 +82,27 @@ pub(crate) fn process_range_fn(args: TokenStream, input: TokenStream) -> TokenSt }) .collect::>(); + let mut result = TokenStream::new(); + // build the struct and its impl block // only do this when `display_name` is specified - if let Ok(display_name) = get_ident(&arg_map, "display_name", arg_span) { + if let Some(display_name) = display_name { let struct_code = build_struct( attrs, vis, - ok!(get_ident(&arg_map, "name", arg_span)), + name.clone().expect("name required"), display_name, array_types, - ok!(get_ident(&arg_map, "ret", arg_span)), + ret.clone().expect("ret required"), ); result.extend(struct_code); } let calc_fn_code = build_calc_fn( - ok!(get_ident(&arg_map, "name", arg_span)), + name.expect("name required"), arg_types, fn_name.clone(), - ok!(get_ident(&arg_map, "ret", arg_span)), + ret.expect("ret required"), ); // preserve this fn, but remove its `pub` modifier let input_fn_code: TokenStream = quote! { diff --git a/src/common/macro/src/stack_trace_debug.rs b/src/common/macro/src/stack_trace_debug.rs index 2e6f2d1594..fbc24260f1 100644 --- a/src/common/macro/src/stack_trace_debug.rs +++ b/src/common/macro/src/stack_trace_debug.rs @@ -16,13 +16,13 @@ use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::{quote, quote_spanned}; -use syn2::spanned::Spanned; -use syn2::{parenthesized, Attribute, Ident, ItemEnum, Variant}; +use syn::spanned::Spanned; +use syn::{parenthesized, Attribute, Ident, ItemEnum, Variant}; pub fn stack_trace_style_impl(args: TokenStream2, input: TokenStream2) -> TokenStream2 { let input_cloned: TokenStream2 = input.clone(); - let error_enum_definition: ItemEnum = syn2::parse2(input_cloned).unwrap(); + let error_enum_definition: ItemEnum = syn::parse2(input_cloned).unwrap(); let enum_name = error_enum_definition.ident; let mut variants = vec![]; diff --git a/src/common/macro/src/utils.rs b/src/common/macro/src/utils.rs index a4587092ef..7c8f3bd775 100644 --- a/src/common/macro/src/utils.rs +++ b/src/common/macro/src/utils.rs @@ -12,48 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::HashMap; - -use proc_macro2::Span; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Comma; -use syn::{FnArg, Ident, Meta, MetaNameValue, NestedMeta, Type}; - -/// Extract a String <-> Ident map from the attribute args. -pub(crate) fn extract_arg_map(args: Vec) -> Result, syn::Error> { - args.into_iter() - .map(|meta| { - if let NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, lit, .. })) = meta { - let name = path.get_ident().unwrap().to_string(); - let ident = match lit { - syn::Lit::Str(lit_str) => lit_str.parse::(), - _ => Err(syn::Error::new( - lit.span(), - "Unexpected attribute format. Expected `name = \"value\"`", - )), - }?; - Ok((name, ident)) - } else { - Err(syn::Error::new( - meta.span(), - "Unexpected attribute format. Expected `name = \"value\"`", - )) - } - }) - .collect::, syn::Error>>() -} - -/// Helper function to get an Ident from the previous arg map. -pub(crate) fn get_ident( - map: &HashMap, - key: &str, - span: Span, -) -> Result { - map.get(key) - .cloned() - .ok_or_else(|| syn::Error::new(span, format!("Expect attribute {key} but not found"))) -} +use syn::{FnArg, Type}; /// Extract the argument list from the annotated function. pub(crate) fn extract_input_types( diff --git a/src/promql/src/functions/aggr_over_time.rs b/src/promql/src/functions/aggr_over_time.rs index a653e1942e..298959ef35 100644 --- a/src/promql/src/functions/aggr_over_time.rs +++ b/src/promql/src/functions/aggr_over_time.rs @@ -28,9 +28,9 @@ use crate::range_array::RangeArray; /// The average value of all points in the specified interval. #[range_fn( - name = "AvgOverTime", - ret = "Float64Array", - display_name = "prom_avg_over_time" + name = AvgOverTime, + ret = Float64Array, + display_name = prom_avg_over_time )] pub fn avg_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { compute::sum(values).map(|result| result / values.len() as f64) @@ -38,9 +38,9 @@ pub fn avg_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Op /// The minimum value of all points in the specified interval. #[range_fn( - name = "MinOverTime", - ret = "Float64Array", - display_name = "prom_min_over_time" + name = MinOverTime, + ret = Float64Array, + display_name = prom_min_over_time )] pub fn min_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { compute::min(values) @@ -48,9 +48,9 @@ pub fn min_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Op /// The maximum value of all points in the specified interval. #[range_fn( - name = "MaxOverTime", - ret = "Float64Array", - display_name = "prom_max_over_time" + name = MaxOverTime, + ret = Float64Array, + display_name = prom_max_over_time )] pub fn max_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { compute::max(values) @@ -58,9 +58,9 @@ pub fn max_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Op /// The sum of all values in the specified interval. #[range_fn( - name = "SumOverTime", - ret = "Float64Array", - display_name = "prom_sum_over_time" + name = SumOverTime, + ret = Float64Array, + display_name = prom_sum_over_time )] pub fn sum_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { compute::sum(values) @@ -68,9 +68,9 @@ pub fn sum_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Op /// The count of all values in the specified interval. #[range_fn( - name = "CountOverTime", - ret = "Float64Array", - display_name = "prom_count_over_time" + name = CountOverTime, + ret = Float64Array, + display_name = prom_count_over_time )] pub fn count_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { @@ -82,9 +82,9 @@ pub fn count_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> /// The most recent point value in specified interval. #[range_fn( - name = "LastOverTime", - ret = "Float64Array", - display_name = "prom_last_over_time" + name = LastOverTime, + ret = Float64Array, + display_name = prom_last_over_time )] pub fn last_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { values.values().last().copied() @@ -94,9 +94,9 @@ pub fn last_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> O /// elements (floats or native histograms) and a 1-element vector with the value 1 if /// the range vector passed to it has no elements. #[range_fn( - name = "AbsentOverTime", - ret = "Float64Array", - display_name = "prom_absent_over_time" + name = AbsentOverTime, + ret = Float64Array, + display_name = prom_absent_over_time )] pub fn absent_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { @@ -108,9 +108,9 @@ pub fn absent_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> /// the value 1 for any series in the specified interval. #[range_fn( - name = "PresentOverTime", - ret = "Float64Array", - display_name = "prom_present_over_time" + name = PresentOverTime, + ret = Float64Array, + display_name = prom_present_over_time )] pub fn present_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { @@ -124,9 +124,9 @@ pub fn present_over_time(_: &TimestampMillisecondArray, values: &Float64Array) - /// DataFusion's implementation: /// #[range_fn( - name = "StdvarOverTime", - ret = "Float64Array", - display_name = "prom_stdvar_over_time" + name = StdvarOverTime, + ret = Float64Array, + display_name = prom_stdvar_over_time )] pub fn stdvar_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { @@ -154,9 +154,9 @@ pub fn stdvar_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> /// the population standard deviation of the values in the specified interval. /// Prometheus's implementation: #[range_fn( - name = "StddevOverTime", - ret = "Float64Array", - display_name = "prom_stddev_over_time" + name = StddevOverTime, + ret = Float64Array, + display_name = prom_stddev_over_time )] pub fn stddev_over_time(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { diff --git a/src/promql/src/functions/changes.rs b/src/promql/src/functions/changes.rs index d10b6f2165..743f941652 100644 --- a/src/promql/src/functions/changes.rs +++ b/src/promql/src/functions/changes.rs @@ -29,7 +29,7 @@ use crate::functions::extract_array; use crate::range_array::RangeArray; /// used to count the number of value changes that occur within a specific time range -#[range_fn(name = "Changes", ret = "Float64Array", display_name = "prom_changes")] +#[range_fn(name = Changes, ret = Float64Array, display_name = prom_changes)] pub fn changes(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { None diff --git a/src/promql/src/functions/deriv.rs b/src/promql/src/functions/deriv.rs index 9a7b9d1e45..90b09f0d40 100644 --- a/src/promql/src/functions/deriv.rs +++ b/src/promql/src/functions/deriv.rs @@ -28,7 +28,7 @@ use datatypes::arrow::datatypes::DataType; use crate::functions::{extract_array, linear_regression}; use crate::range_array::RangeArray; -#[range_fn(name = "Deriv", ret = "Float64Array", display_name = "prom_deriv")] +#[range_fn(name = Deriv, ret = Float64Array, display_name = prom_deriv)] pub fn deriv(times: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.len() < 2 { None diff --git a/src/promql/src/functions/resets.rs b/src/promql/src/functions/resets.rs index a63ef7a99f..7df44b5e76 100644 --- a/src/promql/src/functions/resets.rs +++ b/src/promql/src/functions/resets.rs @@ -29,7 +29,7 @@ use crate::functions::extract_array; use crate::range_array::RangeArray; /// used to count the number of times the time series starts over. -#[range_fn(name = "Resets", ret = "Float64Array", display_name = "prom_resets")] +#[range_fn(name = Resets, ret = Float64Array, display_name = prom_resets)] pub fn resets(_: &TimestampMillisecondArray, values: &Float64Array) -> Option { if values.is_empty() { None