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
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ArrayError {
#[error("out of bounds access -- tried to access at index: {index} with length {length}")]
OutOfBounds { index: usize, length: usize },
}
/// Generates JS-exportable arrays that will run within the WASM
/// memory space. Also, since we're always cloning and not exposing
/// the inner vec as public, this new wrapper array should avoid
/// potential borrowing issues when interacting between JS and WASM.
macro_rules! declare_js_miden_arrays {
($(($miden_type_name:path) -> $miden_type_array_name:ident),+ $(,)?) => {
pub mod miden_arrays {
use crate::js_error_with_context;
use wasm_bindgen::prelude::*;
$(
#[wasm_bindgen(inspectable)]
#[derive(Clone)]
pub struct $miden_type_array_name {
pub (crate) __inner: Vec<$miden_type_name>,
}
#[wasm_bindgen]
impl $miden_type_array_name {
#[wasm_bindgen(constructor)]
pub fn new(elements: Option<Vec<$miden_type_name>>) -> Self {
let elements = elements.unwrap_or_else(|| vec![]);
Self { __inner: elements }
}
/// Get element at index, will always return a clone to avoid aliasing issues.
pub fn get(&self, index: usize) -> Result<$miden_type_name, wasm_bindgen::JsValue> {
match self.__inner.get(index) {
Some(value) => Ok(value.clone()),
None => {
let err = crate::miden_array::ArrayError::OutOfBounds {
index,
length: self.__inner.len(),
};
Err(js_error_with_context(
err,
&format!("array type is: {}", stringify!($miden_type_name)),
))
},
}
}
/// Replace the element at `index`. Borrows + clones the input
/// (mirrors `push`), so the caller's JS handle remains valid
/// after the call. Without this borrow, passing `elem` by
/// value would move the underlying Rust value out of the
/// caller's JS handle and any subsequent method on it would
/// panic with `"null pointer passed to rust"`.
#[wasm_bindgen(js_name = "replaceAt")]
pub fn replace_at(
&mut self,
index: usize,
elem: &$miden_type_name,
) -> Result<(), wasm_bindgen::JsValue> {
if let Some(value_at_index) = self.__inner.get_mut(index) {
*value_at_index = elem.clone();
Ok(())
} else {
let err =
crate::miden_array::ArrayError::OutOfBounds { index, length: self.__inner.len() };
Err(js_error_with_context(
err,
&format!("array type is: {}", stringify!($miden_type_name)),
))
}
}
pub fn push(&mut self, element: &$miden_type_name) {
self.__inner.push(element.clone());
}
pub fn length(&self) -> u32 {
u32::try_from(self.__inner.len()).expect("fatal: usize in wasm should be u32")
}
}
impl From<$miden_type_array_name> for Vec<$miden_type_name> {
fn from(array: $miden_type_array_name) -> Self {
return array.__inner;
}
}
impl From<&$miden_type_array_name> for Vec<$miden_type_name> {
fn from(array: &$miden_type_array_name) -> Self {
return array.__inner.clone();
}
}
impl From<Vec<$miden_type_name>> for $miden_type_array_name {
fn from(vec: Vec<$miden_type_name>) -> Self {
Self::new(Some(vec))
}
}
)+
}
};
}