diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:39:49 +0000 |
commit | a0aa2307322cd47bbf416810ac0292925e03be87 (patch) | |
tree | 37076262a026c4b48c8a0e84f44ff9187556ca35 /rust/vendor/sawp-flags-derive | |
parent | Initial commit. (diff) | |
download | suricata-a0aa2307322cd47bbf416810ac0292925e03be87.tar.xz suricata-a0aa2307322cd47bbf416810ac0292925e03be87.zip |
Adding upstream version 1:7.0.3.upstream/1%7.0.3
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'rust/vendor/sawp-flags-derive')
-rw-r--r-- | rust/vendor/sawp-flags-derive/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | rust/vendor/sawp-flags-derive/Cargo.toml | 52 | ||||
-rw-r--r-- | rust/vendor/sawp-flags-derive/src/lib.rs | 214 |
3 files changed, 267 insertions, 0 deletions
diff --git a/rust/vendor/sawp-flags-derive/.cargo-checksum.json b/rust/vendor/sawp-flags-derive/.cargo-checksum.json new file mode 100644 index 0000000..e6df821 --- /dev/null +++ b/rust/vendor/sawp-flags-derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fbd349b1231a07a0c1220af261a86b8a558d99a1820f9f074e4fadc8e5059152","src/lib.rs":"fb35a946c3367498d41d96a2eb5a2f17e7b67c62f1ec21fa4b19599a78ecf363"},"package":"49a585d3c22887d23bb06dd602b8ce96c2a716e1fa89beec8bfb49e466f2d643"}
\ No newline at end of file diff --git a/rust/vendor/sawp-flags-derive/Cargo.toml b/rust/vendor/sawp-flags-derive/Cargo.toml new file mode 100644 index 0000000..2f074f9 --- /dev/null +++ b/rust/vendor/sawp-flags-derive/Cargo.toml @@ -0,0 +1,52 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "sawp-flags-derive" +version = "0.12.1" +authors = ["Canadian Centre for Cyber Security <sa-sawp@cyber.gc.ca>"] +include = [ + "Cargo.toml", + "../LICENSE", + "../README.md", + "src/**/*.rs", +] +description = "SAWP BitFlags Handling and Storage Derive Macro" +homepage = "https://github.com/CybercentreCanada/sawp" +readme = "README.md" +keywords = [ + "bitflags", + "bit", + "flags", + "bitmask", + "derive", +] +license-file = "LICENSE" +repository = "https://github.com/CybercentreCanada/sawp" + +[package.metadata.release] +pre-release-replacements = [] + +[lib] +proc-macro = true + +[dependencies.proc-macro-crate] +version = "= 1.1.0" + +[dependencies.proc-macro2] +version = "1.0.36" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "1.0" diff --git a/rust/vendor/sawp-flags-derive/src/lib.rs b/rust/vendor/sawp-flags-derive/src/lib.rs new file mode 100644 index 0000000..fc84f87 --- /dev/null +++ b/rust/vendor/sawp-flags-derive/src/lib.rs @@ -0,0 +1,214 @@ +extern crate proc_macro; +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; +use quote::quote; + +#[proc_macro_derive(BitFlags)] +pub fn derive_sawp_flags(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast: syn::DeriveInput = syn::parse(input).unwrap(); + impl_sawp_flags(&ast).into() +} + +fn impl_sawp_flags(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + let repr = if let Some(repr) = get_repr(ast) { + repr + } else { + panic!("BitFlags enum must have a `repr` attribute with numeric argument"); + }; + match &ast.data { + syn::Data::Enum(data) => impl_enum_traits(name, &repr, data), + _ => panic!("Bitflags is only supported on enums"), + } +} + +fn get_repr(ast: &syn::DeriveInput) -> Option<Ident> { + ast.attrs.iter().find_map(|attr| { + if let Some(path) = attr.path.get_ident() { + if path == "repr" { + if let Some(tree) = attr.tokens.clone().into_iter().next() { + match tree { + TokenTree::Group(group) => { + if let Some(ident) = group.stream().into_iter().next() { + match ident { + TokenTree::Ident(ident) => Some(ident), + _ => None, + } + } else { + None + } + } + _ => None, + } + } else { + None + } + } else { + None + } + } else { + None + } + }) +} + +fn impl_enum_traits(name: &syn::Ident, repr: &Ident, data: &syn::DataEnum) -> TokenStream { + // TODO: compile error when these items are reused. + let list_items = data.variants.iter().map(|variant| &variant.ident); + let list_all = list_items.clone(); + let display_items = list_items.clone(); + let from_str_items = list_items.clone(); + let from_str_items_str = list_items.clone().map(|variant| { + Ident::new( + variant.to_string().to_lowercase().as_str(), + Span::call_site(), + ) + }); + + quote! { + impl Flag for #name { + type Primitive = #repr; + + const ITEMS: &'static [Self] = &[#(#name::#list_items),*]; + + fn bits(self) -> Self::Primitive { + self as #repr + } + + fn none() -> Flags<Self> { + Flags::from_bits(0) + } + + fn all() -> Flags<Self> { + Flags::from_bits(#(#name::#list_all as Self::Primitive)|*) + } + } + + impl std::ops::BitOr for #name { + type Output = Flags<#name>; + + fn bitor(self, other: Self) -> Self::Output { + Flags::from_bits(self.bits() | other.bits()) + } + } + + impl std::ops::BitAnd for #name { + type Output = Flags<#name>; + + fn bitand(self, other: Self) -> Self::Output { + Flags::from_bits(self.bits() & other.bits()) + } + } + + impl std::ops::BitXor for #name { + type Output = Flags<#name>; + + fn bitxor(self, other: Self) -> Self::Output { + Flags::from_bits(self.bits() ^ other.bits()) + } + } + + impl std::ops::Not for #name { + type Output = Flags<#name>; + + fn not(self) -> Self::Output { + Flags::from_bits(!self.bits()) + } + } + + impl std::fmt::Display for #name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let empty = self.bits() == Self::none().bits(); + let mut first = true; + #( + if self.bits() & #name::#display_items.bits() == #name::#display_items.bits() { + write!(f, "{}{}", if first { "" } else { " | " }, stringify!(#display_items))?; + first = false; + + if empty { + return Ok(()); + } + } + )* + + if empty { + write!(f, "NONE")?; + } + + Ok(()) + } + } + + impl std::str::FromStr for #name { + type Err = (); + fn from_str(val: &str) -> std::result::Result<#name, Self::Err> { + match val.to_lowercase().as_str() { + #(stringify!(#from_str_items_str) => Ok(#name::#from_str_items),)* + _ => Err(()), + } + } + } + + impl PartialEq<Flags<Self>> for #name { + fn eq(&self, other: &Flags<Self>) -> bool { + self.bits() == other.bits() + } + } + + impl std::fmt::Binary for #name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Binary::fmt(&self.bits(), f) + } + } + } +} + +/// BitFlags derive macro tests +/// +/// `#[derive(BitFlags)]` can't be used here and `impl_sawp_flags` +/// is being called directly instead. +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_macro_enum() { + let input = r#" + #[repr(u8)] + enum Test { + A = 0b0000, + B = 0b0001, + C = 0b0010, + D = 0b0100, + } + "#; + let parsed: syn::DeriveInput = syn::parse_str(input).unwrap(); + impl_sawp_flags(&parsed); + } + + #[test] + #[should_panic(expected = "BitFlags enum must have a `repr` attribute")] + fn test_macro_repr_panic() { + let input = r#" + enum Test { + A = 0b0000, + B = 0b0001, + C = 0b0010, + D = 0b0100, + } + "#; + let parsed: syn::DeriveInput = syn::parse_str(input).unwrap(); + impl_sawp_flags(&parsed); + } + + #[test] + #[should_panic(expected = "Bitflags is only supported on enums")] + fn test_macro_not_enum_panic() { + let input = r#" + #[repr(u8)] + struct Test { + } + "#; + let parsed: syn::DeriveInput = syn::parse_str(input).unwrap(); + impl_sawp_flags(&parsed); + } +} |