mirror of https://github.com/OISF/suricata
detect/integer: rust derive for enumerations
Ticket: 6647 Allows keywords using integers to use strings in signature parsing based on a rust enumeration with a derive.pull/10277/head
parent
06c5dd3133
commit
370ac05419
@ -0,0 +1,96 @@
|
||||
/* Copyright (C) 2023 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
extern crate proc_macro;
|
||||
use super::applayerevent::transform_name;
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{self, parse_macro_input, DeriveInput};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn derive_enum_string<T: std::str::FromStr + quote::ToTokens>(input: TokenStream, ustr: &str) -> TokenStream where <T as FromStr>::Err: std::fmt::Display {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
let name = input.ident;
|
||||
let mut values = Vec::new();
|
||||
let mut names = Vec::new();
|
||||
let mut fields = Vec::new();
|
||||
|
||||
if let syn::Data::Enum(ref data) = input.data {
|
||||
for v in (&data.variants).into_iter() {
|
||||
if let Some((_, val)) = &v.discriminant {
|
||||
let fname = transform_name(&v.ident.to_string());
|
||||
names.push(fname);
|
||||
fields.push(v.ident.clone());
|
||||
if let syn::Expr::Lit(l) = val {
|
||||
if let syn::Lit::Int(li) = &l.lit {
|
||||
if let Ok(value) = li.base10_parse::<T>() {
|
||||
values.push(value);
|
||||
} else {
|
||||
panic!("EnumString requires explicit {}", ustr);
|
||||
}
|
||||
} else {
|
||||
panic!("EnumString requires explicit literal integer");
|
||||
}
|
||||
} else {
|
||||
panic!("EnumString requires explicit literal");
|
||||
}
|
||||
} else {
|
||||
panic!("EnumString requires explicit values");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
panic!("EnumString can only be derived for enums");
|
||||
}
|
||||
|
||||
let is_suricata = std::env::var("CARGO_PKG_NAME").map(|var| var == "suricata").unwrap_or(false);
|
||||
let crate_id = if is_suricata {
|
||||
syn::Ident::new("crate", proc_macro2::Span::call_site())
|
||||
} else {
|
||||
syn::Ident::new("suricata", proc_macro2::Span::call_site())
|
||||
};
|
||||
|
||||
let utype_str = syn::Ident::new(ustr, proc_macro2::Span::call_site());
|
||||
|
||||
let expanded = quote! {
|
||||
impl #crate_id::detect::EnumString<#utype_str> for #name {
|
||||
fn from_u(v: #utype_str) -> Option<Self> {
|
||||
match v {
|
||||
#( #values => Some(#name::#fields) ,)*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn into_u(self) -> #utype_str {
|
||||
match self {
|
||||
#( #name::#fields => #values ,)*
|
||||
}
|
||||
}
|
||||
fn to_str(&self) -> &'static str {
|
||||
match *self {
|
||||
#( #name::#fields => #names ,)*
|
||||
}
|
||||
}
|
||||
fn from_str(s: &str) -> Option<Self> {
|
||||
match s {
|
||||
#( #names => Some(#name::#fields) ,)*
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
proc_macro::TokenStream::from(expanded)
|
||||
}
|
Loading…
Reference in New Issue