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 | |
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')
-rw-r--r-- | rust/vendor/sawp-flags/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | rust/vendor/sawp-flags/Cargo.toml | 39 | ||||
-rw-r--r-- | rust/vendor/sawp-flags/src/lib.rs | 476 |
3 files changed, 516 insertions, 0 deletions
diff --git a/rust/vendor/sawp-flags/.cargo-checksum.json b/rust/vendor/sawp-flags/.cargo-checksum.json new file mode 100644 index 0000000..e5c6a80 --- /dev/null +++ b/rust/vendor/sawp-flags/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b96993caaefd3a9d3fd9543843c929b14f34be12cee7d8f0741bdc91fd8cc3c6","src/lib.rs":"d466d694c87f94666d04c4dae3b7817c7bd2e1a53890c3543ad3ede1a7f3b12b"},"package":"1f2b22023d224b5314d51e53bfb2dbca53dc2cf90a4435aa4feb78172799dad0"}
\ No newline at end of file diff --git a/rust/vendor/sawp-flags/Cargo.toml b/rust/vendor/sawp-flags/Cargo.toml new file mode 100644 index 0000000..1e6805c --- /dev/null +++ b/rust/vendor/sawp-flags/Cargo.toml @@ -0,0 +1,39 @@ +# 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" +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" +homepage = "https://github.com/CybercentreCanada/sawp" +readme = "README.md" +keywords = [ + "bitflags", + "bit", + "flags", + "bitmask", +] +license-file = "LICENSE" +repository = "https://github.com/CybercentreCanada/sawp" + +[package.metadata.release] +pre-release-replacements = [] + +[dependencies.sawp-flags-derive] +version = "^0.12.1" diff --git a/rust/vendor/sawp-flags/src/lib.rs b/rust/vendor/sawp-flags/src/lib.rs new file mode 100644 index 0000000..650cf85 --- /dev/null +++ b/rust/vendor/sawp-flags/src/lib.rs @@ -0,0 +1,476 @@ +//! Bitflags handling and storage. +//! +//! This crate allows you to define flag values using an enum and derive +//! `BitFlags` to add convenience methods. +//! +//! This implementation was heavily inspired by +//! [enumflags2](https://crates.io/crates/enumflags2) and +//! [bitflags](https://crates.io/crates/bitflags) and customized for use in a +//! sawp parser. Consider using those two open source projects before resorting +//! to this one. One key feature is that we are automatically generating ffi +//! accessors using the [sawp-ffi](https://crates.io/crates/sawp-ffi) crate. +//! +//! This crate works as follows: +//! - `enum YourEnum` with a numeric representation (e.g. `#[repr(u8)]`) is used +//! to define bit fields. +//! - deriving `BitFlags` on this enum will add convenience methods for bitwise +//! operations and implement the `Flag` trait. +//! - Flag values are transparently stored as `Flags<YourEnum>` so you can perform +//! more operations on this type. +//! +//! # Example +//! See `example` module for a generated example as well. +//! ``` +//! use sawp_flags::{BitFlags, Flags, Flag}; +//! +//! /// Example enum +//! #[derive(Debug, Clone, Copy, PartialEq, BitFlags)] +//! #[repr(u8)] +//! pub enum Test { +//! A = 0b0001, +//! B = 0b0010, +//! C = 0b0100, +//! D = 0b1000, +//! /// Variants can be a bitmask of the other fields like so +//! E = Test::A as u8 | Test::B as u8 | Test::C as u8 | Test::D as u8, +//! } +//! +//! // `flags` will be of transparent type `Flags<Test>` +//! let flags : Flags<Test> = Test::A | Test::C; +//! +//! // convert a number to flags using `from_bits()` +//! assert_eq!(flags, Flags::<Test>::from_bits(0b101)); +//! +//! // convert flags to a number using `bits()` +//! assert_eq!(0b101, flags.bits()); +//! +//! // perform bitwise operations +//! assert_eq!(Test::A | Test::B | Test::C, flags | Test::B); +//! assert_eq!(Test::A, flags & Test::A); +//! assert_eq!(Test::C, flags ^ Test::A); +//! +//! // check which flags are set +//! assert!(flags.contains(Test::A)); +//! assert!(!flags.contains(Test::A | Test::B)); +//! assert!(flags.intersects(Test::A)); +//! assert!(flags.intersects(Test::A | Test::B)); +//! ``` + +use std::ops::*; + +/// The `BitFlags` derive macro will implement the `Flags` Trait on your enum and +/// provide convenience methods for bit operations and type conversions. +/// +// Re-export derive macro for convenience. +pub use sawp_flags_derive::BitFlags; + +/// A primitive numeric type to be used for flag storage. +pub trait Primitive: + Default + + BitOr<Self, Output = Self> + + BitAnd<Self, Output = Self> + + BitXor<Self, Output = Self> + + Not<Output = Self> + + PartialOrd<Self> + + std::fmt::Debug + + std::fmt::Binary + + Copy + + Clone +{ +} + +impl Primitive for u8 {} +impl Primitive for u16 {} +impl Primitive for u32 {} +impl Primitive for u64 {} +impl Primitive for u128 {} + +/// A trait implemented by all flag enums. +pub trait Flag: Copy + Clone + std::fmt::Debug + std::fmt::Display + 'static { + /// Associated primitive numeric type + type Primitive: Primitive; + + /// A list of all flag variants in the enum + const ITEMS: &'static [Self]; + + /// Numeric representation of the variant + fn bits(self) -> Self::Primitive; + + /// Flag value when no variants are set + fn none() -> Flags<Self>; + + /// Flag value when all variants are set + fn all() -> Flags<Self>; +} + +/// Storage type for handling flags +#[derive(Copy, Clone, PartialEq, Eq)] +#[repr(transparent)] +pub struct Flags<Enum, Primitive = <Enum as Flag>::Primitive> { + val: Primitive, + marker: std::marker::PhantomData<Enum>, +} + +impl<Enum> std::fmt::Debug for Flags<Enum> +where + Enum: Flag, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.val.fmt(f) + } +} + +impl<Enum> Default for Flags<Enum> +where + Enum: Flag, +{ + fn default() -> Self { + Self { + val: <Enum as Flag>::Primitive::default(), + marker: std::marker::PhantomData, + } + } +} + +impl<Enum> Flags<Enum> +where + Enum: Flag, +{ + /// Get a flag from a single enum value + pub fn from_flag(flag: Enum) -> Self { + Self { + val: flag.bits(), + marker: std::marker::PhantomData, + } + } + + /// Get a flag from a numeric value + /// + /// Note: the value is unchecked so any bit may be set. Be + /// careful because `PartialEq` is a direct comparison of + /// underlying bits. + pub fn from_bits(bits: <Enum as Flag>::Primitive) -> Self { + Self { + val: bits, + marker: std::marker::PhantomData, + } + } + + /// Numeric representation of the variant + pub fn bits(&self) -> <Enum as Flag>::Primitive { + self.val + } + + /// Reference to numeric representation of the variant + pub fn bits_ref(&self) -> &<Enum as Flag>::Primitive { + &self.val + } + + /// Check if at least one flag in common is set + pub fn intersects<B: Into<Flags<Enum>>>(self, rhs: B) -> bool { + (self & rhs.into()).bits() != Enum::none().bits() + } + + /// Check if all flags provided in `rhs` are set + pub fn contains<B: Into<Flags<Enum>>>(self, rhs: B) -> bool { + let rhs = rhs.into(); + (self & rhs).bits() == rhs.bits() + } + + pub fn is_empty(&self) -> bool { + self.bits() == <Enum as Flag>::none().bits() + } + + pub fn is_all(&self) -> bool { + self.bits() == <Enum as Flag>::all().bits() + } +} + +impl<Enum: Flag> From<Enum> for Flags<Enum> { + fn from(flag: Enum) -> Self { + Self::from_flag(flag) + } +} + +impl<Enum: Flag> PartialEq<Enum> for Flags<Enum> { + fn eq(&self, other: &Enum) -> bool { + self.bits() == other.bits() + } +} + +impl<T, B> std::ops::BitOr<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + type Output = Flags<T>; + fn bitor(self, other: B) -> Flags<T> { + Flags::from_bits(self.bits() | other.into().bits()) + } +} + +impl<T, B> std::ops::BitOrAssign<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + fn bitor_assign(&mut self, rhs: B) { + *self = Flags::from_bits(self.bits() | rhs.into().bits()) + } +} + +impl<T, B> std::ops::BitAnd<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + type Output = Flags<T>; + fn bitand(self, other: B) -> Flags<T> { + Flags::from_bits(self.bits() & other.into().bits()) + } +} + +impl<T, B> std::ops::BitAndAssign<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + fn bitand_assign(&mut self, rhs: B) { + *self = Flags::from_bits(self.bits() & rhs.into().bits()) + } +} + +impl<T, B> std::ops::BitXor<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + type Output = Flags<T>; + fn bitxor(self, other: B) -> Flags<T> { + Flags::from_bits(self.bits() ^ other.into().bits()) + } +} + +impl<T, B> std::ops::BitXorAssign<B> for Flags<T> +where + T: Flag, + B: Into<Flags<T>>, +{ + fn bitxor_assign(&mut self, rhs: B) { + *self = Flags::from_bits(self.bits() ^ rhs.into().bits()) + } +} + +impl<T: Flag> std::ops::Not for Flags<T> { + type Output = Flags<T>; + + fn not(self) -> Self::Output { + Flags::from_bits(!self.bits()) + } +} + +impl<T: Flag> std::fmt::Display for Flags<T> { + /// A pipe-separated list of set flags. + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let none = self.bits() == T::none().bits(); + let mut first = true; + for val in <T as Flag>::ITEMS + .iter() + .cloned() + .filter(move |&flag| self.contains(flag)) + { + write!(f, "{}{:?}", if first { "" } else { " | " }, val)?; + first = false; + + if none { + return Ok(()); + } + } + + if none { + write!(f, "NONE")?; + } + + Ok(()) + } +} + +impl<T: Flag> std::fmt::Binary for Flags<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Binary::fmt(&self.bits(), f) + } +} + +/// Example enum deriving `BitFlags` +pub mod example { + use super::*; + + /// Example enum + #[derive(Debug, Clone, Copy, PartialEq, Eq, BitFlags)] + #[repr(u8)] + pub enum Test { + A = 0b0001, + B = 0b0010, + C = 0b0100, + D = 0b1000, + /// Variants can be bitmask of other fields + E = Test::A as u8 | Test::B as u8 | Test::C as u8 | Test::D as u8, + } +} + +#[cfg(test)] +mod test { + use super::{example::*, *}; + + #[test] + fn test_enum_bits() { + let bits = 0b1010_1010; + let flags = Flags::<Test>::from_bits(bits); + assert_eq!(bits, flags.bits()); + assert_eq!(&bits, flags.bits_ref()); + } + + #[test] + fn test_enum_or() { + let mut flags = Test::A | Test::B; + assert_eq!(0b0011, flags.bits()); + + flags |= Test::C; + assert_eq!(0b0111, flags.bits()); + + flags |= Test::C | Test::D; + assert_eq!(0b1111, flags.bits()); + } + + #[test] + fn test_enum_and() { + let mut flags = Test::E & Test::B; + assert_eq!(0b0010, flags.bits()); + + flags &= Test::B; + assert_eq!(0b0010, flags.bits()); + + flags &= Test::E & Test::B; + assert_eq!(0b0010, flags.bits()); + } + + #[test] + fn test_enum_xor() { + let mut flags = Test::A ^ Test::B; + assert_eq!(0b0011, flags.bits()); + + flags ^= Test::C; + assert_eq!(0b0111, flags.bits()); + + flags ^= Test::D ^ Test::B; + assert_eq!(0b1101, flags.bits()); + } + + #[test] + fn test_enum_not() { + let flags = !Test::A; + assert_eq!(0b1111_1110, flags.bits()); + let flags = !(Test::A ^ Test::B); + assert_eq!(0b1111_1100, flags.bits()); + } + + #[test] + fn test_contains() { + let flags = Test::A | Test::C; + assert!(flags.contains(Test::A)); + assert!(!flags.contains(Test::B)); + assert!(!flags.contains(Test::E)); + assert!(!flags.contains(Test::B | Test::D)); + assert!(!flags.contains(Test::A | Test::B)); + assert!(flags.contains(Test::A | Test::C)); + } + + #[test] + fn test_intersects() { + let flags = Test::A | Test::C; + assert!(flags.intersects(Test::A)); + assert!(flags.intersects(Test::E)); + assert!(flags.intersects(Test::A | Test::B)); + assert!(flags.intersects(Test::A | Test::C)); + assert!(flags.intersects(Test::A | Test::B | Test::C)); + assert!(!flags.intersects(Test::B | Test::D)); + } + + #[test] + fn test_eq() { + let flags = Test::A; + assert_eq!(flags, Test::A); + assert_eq!(Test::A, flags); + + let flags = Test::A | Test::C; + assert_ne!(flags, Test::A); + assert_ne!(flags, Test::C); + assert_ne!(Test::A, flags); + assert_eq!(flags, Test::A | Test::C); + assert_ne!(flags, Test::A | Test::C | Test::E); + + let flags = Flags::<Test>::from_bits(0b1000_0001); + assert_ne!(flags, Test::A); + } + + #[test] + fn test_enum_string() { + assert_eq!("NONE", Test::none().to_string()); + assert_eq!("A", Test::A.to_string()); + assert_eq!("A | B", (Test::A | Test::B).to_string()); + assert_eq!("A | B | C | D | E", Test::E.to_string()); + assert_eq!("A | B | C | D | E", Flags::from_flag(Test::E).to_string()); + } + + #[test] + fn test_enum_string_none() { + #[derive(Debug, Clone, Copy, PartialEq, Eq, BitFlags)] + #[repr(u8)] + pub enum Test { + Zero = 0b0000, + A = 0b0001, + B = 0b0010, + C = 0b0100, + D = 0b1000, + /// Variants can be bitmask of other fields + E = Test::A as u8 | Test::B as u8 | Test::C as u8 | Test::D as u8, + } + assert_eq!("Zero", Test::Zero.to_string()); + assert_eq!("Zero", Test::none().to_string()); + assert_eq!("Zero", Flags::from_flag(Test::Zero).to_string()); + } + + #[test] + fn test_enum_format() { + assert_eq!("A", format!("{:?}", Test::A)); + assert_eq!("E", format!("{:?}", Test::E)); + assert_eq!("0", format!("{:?}", Test::none())); + + assert_eq!("0", format!("{:b}", Test::none())); + assert_eq!("1", format!("{:b}", Test::A)); + assert_eq!("1111", format!("{:b}", Test::E)); + } + + #[test] + fn test_enum_from_str() { + use std::str::FromStr; + assert_eq!(Err(()), Test::from_str("")); + assert_eq!(Ok(Test::A), Test::from_str("a")); + assert_eq!(Ok(Test::A), Test::from_str("A")); + } + + #[test] + fn test_all() { + assert_eq!(Test::E, Test::all()); + assert!(!Flags::from_flag(Test::A).is_all()); + assert!(Flags::from_flag(Test::E).is_all()); + } + + #[test] + fn test_none() { + assert_eq!(Flags::from_bits(0), Test::none()); + assert!(Flags::<Test>::from_bits(0).is_empty()); + assert!(!Flags::from_flag(Test::A).is_empty()); + assert!(!Flags::from_flag(Test::E).is_empty()); + } +} |