use crate::evaluator::operators::equality::apply_equal;
use crate::parser::ast::Value;
#[must_use]
pub fn apply_bitwise_and_mask(mask: u64, left: &Value, right: &Value) -> bool {
let masked_left = match left {
Value::Uint(val) => Value::Uint(val & mask),
Value::Int(val) => {
let i64_mask =
i64::try_from(mask).unwrap_or_else(|_| i64::from_ne_bytes(mask.to_ne_bytes()));
Value::Int(val & i64_mask)
}
_ => return false, };
apply_equal(&masked_left, right)
}
#[must_use]
pub fn apply_bitwise_and(left: &Value, right: &Value) -> bool {
match (left, right) {
(Value::Uint(a), Value::Uint(b)) => (a & b) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Int(a), Value::Int(b)) => ((*a as u64) & (*b as u64)) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Uint(a), Value::Int(b)) => (a & (*b as u64)) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Int(a), Value::Uint(b)) => ((*a as u64) & b) != 0,
_ => false,
}
}
#[must_use]
pub fn apply_bitwise_xor(left: &Value, right: &Value) -> bool {
match (left, right) {
(Value::Uint(a), Value::Uint(b)) => (a ^ b) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Int(a), Value::Int(b)) => ((*a as u64) ^ (*b as u64)) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Uint(a), Value::Int(b)) => (a ^ (*b as u64)) != 0,
#[allow(clippy::cast_sign_loss)]
(Value::Int(a), Value::Uint(b)) => ((*a as u64) ^ b) != 0,
_ => false,
}
}
#[must_use]
pub fn apply_bitwise_not(left: &Value, right: &Value) -> bool {
apply_bitwise_not_with_width(left, right, None)
}
#[must_use]
pub fn apply_bitwise_not_with_width(left: &Value, right: &Value, bit_width: Option<u32>) -> bool {
let complemented = match (left, bit_width) {
(Value::Uint(val), Some(width)) if width < 64 => {
let mask = (1u64 << width) - 1;
Value::Uint(!val & mask)
}
(Value::Uint(val), _) => Value::Uint(!val),
(Value::Int(val), _) => Value::Int(!*val),
_ => return false,
};
apply_equal(&complemented, right)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_apply_bitwise_and_uint_basic() {
assert!(apply_bitwise_and(&Value::Uint(0x01), &Value::Uint(0x01))); assert!(!apply_bitwise_and(&Value::Uint(0x02), &Value::Uint(0x01))); assert!(apply_bitwise_and(&Value::Uint(0x03), &Value::Uint(0x01))); }
#[test]
fn test_apply_bitwise_and_uint_multiple_bits() {
assert!(apply_bitwise_and(&Value::Uint(0xFF), &Value::Uint(0x0F))); assert!(!apply_bitwise_and(&Value::Uint(0xF0), &Value::Uint(0x0F))); assert!(!apply_bitwise_and(&Value::Uint(0xAA), &Value::Uint(0x55))); assert!(apply_bitwise_and(&Value::Uint(0xAA), &Value::Uint(0xAA))); }
#[test]
fn test_apply_bitwise_and_uint_edge_cases() {
assert!(!apply_bitwise_and(&Value::Uint(0), &Value::Uint(0xFF))); assert!(!apply_bitwise_and(&Value::Uint(0xFF), &Value::Uint(0))); assert!(!apply_bitwise_and(&Value::Uint(0), &Value::Uint(0)));
assert!(apply_bitwise_and(&Value::Uint(u64::MAX), &Value::Uint(1))); assert!(apply_bitwise_and(
&Value::Uint(u64::MAX),
&Value::Uint(u64::MAX)
)); }
#[test]
fn test_apply_bitwise_and_uint_specific_patterns() {
assert!(apply_bitwise_and(
&Value::Uint(0x7F45_4C46),
&Value::Uint(0xFF00_0000)
)); assert!(apply_bitwise_and(
&Value::Uint(0x504B_0304),
&Value::Uint(0xFFFF_0000)
)); assert!(!apply_bitwise_and(
&Value::Uint(0x1234_5678),
&Value::Uint(0x0000_0001)
)); }
#[test]
fn test_apply_bitwise_and_int_basic() {
assert!(apply_bitwise_and(&Value::Int(1), &Value::Int(1))); assert!(!apply_bitwise_and(&Value::Int(2), &Value::Int(1))); assert!(apply_bitwise_and(&Value::Int(3), &Value::Int(1))); }
#[test]
fn test_apply_bitwise_and_int_negative() {
assert!(apply_bitwise_and(&Value::Int(-1), &Value::Int(1))); assert!(apply_bitwise_and(&Value::Int(-2), &Value::Int(2))); assert!(!apply_bitwise_and(&Value::Int(-2), &Value::Int(1))); }
#[test]
fn test_apply_bitwise_and_int_zero() {
assert!(!apply_bitwise_and(&Value::Int(0), &Value::Int(0xFF))); assert!(!apply_bitwise_and(&Value::Int(0xFF), &Value::Int(0))); assert!(!apply_bitwise_and(&Value::Int(0), &Value::Int(0))); }
#[test]
fn test_apply_bitwise_and_int_extreme_values() {
assert!(apply_bitwise_and(&Value::Int(i64::MAX), &Value::Int(1))); assert!(apply_bitwise_and(
&Value::Int(i64::MIN),
&Value::Int(i64::MIN)
)); assert!(apply_bitwise_and(&Value::Int(i64::MIN), &Value::Int(-1))); }
#[test]
fn test_apply_bitwise_and_mixed_int_uint() {
assert!(apply_bitwise_and(&Value::Uint(0xFF), &Value::Int(0x0F))); assert!(apply_bitwise_and(&Value::Int(0xFF), &Value::Uint(0x0F))); assert!(!apply_bitwise_and(&Value::Uint(0xF0), &Value::Int(0x0F))); assert!(!apply_bitwise_and(&Value::Int(0xF0), &Value::Uint(0x0F))); }
#[test]
fn test_apply_bitwise_and_mixed_negative_uint() {
assert!(apply_bitwise_and(&Value::Int(-1), &Value::Uint(1))); assert!(apply_bitwise_and(&Value::Uint(1), &Value::Int(-1))); assert!(!apply_bitwise_and(&Value::Int(-2), &Value::Uint(1))); assert!(!apply_bitwise_and(&Value::Uint(1), &Value::Int(-2))); }
#[test]
fn test_apply_bitwise_and_non_integer_types() {
assert!(!apply_bitwise_and(
&Value::String("test".to_string()),
&Value::Uint(0x01)
));
assert!(!apply_bitwise_and(
&Value::Uint(0x01),
&Value::String("test".to_string())
));
assert!(!apply_bitwise_and(
&Value::Bytes(vec![1]),
&Value::Uint(0x01)
));
assert!(!apply_bitwise_and(
&Value::Uint(0x01),
&Value::Bytes(vec![1])
));
assert!(!apply_bitwise_and(
&Value::String("a".to_string()),
&Value::String("b".to_string())
));
assert!(!apply_bitwise_and(
&Value::Bytes(vec![1]),
&Value::Bytes(vec![1])
));
}
#[test]
fn test_apply_bitwise_and_all_non_integer_combinations() {
let non_integer_values = [Value::String("test".to_string()), Value::Bytes(vec![42])];
let integer_values = [Value::Uint(42), Value::Int(42)];
for non_int in &non_integer_values {
for int_val in &integer_values {
assert!(
!apply_bitwise_and(non_int, int_val),
"Non-integer & integer should be false: {non_int:?} & {int_val:?}"
);
assert!(
!apply_bitwise_and(int_val, non_int),
"Integer & non-integer should be false: {int_val:?} & {non_int:?}"
);
}
}
for left in &non_integer_values {
for right in &non_integer_values {
assert!(
!apply_bitwise_and(left, right),
"Non-integer & non-integer should be false: {left:?} & {right:?}"
);
}
}
}
#[test]
fn test_apply_bitwise_and_bit_patterns() {
let test_cases = vec![
(0b0000_0001_u64, 0b0000_0001_u64, true), (0b0000_0010_u64, 0b0000_0001_u64, false), (0b0000_0011_u64, 0b0000_0001_u64, true), (0b1111_1111_u64, 0b0000_1111_u64, true), (0b1111_0000_u64, 0b0000_1111_u64, false), (0b1010_1010_u64, 0b0101_0101_u64, false), (0b1010_1010_u64, 0b1010_1010_u64, true), (0b1111_1111_u64, 0b0000_0000_u64, false), (0b0000_0000_u64, 0b1111_1111_u64, false), ];
for (value, mask, expected) in test_cases {
assert_eq!(
apply_bitwise_and(&Value::Uint(value), &Value::Uint(mask)),
expected,
"apply_bitwise_and(0b{value:08b}, 0b{mask:08b}) should be {expected}"
);
}
}
#[test]
fn test_apply_bitwise_and_magic_file_patterns() {
let elf_magic = Value::Uint(0x7F45_4C46);
let elf_mask = Value::Uint(0xFFFF_FFFF);
assert!(apply_bitwise_and(&elf_magic, &elf_mask));
assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x7F00_0000))); assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0045_0000))); assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0000_4C00))); assert!(apply_bitwise_and(&elf_magic, &Value::Uint(0x0000_0046)));
let zip_magic = Value::Uint(0x504B_0304);
assert!(apply_bitwise_and(&zip_magic, &Value::Uint(0x504B_0000))); assert!(!apply_bitwise_and(&zip_magic, &Value::Uint(0x0000_0001)));
let pdf_magic = Value::Uint(0x2550_4446); assert!(apply_bitwise_and(&pdf_magic, &Value::Uint(0xFF00_0000))); assert!(apply_bitwise_and(&pdf_magic, &Value::Uint(0x00FF_0000))); }
#[test]
fn test_apply_bitwise_and_symmetry() {
let test_cases = vec![
(Value::Uint(0xFF), Value::Uint(0x0F)),
(Value::Int(42), Value::Int(24)),
(Value::Uint(0xAAAA), Value::Int(0x5555)),
(Value::Int(-1), Value::Uint(1)),
];
for (left, right) in test_cases {
let left_to_right = apply_bitwise_and(&left, &right);
let right_to_left = apply_bitwise_and(&right, &left);
assert_eq!(
left_to_right, right_to_left,
"Bitwise AND should be commutative: {left:?} & {right:?}"
);
}
}
#[test]
fn test_apply_bitwise_and_associativity_concept() {
let value = Value::Uint(0b1111_0000);
let mask1 = Value::Uint(0b1100_0000);
let mask2 = Value::Uint(0b0011_0000);
let combined_mask = Value::Uint(0b1111_0000);
assert!(apply_bitwise_and(&value, &mask1));
assert!(apply_bitwise_and(&value, &mask2));
assert!(apply_bitwise_and(&value, &combined_mask));
}
#[test]
fn test_apply_bitwise_xor_uint() {
assert!(apply_bitwise_xor(&Value::Uint(0xFF), &Value::Uint(0x0F)));
assert!(!apply_bitwise_xor(&Value::Uint(0xFF), &Value::Uint(0xFF)));
assert!(apply_bitwise_xor(&Value::Uint(1), &Value::Uint(2)));
assert!(!apply_bitwise_xor(&Value::Uint(0), &Value::Uint(0)));
}
#[test]
fn test_apply_bitwise_xor_int() {
assert!(apply_bitwise_xor(&Value::Int(0xFF), &Value::Int(0x0F)));
assert!(!apply_bitwise_xor(&Value::Int(42), &Value::Int(42)));
assert!(apply_bitwise_xor(&Value::Int(-1), &Value::Int(0)));
}
#[test]
fn test_apply_bitwise_xor_cross_type() {
assert!(apply_bitwise_xor(&Value::Uint(0xFF), &Value::Int(0x0F)));
assert!(apply_bitwise_xor(&Value::Int(0xFF), &Value::Uint(0x0F)));
assert!(!apply_bitwise_xor(&Value::Uint(42), &Value::Int(42)));
}
#[test]
fn test_apply_bitwise_xor_same_value() {
assert!(!apply_bitwise_xor(&Value::Uint(100), &Value::Uint(100)));
assert!(!apply_bitwise_xor(&Value::Int(-1), &Value::Int(-1)));
}
#[test]
fn test_apply_bitwise_xor_non_numeric() {
assert!(!apply_bitwise_xor(
&Value::Bytes(vec![1, 2]),
&Value::Uint(1)
));
assert!(!apply_bitwise_xor(
&Value::String("x".to_string()),
&Value::Uint(0xFF)
));
}
#[test]
fn test_apply_bitwise_not_uint() {
assert!(apply_bitwise_not(&Value::Uint(0), &Value::Uint(u64::MAX)));
assert!(apply_bitwise_not(&Value::Uint(u64::MAX), &Value::Uint(0)));
assert!(!apply_bitwise_not(&Value::Uint(0xFF), &Value::Uint(0)));
}
#[test]
fn test_apply_bitwise_not_int() {
assert!(apply_bitwise_not(&Value::Int(0), &Value::Int(-1)));
assert!(apply_bitwise_not(&Value::Int(-1), &Value::Int(0)));
}
#[test]
fn test_apply_bitwise_not_all_bits_set() {
assert!(apply_bitwise_not(
&Value::Uint(0xFFFF_FFFF_FFFF_FFFF),
&Value::Uint(0)
));
}
#[test]
fn test_apply_bitwise_not_non_numeric() {
assert!(!apply_bitwise_not(
&Value::Bytes(vec![0xff]),
&Value::Uint(0)
));
assert!(!apply_bitwise_not(
&Value::String("x".to_string()),
&Value::Uint(0)
));
}
#[test]
fn test_apply_bitwise_not_with_byte_width() {
assert!(apply_bitwise_not_with_width(
&Value::Uint(0x00),
&Value::Uint(0xFF),
Some(8)
));
assert!(apply_bitwise_not_with_width(
&Value::Uint(0xFF),
&Value::Uint(0x00),
Some(8)
));
assert!(apply_bitwise_not_with_width(
&Value::Uint(0x42),
&Value::Uint(0xBD),
Some(8)
));
}
#[test]
fn test_apply_bitwise_not_with_short_width() {
assert!(apply_bitwise_not_with_width(
&Value::Uint(0x0000),
&Value::Uint(0xFFFF),
Some(16)
));
assert!(apply_bitwise_not_with_width(
&Value::Uint(0x1234),
&Value::Uint(0xEDCB),
Some(16)
));
}
#[test]
fn test_apply_bitwise_not_with_long_width() {
assert!(apply_bitwise_not_with_width(
&Value::Uint(0x0000_0000),
&Value::Uint(0xFFFF_FFFF),
Some(32)
));
}
#[test]
fn test_apply_bitwise_not_with_quad_width() {
assert!(apply_bitwise_not_with_width(
&Value::Uint(0),
&Value::Uint(u64::MAX),
Some(64)
));
}
#[test]
fn test_apply_bitwise_not_with_no_width() {
assert!(apply_bitwise_not_with_width(
&Value::Uint(0),
&Value::Uint(u64::MAX),
None
));
}
}