use std::ffi::{c_char, c_int, c_void};
use bitflags::bitflags;
use crate::Address;
unsafe extern "C" {
#[link_name = "idakit_get_bytes"]
pub fn get_bytes_into(address: Address, buf: *mut c_void, size: usize) -> i64;
}
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
#[doc(alias("BIN_SEARCH_CASE", "BIN_SEARCH_BITMASK"))]
pub struct BinSearchFlags: c_int {
#[doc(alias("BIN_SEARCH_CASE"))]
const CASE = 0x01;
#[doc(alias("BIN_SEARCH_BITMASK"))]
const BITMASK = 0x20;
}
}
pub const MS_CLS: u64 = 0x0000_0600;
pub const FF_CODE: u64 = 0x0000_0600;
pub const FF_DATA: u64 = 0x0000_0400;
unsafe extern "C" {
pub fn set_cmt(address: Address, comm: *const c_char, rptble: bool) -> bool;
}
#[cfg(test)]
mod tests {
use assert2::assert;
use proptest::prelude::*;
use rstest::rstest;
use super::*;
#[rstest]
#[case::case(BinSearchFlags::CASE, 0x01)]
#[case::bitmask(BinSearchFlags::BITMASK, 0x20)]
fn flags_pin_the_raw_sdk_values(#[case] flag: BinSearchFlags, #[case] raw: c_int) {
assert!(flag.bits() == raw);
}
#[rstest]
#[case::ms_cls(MS_CLS, 0x0000_0600)]
#[case::ff_code(FF_CODE, 0x0000_0600)]
#[case::ff_data(FF_DATA, 0x0000_0400)]
fn classification_consts_pin_the_raw_sdk_values(#[case] value: u64, #[case] raw: u64) {
assert!(value == raw);
}
#[test]
fn ff_code_and_ff_data_are_distinct_under_the_class_mask() {
assert!(FF_CODE & MS_CLS == FF_CODE);
assert!(FF_DATA & MS_CLS == FF_DATA);
assert!(FF_CODE != FF_DATA);
}
proptest! {
#[test]
fn from_bits_retain_round_trips_every_bit_pattern(raw: c_int) {
prop_assert_eq!(BinSearchFlags::from_bits_retain(raw).bits(), raw);
}
#[test]
fn union_and_intersection_are_raw_bitwise_ops(a: c_int, b: c_int) {
let (fa, fb) = (BinSearchFlags::from_bits_retain(a), BinSearchFlags::from_bits_retain(b));
prop_assert_eq!((fa | fb).bits(), a | b);
prop_assert_eq!((fa & fb).bits(), a & b);
}
#[test]
fn complement_truncates_to_the_known_flag_mask(a: c_int) {
let fa = BinSearchFlags::from_bits_retain(a);
prop_assert_eq!((!fa).bits(), !a & BinSearchFlags::all().bits());
}
}
}