bitcoin_internals/
const_tools.rs

1//! Contains tools (workarounds) to make implementing `const fn`s easier.
2
3/// Copies first `$len` bytes from `$slice` and returns them as an array.
4///
5/// Returns `None` if `$len > $slice.len()`. `$len` must be (obviously) statically known.
6/// Calling from non-const context doesn't affect performance.
7#[macro_export]
8macro_rules! copy_byte_array_from_slice {
9    ($slice:expr, $len:expr) => {
10        if $len > $slice.len() {
11            None
12        } else {
13            let mut array = [0u8; $len];
14            // Note: produces same assemble as copy_from_slice
15            let mut i = 0;
16            while i < $len {
17                array[i] = $slice[i];
18                i += 1;
19            }
20            Some(array)
21        }
22    };
23}
24pub use copy_byte_array_from_slice;
25
26/// Concatenates two byte slices or byte arrays (or combination) to a single array.
27///
28/// # Panics
29///
30/// This macro panics if `$len` is not equal to the sum of `$a.len()` and `$b.len()`.
31#[macro_export]
32macro_rules! concat_bytes_to_arr {
33    ($a:expr, $b:expr, $len:expr) => {{
34        // avoid repeated eval
35        let a = $a;
36        let b = $b;
37
38        #[allow(unconditional_panic)]
39        let _ = [(); 1][($len != a.len() + b.len()) as usize];
40
41        let mut output = [0u8; $len];
42        let mut i = 0;
43        while i < a.len() {
44            output[i] = $a[i];
45            i += 1;
46        }
47        while i < a.len() + b.len() {
48            output[i] = b[i - a.len()];
49            i += 1;
50        }
51        output
52    }};
53}
54pub use concat_bytes_to_arr;
55
56#[macro_export]
57/// Enables const fn in specified Rust version
58macro_rules! cond_const {
59    ($($(#[$attr:meta])* $vis:vis const(in $version:tt) fn $name:ident$(<$($gen:tt)*>)?($($args:tt)*) $(-> $ret:ty)? $body:block)+ ) => {
60        $(
61            $crate::rust_version::rust_version! {
62                if >= $version {
63                    $(#[$attr])*
64                    #[doc = concat!("\nNote: the function is only `const` in Rust ", stringify!($version), ".")]
65                    $vis const fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
66                } else {
67                    $(#[$attr])*
68                    #[doc = concat!("\nNote: the function is `const` in Rust ", stringify!($version), ".")]
69                    $vis fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
70                }
71            }
72        )+
73    };
74    ($($(#[$attr:meta])* $vis:vis const(in $version:tt) unsafe fn $name:ident$(<$($gen:tt)*>)?($($args:tt)*) $(-> $ret:ty)? $body:block)+ ) => {
75        $(
76            $crate::rust_version::rust_version! {
77                if >= $version {
78                    $(#[$attr])*
79                    #[doc = concat!("\nNote: the function is only `const` in Rust ", stringify!($version), ".")]
80                    $vis const unsafe fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
81                } else {
82                    $(#[$attr])*
83                    #[doc = concat!("\nNote: the function is `const` in Rust ", stringify!($version), ".")]
84                    $vis unsafe fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
85                }
86            }
87        )+
88    };
89}
90pub use cond_const;