memflex/macros/
mod.rs

1mod global;
2mod interface;
3mod makestruct;
4pub use global::*;
5mod function;
6pub use function::*;
7mod bitstruct;
8pub use bitstruct::*;
9
10/// How to resolve static offsets
11pub enum ResolveBy<const N: usize> {
12    /// By module name and offset
13    NameOffset {
14        /// Module name
15        module_name: &'static str,
16        /// Offset
17        offset: usize,
18    },
19    /// By module name and pattern
20    IdaPattern {
21        /// Module name
22        module_name: &'static str,
23        /// Ida pattern
24        pattern: crate::Pattern<N>,
25    },
26}
27
28#[macro_export]
29#[doc(hidden)]
30macro_rules! __resolve_by {
31    (# $module:literal, $second:literal) => {
32        $crate::ResolveBy::<0>::NameOffset {
33            module_name: $module,
34            offset: $second,
35        }
36    };
37    (% $module:literal, $second:literal) => {
38        $crate::ResolveBy::IdaPattern {
39            module_name: $module,
40            pattern: $crate::ida_pat!($second),
41        }
42    };
43}
44
45#[doc(hidden)]
46#[cfg(all(windows, feature = "std"))]
47pub fn __default_resolver<const N: usize>(res: ResolveBy<N>) -> usize {
48    use crate::internal::{find_module_by_name, find_pattern_in_module};
49
50    match res {
51        ResolveBy::NameOffset {
52            module_name,
53            offset,
54        } => {
55            find_module_by_name(module_name)
56                .expect("Module not found")
57                .base as usize
58                + offset
59        }
60        ResolveBy::IdaPattern {
61            module_name,
62            pattern,
63        } => find_pattern_in_module(pattern, module_name)
64            .unwrap()
65            .next()
66            .unwrap() as usize,
67    }
68}
69
70#[doc(hidden)]
71#[cfg(not(windows))]
72pub fn __default_resolver<const N: usize>(_: ResolveBy<N>) -> usize {
73    unimplemented!()
74}
75
76#[doc(hidden)]
77#[macro_export]
78macro_rules! __resolver {
79    () => {
80        $crate::__default_resolver
81    };
82    ($item:path) => {
83        $item
84    };
85}
86
87/// Gets the size in bytes of the type or the variable
88/// ```
89/// # use memflex::size_of;
90/// assert_eq!(size_of!(i32), 4);
91///
92/// let var = 5_u64;
93/// assert_eq!(size_of!(@var), 8);
94/// ```
95#[macro_export]
96macro_rules! size_of {
97    ($ty:ty) => {
98        core::mem::size_of::<$ty>()
99    };
100    (@ $var:ident) => {
101        core::mem::size_of_val(&$var)
102    };
103}
104
105/// Gets the offset of the field.
106/// ```
107/// # use memflex::offset_of;
108/// #[repr(C)]
109/// struct Foo {
110///     a: u32,
111///     b: f32,
112///     value: usize
113/// }
114///
115/// let offset = offset_of!(Foo, value);
116/// assert_eq!(offset, 8);
117///
118/// const CONSTANT: usize = offset_of!(Foo, value);
119/// assert_eq!(CONSTANT, 8);
120/// ```
121#[macro_export]
122macro_rules! offset_of {
123    ($target:ty, $($field:tt).* $(,)?) => {{
124        let base = core::mem::MaybeUninit::<$target>::uninit();
125        let base_ptr = base.as_ptr();
126
127        #[allow(unused_unsafe)]
128        unsafe {
129            let field_ptr = core::ptr::addr_of!( (*base_ptr) $(.$field)* ).cast::<u8>();
130            field_ptr.offset_from(base_ptr.cast::<u8>()) as usize
131        }
132    }};
133}
134
135/// Asserts size of the type
136/// ```
137/// # use memflex::assert_size;
138/// #[repr(C)]
139/// struct Foo {
140///     a: u32,
141///     b: i32
142/// }
143/// // Doesn't compile
144/// // assert_size!(Foo, 4);
145///
146/// // Works fine
147/// assert_size!(Foo, 8);
148/// ```
149#[macro_export]
150macro_rules! assert_size {
151    ($target:ty, $size:expr) => {
152        const _: () = if core::mem::size_of::<$target>() != $size {
153            panic!(concat!(
154                "Size assertion failed! sizeof(",
155                stringify!($target),
156                ") != ",
157                stringify!($size)
158            ))
159        };
160    };
161}
162
163/// Asserts offset of the fields
164/// ```
165/// # use memflex::assert_offset;
166/// #[repr(C)]
167/// struct Foo {
168///     a: u32,
169///     b: i32
170/// }
171///
172/// assert_offset!(Foo, a, 0, b, 4);
173/// ```
174#[macro_export]
175macro_rules! assert_offset {
176    ($target:ty, $( $($field:ident).*, $offset:expr),* $(,)?) => {
177        $(
178            const _: () = if $crate::offset_of!($target, $($field).*) != $offset {
179                panic!(concat!(
180                    "Offset assertion failed! offset_of!(",
181                    stringify!($target),
182                    ", ",
183                    stringify!( $($field).* ),
184                    ") != ",
185                    stringify!($offset)
186                ))
187            };
188        )*
189    }
190}