Skip to main content

idakit_sys/
frame_flags.rs

1//! The typed [`FrameVarFlags`] layer over `FrameVar`'s reserved-slot flag bits.
2//!
3//! The frame walk itself is the `cxx` `bridge::frame_type_walk_visit` entry (see
4//! `bridge_visitors`); these flags classify the slots it returns.
5
6use bitflags::bitflags;
7
8bitflags! {
9    /// `FrameVar::flags` bits marking the reserved return-address and saved-registers slots.
10    ///
11    /// The bits are idakit's own, set by the C++ frame walk; they correspond to the SDK's
12    /// `FPC_RETADDR`/`FPC_SAVREGS` frame parts (`frame_part_t`). Accepts any bit pattern
13    /// (`from_bits_retain`), since `FrameVar::flags` is a raw `u32` field the walk writes.
14    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
15    #[doc(alias("FPC_RETADDR", "FPC_SAVREGS"))]
16    pub struct FrameVarFlags: u32 {
17        /// The return-address slot in the frame (SDK `FPC_RETADDR`).
18        #[doc(alias("FPC_RETADDR"))]
19        const RETADDR = 1;
20        /// The saved-registers slot in the frame (SDK `FPC_SAVREGS`).
21        #[doc(alias("FPC_SAVREGS"))]
22        const SAVREGS = 2;
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use assert2::assert;
29    use proptest::prelude::*;
30    use rstest::rstest;
31
32    use super::*;
33
34    #[rstest]
35    #[case::retaddr(FrameVarFlags::RETADDR, 1)]
36    #[case::savregs(FrameVarFlags::SAVREGS, 2)]
37    fn flags_pin_the_raw_values(#[case] flag: FrameVarFlags, #[case] raw: u32) {
38        assert!(flag.bits() == raw);
39    }
40
41    proptest! {
42        #[test]
43        fn from_bits_retain_round_trips_every_bit_pattern(raw: u32) {
44            prop_assert_eq!(FrameVarFlags::from_bits_retain(raw).bits(), raw);
45        }
46
47        #[test]
48        fn union_and_intersection_are_raw_bitwise_ops(a: u32, b: u32) {
49            let (fa, fb) = (FrameVarFlags::from_bits_retain(a), FrameVarFlags::from_bits_retain(b));
50            prop_assert_eq!((fa | fb).bits(), a | b);
51            prop_assert_eq!((fa & fb).bits(), a & b);
52        }
53
54        #[test]
55        fn complement_truncates_to_the_known_flag_mask(a: u32) {
56            let fa = FrameVarFlags::from_bits_retain(a);
57            prop_assert_eq!((!fa).bits(), !a & FrameVarFlags::all().bits());
58        }
59    }
60}