nx/macros/
util.rs

1#![macro_use]
2
3/// Aligns a value up based on the provided alignment which should be a power of two.
4///
5/// # Arguments
6///
7/// * `val`: Expression that should resolve to an unsigned primitive integer type
8/// * `alignement`: Alignement value, that should resolve to the same type as `$val`
9///
10/// # Examples
11///
12/// ```
13/// let new_buffer_with_aligned_size = nx::mem::alloc::Buffer::new(size_of::<u128>(), max_object_count);
14/// ```
15#[macro_export]
16macro_rules! align_up {
17    ($val:expr, $alignment:expr ) => {{
18        debug_assert!(
19            ($alignment).is_power_of_two(),
20            "Alignment value must be a power of two"
21        );
22        let align_mask = ($alignment) - 1;
23        (($val) + align_mask) & !align_mask
24    }};
25}
26
27/// Checks if the provided value is aligned to the provided alignment
28///
29/// # Arguments
30///
31/// * `val`: Expression that should resolve to an unsigned primitive integer type
32/// * `alignement`: Alignement value, that should resolve to the same type as `$val`
33///
34/// # Examples
35///
36/// ```
37/// debug_assert!(is_aligned!(buffer.ptr, align_of::<T>()));
38/// ```
39#[macro_export]
40macro_rules! is_aligned {
41    ($val:expr, $alignment:expr ) => {{
42        debug_assert!(
43            ($alignment).is_power_of_two(),
44            "Alignment value must be a power of two"
45        );
46        let align_mask = ($alignment) - 1;
47        ($val) & align_mask == 0
48    }};
49}
50
51/// Gets a value corresponding to the given bit
52///
53/// # Arguments
54///
55/// * `val`: Bit index
56///
57/// # Examples
58///
59/// ```
60/// assert_eq!(bit!(0), 0b1);
61/// assert_eq!(bit!(1), 0b10);
62/// assert_eq!(bit!(5), 0b100000);
63/// ```
64#[macro_export]
65macro_rules! bit {
66    ($val:expr) => {
67        (1 << $val)
68    };
69}
70
71/// Defines a type meant to serve as a bitflag enum-like type
72///
73/// # Examples
74///
75/// ```
76/// bit_enum! {
77///    Test (u32) {
78///        A = bit!(1),
79///        B = bit!(2)
80///    }
81/// }
82/// ```
83#[macro_export]
84macro_rules! define_bit_enum {
85    (
86        $(#[$a_meta:meta])*
87        $name:ident ($base:ty) {
88            $(
89                $(#[$b_meta:meta])*
90                $entry_name:ident = $entry_value:expr
91            ),*
92        }
93    ) => {
94        $(#[$a_meta])*
95        #[derive($crate::ipc::sf::Request, $crate::ipc::sf::Response, Copy, Clone, PartialEq, Eq, Debug, Default)]
96        #[repr(C)]
97        pub struct $name($base);
98
99        #[allow(non_snake_case)]
100        impl $name {
101            /// Creates a `$name` from the underlying base type `$base`
102            pub const fn from(val: $base) -> Self {
103                Self(val)
104            }
105
106            /// Checks if the provided `$name` has all of the set bits in `other` are set in `self`
107            pub const fn contains(self, other: Self) -> bool {
108                (self.0 & other.0) == other.0
109            }
110
111            /// Returns the value as the underlying type
112            pub const fn get(self) -> $base {
113                self.0
114            }
115
116            $(
117                /// Returns a `$name` where only the bit for `$entry_name` is set
118                $(#[$b_meta])*
119                pub const fn $entry_name() -> Self {
120                    Self($entry_value)
121                }
122            )*
123        }
124
125        impl core::ops::BitOr for $name {
126            type Output = Self;
127
128            #[inline]
129            fn bitor(self, other: Self) -> Self {
130                Self(self.0 | other.0)
131            }
132        }
133
134        impl core::ops::BitAnd for $name {
135            type Output = Self;
136
137            #[inline]
138            fn bitand(self, other: Self) -> Self {
139                Self(self.0 & other.0)
140            }
141        }
142
143        impl core::ops::BitOrAssign for $name {
144            #[inline]
145            fn bitor_assign(&mut self, other: Self) {
146                self.0 |= other.0
147            }
148        }
149
150        impl core::ops::BitAndAssign for $name {
151            #[inline]
152            fn bitand_assign(&mut self, other: Self) {
153                self.0 &= other.0
154            }
155        }
156
157        impl core::ops::Not for $name {
158            type Output = Self;
159
160            #[inline]
161            fn not(self) -> Self {
162                Self(!self.0)
163            }
164        }
165    };
166}
167
168/// Constructs a `bit_enum` type value from various flags
169///
170/// # Examples
171///
172/// ```
173/// bit_enum! {
174///    Test (u32) {
175///        A = bit!(1),
176///        B = bit!(2)
177///    }
178/// }
179///
180/// // The equivalent to what would be "A | B"
181/// let test_ab = bit_group! { Test [A, B] };
182/// ```
183#[macro_export]
184macro_rules! bit_group {
185    ($base:ty [ $( $val:ident ),* ]) => {
186        <$base>::from( $( <$base>::$val().get() )|* )
187    };
188}
189
190/// Writes bits into a given value
191///
192/// # Arguments
193///
194/// * `start`: The start bit index (inclusive)
195/// * `end`: The end bit index (inclusive)
196/// * `value`: The value to write into
197/// * `data`: The value to set
198///
199/// # Examples
200///
201/// ```
202/// let value = 0u8;
203/// write_bits!(0, 3, value, 0b0110);
204/// write_bits!(4, 7, value, 0b1001);
205/// assert_eq!(value, 0b10010110);
206/// ```
207#[macro_export]
208macro_rules! write_bits {
209    ($start:expr, $end:expr, $value:expr, $data:expr) => {
210        $value = ($value & (!(((1 << ($end - $start + 1)) - 1) << $start))) | ($data << $start);
211    };
212}
213
214/// Reads bits from a given value
215///
216/// # Arguments
217///
218/// * `start`: The start bit index (inclusive)
219/// * `end`: The end bit index (inclusive)
220/// * `value`: The value
221///
222/// # Examples
223///
224/// ```
225/// let value = 0b11110000u8;
226/// assert_eq!(read_bits!(value, 0, 3), 0b0000);
227/// assert_eq!(read_bits!(value, 4, 7), 0b1111);
228/// ```
229#[macro_export]
230macro_rules! read_bits {
231    ($start:expr, $end:expr, $value:expr) => {
232        ($value & (((1 << ($end - $start + 1)) - 1) << $start)) >> $start
233    };
234}
235
236/// Creates a NUL-terminated string literal
237///
238/// # Arguments
239///
240/// * `lit`: The string literal
241///
242/// # Examples
243///
244/// ```
245/// assert_eq!("demo\0", nul!("demo"));
246/// ```
247#[macro_export]
248macro_rules! nul {
249    ($lit:literal) => {
250        concat!($lit, "\0")
251    };
252}
253
254/// Gets the current function name
255///
256/// # Examples
257///
258/// ```
259/// fn test() {
260///     assert_eq!(cur_fn_name!(), "test");
261/// }
262/// ```
263#[macro_export]
264macro_rules! cur_fn_name {
265    () => {{
266        fn dummy_fn() {}
267        const DUMMY_FN_EXTRA_SIZE: usize = "::dummy_fn".len();
268
269        fn type_name_of<T>(_: T) -> &'static str {
270            core::any::type_name::<T>()
271        }
272
273        let name = type_name_of(dummy_fn);
274        &name[..name.len() - DUMMY_FN_EXTRA_SIZE]
275    }};
276}