Import upstream v0.16.22, stripped
Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "event_macro"
|
||||
version = "0.16.22"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "3.0", features = ["full"] }
|
||||
quote = "1.0"
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
||||
*/
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{Data, DeriveInput, Expr, ExprPath, Ident, Token, parse::Parse, parse_macro_input};
|
||||
|
||||
static mut GLOBAL_ID_COUNTER: usize = 0;
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn key_names(_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(item as DeriveInput);
|
||||
let name = &input.ident;
|
||||
|
||||
let enum_variants = match &input.data {
|
||||
Data::Enum(data_enum) => &data_enum.variants,
|
||||
_ => panic!("This macro only works with enums"),
|
||||
};
|
||||
|
||||
let mut variant_names = Vec::new();
|
||||
let mut camel_case_names = Vec::new();
|
||||
let mut snake_case_names = Vec::new();
|
||||
|
||||
for variant in enum_variants.iter() {
|
||||
let variant_name = &variant.ident;
|
||||
variant_names.push(variant_name);
|
||||
snake_case_names.push(to_snake_case(&variant_name.to_string()));
|
||||
camel_case_names.push(
|
||||
variant_name
|
||||
.to_string()
|
||||
.char_indices()
|
||||
.map(|(i, c)| if i == 0 { c.to_ascii_lowercase() } else { c })
|
||||
.collect::<String>(),
|
||||
);
|
||||
}
|
||||
|
||||
let id_fn = quote! {
|
||||
pub fn id(&self) -> &'static str {
|
||||
match self {
|
||||
#(Self::#variant_names => #snake_case_names,)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let name_fn = quote! {
|
||||
pub fn name(&self) -> &'static str {
|
||||
match self {
|
||||
#(Self::#variant_names => #camel_case_names,)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let parse_fn = quote! {
|
||||
pub fn try_parse(name: &str) -> Option<Self> {
|
||||
match name {
|
||||
#(#camel_case_names => Some(Self::#variant_names),)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#input
|
||||
|
||||
impl #name {
|
||||
#name_fn
|
||||
#id_fn
|
||||
#parse_fn
|
||||
}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn total_event_count(_item: TokenStream) -> TokenStream {
|
||||
let count = unsafe { GLOBAL_ID_COUNTER };
|
||||
let expanded = quote! {
|
||||
#count
|
||||
};
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
fn to_snake_case(name: &str) -> String {
|
||||
let mut out = String::with_capacity(name.len());
|
||||
for (idx, ch) in name.char_indices() {
|
||||
if ch.is_ascii_uppercase() {
|
||||
if idx > 0 {
|
||||
out.push('-');
|
||||
}
|
||||
out.push(ch.to_ascii_lowercase());
|
||||
} else {
|
||||
out.push(ch);
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
struct EventMacroInput {
|
||||
event: Ident,
|
||||
param: Expr,
|
||||
key_values: Vec<(Ident, Expr)>,
|
||||
}
|
||||
|
||||
impl Parse for EventMacroInput {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let event: Ident = input.parse()?;
|
||||
let content;
|
||||
syn::parenthesized!(content in input);
|
||||
let param: Expr = content.parse()?;
|
||||
|
||||
let mut key_values = Vec::new();
|
||||
while !input.is_empty() {
|
||||
input.parse::<Token![,]>()?;
|
||||
if input.is_empty() {
|
||||
break;
|
||||
}
|
||||
let key: Ident = input.parse()?;
|
||||
input.parse::<Token![=]>()?;
|
||||
let value: Expr = input.parse()?;
|
||||
key_values.push((key, value));
|
||||
}
|
||||
|
||||
Ok(EventMacroInput {
|
||||
event,
|
||||
param,
|
||||
key_values,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn event(input: TokenStream) -> TokenStream {
|
||||
let EventMacroInput {
|
||||
event,
|
||||
param,
|
||||
key_values,
|
||||
} = parse_macro_input!(input as EventMacroInput);
|
||||
|
||||
let key_value_tokens = key_values.iter().map(|(key, value)| {
|
||||
quote! {
|
||||
(trc::Key::#key, trc::Value::from(#value))
|
||||
}
|
||||
});
|
||||
// This avoids having to evaluate expensive values when we know we are not interested in the event
|
||||
let key_value_metric_tokens = key_values.iter().filter_map(|(key, value)| {
|
||||
if key.is_metric_key() {
|
||||
Some(quote! {
|
||||
(trc::Key::#key, trc::Value::from(#value))
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let expanded = if matches!(¶m, Expr::Path(ExprPath { path, .. }) if path.segments.len() > 1 && path.segments.last().unwrap().arguments.is_empty() )
|
||||
{
|
||||
quote! {{
|
||||
const ET: trc::EventType = trc::EventType::#event(#param);
|
||||
const ET_ID: usize = ET.to_id() as usize;
|
||||
if trc::Collector::has_interest(ET_ID) {
|
||||
let keys = vec![#(#key_value_tokens),*];
|
||||
if trc::Collector::is_metric(ET_ID) {
|
||||
trc::Collector::record_metric(ET, ET_ID, &keys);
|
||||
}
|
||||
trc::Event::with_keys(ET, keys).send();
|
||||
} else if trc::Collector::is_metric(ET_ID) {
|
||||
trc::Collector::record_metric(ET, ET_ID, &[#(#key_value_metric_tokens),*]);
|
||||
}
|
||||
}}
|
||||
} else {
|
||||
quote! {{
|
||||
let et = trc::EventType::#event(#param);
|
||||
let et_id = et.to_id() as usize;
|
||||
if trc::Collector::has_interest(et_id) {
|
||||
let keys = vec![#(#key_value_tokens),*];
|
||||
if trc::Collector::is_metric(et_id) {
|
||||
trc::Collector::record_metric(et, et_id, &keys);
|
||||
}
|
||||
trc::Event::with_keys(et, keys).send();
|
||||
} else if trc::Collector::is_metric(et_id) {
|
||||
trc::Collector::record_metric(et, et_id, &[#(#key_value_metric_tokens),*]);
|
||||
}
|
||||
}}
|
||||
};
|
||||
|
||||
TokenStream::from(expanded)
|
||||
}
|
||||
|
||||
trait IsMetricKey {
|
||||
fn is_metric_key(&self) -> bool;
|
||||
}
|
||||
|
||||
impl IsMetricKey for Ident {
|
||||
fn is_metric_key(&self) -> bool {
|
||||
matches!(
|
||||
self.to_string().as_ref(),
|
||||
"Total"
|
||||
| "Elapsed"
|
||||
| "Size"
|
||||
| "TotalSuccesses"
|
||||
| "TotalFailures"
|
||||
| "DmarcPass"
|
||||
| "DmarcQuarantine"
|
||||
| "DmarcReject"
|
||||
| "DmarcNone"
|
||||
| "DkimPass"
|
||||
| "DkimFail"
|
||||
| "DkimNone"
|
||||
| "SpfPass"
|
||||
| "SpfFail"
|
||||
| "SpfNone"
|
||||
| "Protocol"
|
||||
| "Code"
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user