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 $ver:ident $(= $human_ver:literal)?) fn $name:ident$(<$($gen:tt)*>)?($($args:tt)*) $(-> $ret:ty)? $body:block)+ ) => {
60        $(
61            #[cfg($ver)]
62            $(#[$attr])*
63            $(
64                #[doc = "\nNote: the function is only `const` in Rust "]
65                #[doc = $human_ver]
66                #[doc = "."]
67            )?
68            $vis const fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
69
70            #[cfg(not($ver))]
71            $(#[$attr])*
72            $vis fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
73        )+
74    };
75    ($($(#[$attr:meta])* $vis:vis const(in $ver:ident $(= $human_ver:literal)?) unsafe fn $name:ident$(<$($gen:tt)*>)?($($args:tt)*) $(-> $ret:ty)? $body:block)+ ) => {
76        $(
77            #[cfg($ver)]
78            $(#[$attr])*
79            $(
80                #[doc = "\nNote: the function is only `const` in Rust "]
81                #[doc = $human_ver]
82                #[doc = " and newer."]
83            )?
84            $vis const unsafe fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
85
86            #[cfg(not($ver))]
87            $(#[$attr])*
88            $vis unsafe fn $name$(<$($gen)*>)?($($args)*) $(-> $ret)? $body
89        )+
90    };
91}
92pub use cond_const;