@ -15,14 +15,75 @@
* 02110 - 1301 , USA .
* /
//! String-enumeration derive macro
/*
String enumeration allows a compact representation , and ensure that
there is no discrepancy between what is logged , and what can be parser
in signature keywords .
Usage : just derive EnumStringUX with X being the number of bits used in repr
#[ derive(EnumStringU8) ]
#[ repr(u8) ]
pub enum ExampleEnum {
Zero = 0 ,
BestValueEver = 42 ,
}
Then , get 4 functions to translate from u8 < -> ExampleEnum < -> string
- from_u : takes an unsigned and return an Option < ExampleEnum >
- into_u : takes an ExampleEnum and return an unsigned
- from_str : takes a string and return an Option < ExampleEnum >
- into_str : takes an ExampleEnum and return a string ( & ' static str )
Case :
snake_case is used by default :
ExampleEnum ::BestValueEver . to_str ( ) is "best_value_ever"
Strings parsed to get an enumeration value are case insensitive
Parameters :
The enum can have a suricata attribute , which is a list of named values
- enum_string_style can be :
- UPPERCASE : uppercase is used for logging and parsing
- LOG_UPPERCASE : uppercase is only used for logging , snake_case for parsing
With UPPERCASE
ExampleEnum ::BestValueEver . to_str ( ) is "BESTVALUEEVER" ( without underscores )
* /
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 ;
use syn ::{ self , parse_macro_input , DeriveInput } ;
fn get_attr_enum_string_style ( attr : & syn ::Attribute ) -> String {
let meta = attr . parse_meta ( ) . unwrap ( ) ;
if let syn ::Meta ::List ( l ) = meta {
for n in l . nested {
if let syn ::NestedMeta ::Meta ( syn ::Meta ::NameValue ( nv ) ) = n {
if nv . path . is_ident ( "enum_string_style" ) {
if let syn ::Lit ::Str ( s ) = nv . lit {
return s . value ( ) ;
}
panic! ( "enum_string_style invalid syntax" ) ;
}
}
}
panic! ( "no enum_string_style" ) ;
}
panic! ( "suricata attribute is not a list" ) ;
}
pub fn derive_enum_string < T : std ::str ::FromStr + quote ::ToTokens > ( input : TokenStream , ustr : & str ) -> TokenStream where < T as FromStr > ::Err : std ::fmt ::Display {
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 ( ) ;
@ -30,13 +91,37 @@ pub fn derive_enum_string<T: std::str::FromStr + quote::ToTokens>(input: TokenSt
let mut names_upper = Vec ::new ( ) ;
let mut fields = Vec ::new ( ) ;
let mut enum_string_style = String ::from ( "" ) ;
if let syn ::Data ::Enum ( ref data ) = input . data {
for attr in input . attrs . iter ( ) {
if attr . path . is_ident ( "suricata" ) {
enum_string_style = get_attr_enum_string_style ( attr ) ;
}
}
for v in ( & data . variants ) . into_iter ( ) {
if let Some ( ( _ , val ) ) = & v . discriminant {
let fname = transform_name ( & v . ident . to_string ( ) ) ;
let fnameu = fname . to_ascii_uppercase ( ) ;
names . push ( fname ) ;
names_upper . push ( fnameu ) ;
match & enum_string_style [ .. ] {
"UPPERCASE" = > {
names . push ( v . ident . to_string ( ) . to_ascii_uppercase ( ) ) ;
names_upper . push ( v . ident . to_string ( ) . to_ascii_uppercase ( ) ) ;
}
"LOG_UPPERCASE" = > {
names . push ( v . ident . to_string ( ) . to_ascii_uppercase ( ) ) ;
let fname = transform_name ( & v . ident . to_string ( ) ) ;
let fnameu = fname . to_ascii_uppercase ( ) ;
names_upper . push ( fnameu ) ;
}
"" = > { // snake_case
let fname = transform_name ( & v . ident . to_string ( ) ) ;
let fnameu = fname . to_ascii_uppercase ( ) ;
names . push ( fname ) ;
names_upper . push ( fnameu ) ;
}
_ = > {
panic! ( "EnumString style unknown {}" , enum_string_style ) ;
}
} ;
fields . push ( v . ident . clone ( ) ) ;
if let syn ::Expr ::Lit ( l ) = val {
if let syn ::Lit ::Int ( li ) = & l . lit {
@ -59,7 +144,9 @@ pub fn derive_enum_string<T: std::str::FromStr + quote::ToTokens>(input: TokenSt
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 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 {