hooks_rs/utils.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
use crate::api::*;
/// Comparable array of variables.
///
/// This can be used when manually calling `is_buffer_equal` to compare two arrays
/// is to be avoided.
///
/// Using ComparableArray over `is_buffer_equal` is generally preferred, since
/// it is more readable.
///
/// # Example
/// ```
/// const A: &[u8; 14] = b"same same same";
/// const B: &[u8; 14] = b"same same same";
///
/// const COMPARABLE_A: ComparableArray<u8, 14> = ComparableArray::new(A);
/// const COMPARABLE_B: ComparableArray<u8, 14> = ComparableArray::new(B);
///
/// if COMPARABLE_A != COMPARABLE_B {
/// rollback(b"arrays are not the same", -1);
/// }
/// ```
pub struct ComparableArray<'a, T, const N: usize>
where
T: PartialEq,
{
data: &'a [T; N],
}
/// Tests two buffers for equality, without needing to specify the max iteration count
/// or use a guard function.
///
/// # Example
/// ```
/// const A: &[u8; 14] = b"same same same";
/// const B: &[u8; 14] = b"same same same";
///
/// if !is_buffer_equal(A, B) {
/// rollback(b"arrays are not the same", -1);
/// }
/// ```
#[inline(always)]
pub fn is_buffer_equal<T: PartialEq>(buf_1: &[T], buf_2: &[T]) -> bool {
let buf1_len = buf_1.len();
if buf1_len != buf_2.len() {
return false;
};
// guarded loop
let mut i = 0;
while {
max_iter(buf1_len as u32 + 1);
i < buf1_len
} {
if buf_1[i] != buf_2[i] {
return false;
}
i += 1;
}
true
}
impl<'a, T: PartialEq, const N: usize> ComparableArray<'a, T, N> {
/// Create a new ComparableArray
#[inline(always)]
pub const fn new(data: &'a [T; N]) -> Self {
Self { data }
}
}
impl<T: PartialEq, const N: usize> AsRef<[T]> for ComparableArray<'_, T, N> {
fn as_ref(&self) -> &[T] {
self.data.as_ref()
}
}
impl<T, const N: usize> PartialEq for ComparableArray<'_, T, N>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
is_buffer_equal::<T>(self.as_ref(), other.as_ref())
}
}
impl<'a, T, const N: usize> From<&'a [T; N]> for ComparableArray<'a, T, N>
where
T: PartialEq,
{
fn from(data: &'a [T; N]) -> Self {
Self::new(data)
}
}
#[cfg(test)]
mod tests {
// use super::*;
// use wasm_bindgen_test::*;
// Due to some bug with wasm-pack or wasm-bindgen-test, this test does not compile.
// and wasm-pack test --node does not pick up #[ignore] attribute. It's probably due to
// the mutable-globals feature not being enabled for wasm-bindgen-test.
// #[wasm_bindgen_test]
// fn comparable_array_equal() {
// const A: ComparableArray<u8, 14> = ComparableArray::new(b"same same same");
// const B: ComparableArray<u8, 14> = ComparableArray::new(b"same same same");
// // assert_eq! requires ComparableArray to implement Debug trait,
// // but this is much simpler
// assert!(A == B);
// }
}