Skip to main content

idakit_sys/
name_flags.rs

1//! The typed [`NameFlags`] layer over `name.hpp`'s `GN_*` bits for `get_ea_name`.
2
3use std::ffi::c_int;
4
5use bitflags::bitflags;
6
7bitflags! {
8    /// `get_ea_name`'s `gtn_flags` bits (`name.hpp`), controlling substitution/demangling.
9    ///
10    /// Accepts any bit pattern (`from_bits_retain`), so it stays sound as the raw `int` argument
11    /// crossing to `get_ea_name`.
12    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
13    #[doc(alias(
14        "GN_VISIBLE", "GN_COLORED", "GN_DEMANGLED", "GN_STRICT", "GN_SHORT", "GN_LONG",
15        "GN_LOCAL", "GN_ISRET", "GN_NOT_ISRET", "GN_NOT_DUMMY"
16    ))]
17    pub struct NameFlags: c_int {
18        /// Replace forbidden characters with `SUBSTCHAR` (`GN_VISIBLE`).
19        #[doc(alias("GN_VISIBLE"))]
20        const VISIBLE = 0x0001;
21        /// Return a colored name (`GN_COLORED`).
22        #[doc(alias("GN_COLORED"))]
23        const COLORED = 0x0002;
24        /// Return the demangled form (`GN_DEMANGLED`).
25        #[doc(alias("GN_DEMANGLED"))]
26        const DEMANGLED = 0x0004;
27        /// Fail rather than fall back when demangling fails (`GN_STRICT`).
28        #[doc(alias("GN_STRICT"))]
29        const STRICT = 0x0008;
30        /// Use the short demangled form (`GN_SHORT`).
31        #[doc(alias("GN_SHORT"))]
32        const SHORT = 0x0010;
33        /// Use the long demangled form (`GN_LONG`).
34        #[doc(alias("GN_LONG"))]
35        const LONG = 0x0020;
36        /// Try the local name first, falling back to the global one (`GN_LOCAL`).
37        #[doc(alias("GN_LOCAL"))]
38        const LOCAL = 0x0040;
39        /// For a dummy name, use the return-location form (`GN_ISRET`).
40        #[doc(alias("GN_ISRET"))]
41        const ISRET = 0x0080;
42        /// For a dummy name, do not use the return-location form (`GN_NOT_ISRET`).
43        #[doc(alias("GN_NOT_ISRET"))]
44        const NOT_ISRET = 0x0100;
45        /// Do not return a dummy name (`GN_NOT_DUMMY`).
46        #[doc(alias("GN_NOT_DUMMY"))]
47        const NOT_DUMMY = 0x0200;
48    }
49}
50
51#[cfg(test)]
52mod tests {
53    use assert2::assert;
54    use proptest::prelude::*;
55    use rstest::rstest;
56
57    use super::*;
58
59    #[rstest]
60    #[case::visible(NameFlags::VISIBLE, 0x0001)]
61    #[case::colored(NameFlags::COLORED, 0x0002)]
62    #[case::demangled(NameFlags::DEMANGLED, 0x0004)]
63    #[case::strict(NameFlags::STRICT, 0x0008)]
64    #[case::short(NameFlags::SHORT, 0x0010)]
65    #[case::long(NameFlags::LONG, 0x0020)]
66    #[case::local(NameFlags::LOCAL, 0x0040)]
67    #[case::isret(NameFlags::ISRET, 0x0080)]
68    #[case::not_isret(NameFlags::NOT_ISRET, 0x0100)]
69    #[case::not_dummy(NameFlags::NOT_DUMMY, 0x0200)]
70    fn flags_pin_the_raw_sdk_values(#[case] flag: NameFlags, #[case] raw: c_int) {
71        assert!(flag.bits() == raw);
72    }
73
74    proptest! {
75        #[test]
76        fn from_bits_retain_round_trips_every_bit_pattern(raw: c_int) {
77            prop_assert_eq!(NameFlags::from_bits_retain(raw).bits(), raw);
78        }
79
80        #[test]
81        fn union_and_intersection_are_raw_bitwise_ops(a: c_int, b: c_int) {
82            let (fa, fb) = (NameFlags::from_bits_retain(a), NameFlags::from_bits_retain(b));
83            prop_assert_eq!((fa | fb).bits(), a | b);
84            prop_assert_eq!((fa & fb).bits(), a & b);
85        }
86
87        #[test]
88        fn complement_truncates_to_the_known_flag_mask(a: c_int) {
89            let fa = NameFlags::from_bits_retain(a);
90            prop_assert_eq!((!fa).bits(), !a & NameFlags::all().bits());
91        }
92    }
93}