miden-client-web 0.15.0

Web Client library that facilitates interaction with the Miden network
#[cfg(feature = "browser")]
use thiserror::Error;

#[cfg(feature = "browser")]
#[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 },
}

/// Implements `FromNapiValue` for napi class types that have `FromNapiRef` + `Clone`.
///
/// napi-rs v3 generates `FromNapiRef` (borrow) for `#[napi]` class types but NOT
/// `FromNapiValue` (by-value). This macro bridges the gap so these types can be used
/// as by-value parameters and inside `Vec<T>` parameters.
#[cfg(feature = "nodejs")]
macro_rules! impl_napi_from_value {
    ($t:ty) => {
        impl napi::bindgen_prelude::FromNapiValue for $t {
            unsafe fn from_napi_value(
                env: napi::bindgen_prelude::sys::napi_env,
                napi_val: napi::bindgen_prelude::sys::napi_value,
            ) -> napi::Result<Self> {
                let ref_val = unsafe {
                    <$t as napi::bindgen_prelude::FromNapiRef>::from_napi_ref(env, napi_val)?
                };
                Ok(ref_val.clone())
            }
        }
    };
}

/// No-op for browser builds.
#[cfg(feature = "browser")]
macro_rules! impl_napi_from_value {
    ($t:ty) => {};
}

/// Browser variant: Generates JS-exportable array wrapper types using `wasm_bindgen`.
#[cfg(feature = "browser")]
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)),
                            ))
                        },
                    }
                }

                #[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;
                        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 $miden_type_array_name {
                pub fn iter(&self) -> core::slice::Iter<'_, $miden_type_name> {
                    self.__inner.iter()
                }
            }

            impl IntoIterator for $miden_type_array_name {
                type Item = $miden_type_name;
                type IntoIter = alloc::vec::IntoIter<$miden_type_name>;

                fn into_iter(self) -> Self::IntoIter {
                    self.__inner.into_iter()
                }
            }

            impl<'a> IntoIterator for &'a $miden_type_array_name {
                type Item = &'a $miden_type_name;
                type IntoIter = core::slice::Iter<'a, $miden_type_name>;

                fn into_iter(self) -> Self::IntoIter {
                    self.__inner.iter()
                }
            }

            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))
                }
            }
        )+
    }
    };
}

/// Node.js variant: Creates newtype wrapper structs around `Vec<T>` that implement
/// `FromNapiRef` and `FromNapiValue`, allowing them to be used as `&ArrayType` parameters
/// in `#[napi]` functions. The wrappers deref to `Vec<T>` for ergonomic access.
#[cfg(feature = "nodejs")]
macro_rules! declare_js_miden_arrays {
    ($(($miden_type_name:path) -> $miden_type_array_name:ident),+ $(,)?) => {
    pub mod miden_arrays {
        $(
            #[derive(Clone)]
            pub struct $miden_type_array_name(pub(crate) Vec<$miden_type_name>);

            impl std::ops::Deref for $miden_type_array_name {
                type Target = Vec<$miden_type_name>;
                fn deref(&self) -> &Self::Target {
                    &self.0
                }
            }

            impl std::ops::DerefMut for $miden_type_array_name {
                fn deref_mut(&mut self) -> &mut Self::Target {
                    &mut self.0
                }
            }

            impl From<$miden_type_array_name> for Vec<$miden_type_name> {
                fn from(array: $miden_type_array_name) -> Self {
                    array.0
                }
            }

            impl From<&$miden_type_array_name> for Vec<$miden_type_name> {
                fn from(array: &$miden_type_array_name) -> Self {
                    array.0.clone()
                }
            }

            impl From<Vec<$miden_type_name>> for $miden_type_array_name {
                fn from(vec: Vec<$miden_type_name>) -> Self {
                    Self(vec)
                }
            }

            impl $miden_type_array_name {
                pub fn iter(&self) -> std::slice::Iter<'_, $miden_type_name> {
                    self.0.iter()
                }
            }

            impl IntoIterator for $miden_type_array_name {
                type Item = $miden_type_name;
                type IntoIter = std::vec::IntoIter<$miden_type_name>;

                fn into_iter(self) -> Self::IntoIter {
                    self.0.into_iter()
                }
            }

            impl<'a> IntoIterator for &'a $miden_type_array_name {
                type Item = &'a $miden_type_name;
                type IntoIter = std::slice::Iter<'a, $miden_type_name>;

                fn into_iter(self) -> Self::IntoIter {
                    self.0.iter()
                }
            }

            impl napi::bindgen_prelude::TypeName for $miden_type_array_name {
                fn type_name() -> &'static str {
                    concat!("Array<", stringify!($miden_type_name), ">")
                }

                fn value_type() -> napi::ValueType {
                    napi::ValueType::Object
                }
            }

            impl napi::bindgen_prelude::TypeName for &$miden_type_array_name {
                fn type_name() -> &'static str {
                    concat!("Array<", stringify!($miden_type_name), ">")
                }

                fn value_type() -> napi::ValueType {
                    napi::ValueType::Object
                }
            }

            impl napi::bindgen_prelude::TypeName for &mut $miden_type_array_name {
                fn type_name() -> &'static str {
                    concat!("Array<", stringify!($miden_type_name), ">")
                }

                fn value_type() -> napi::ValueType {
                    napi::ValueType::Object
                }
            }

            impl napi::bindgen_prelude::ValidateNapiValue for $miden_type_array_name {
                unsafe fn validate(
                    env: napi::bindgen_prelude::sys::napi_env,
                    napi_val: napi::bindgen_prelude::sys::napi_value,
                ) -> napi::Result<napi::bindgen_prelude::sys::napi_value> {
                    unsafe { <Vec<$miden_type_name> as napi::bindgen_prelude::ValidateNapiValue>::validate(env, napi_val) }
                }
            }

            impl napi::bindgen_prelude::FromNapiValue for $miden_type_array_name {
                unsafe fn from_napi_value(
                    env: napi::bindgen_prelude::sys::napi_env,
                    napi_val: napi::bindgen_prelude::sys::napi_value,
                ) -> napi::Result<Self> {
                    let vec = unsafe { <Vec<$miden_type_name> as napi::bindgen_prelude::FromNapiValue>::from_napi_value(env, napi_val)? };
                    Ok(Self(vec))
                }
            }

            impl napi::bindgen_prelude::ToNapiValue for $miden_type_array_name {
                unsafe fn to_napi_value(
                    env: napi::bindgen_prelude::sys::napi_env,
                    val: Self,
                ) -> napi::Result<napi::bindgen_prelude::sys::napi_value> {
                    unsafe { <Vec<$miden_type_name> as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, val.0) }
                }
            }

            impl napi::bindgen_prelude::ToNapiValue for &$miden_type_array_name {
                unsafe fn to_napi_value(
                    env: napi::bindgen_prelude::sys::napi_env,
                    val: Self,
                ) -> napi::Result<napi::bindgen_prelude::sys::napi_value> {
                    unsafe { <Vec<$miden_type_name> as napi::bindgen_prelude::ToNapiValue>::to_napi_value(env, val.0.clone()) }
                }
            }
        )+
    }
    };
}