use gloo_utils::format::JsValueSerdeExt;
use std::{ops::Deref, str::FromStr};
use wasm_bindgen::prelude::*;
macro_rules! impl_big_int {
($name:ident) => {
#[derive(Debug, Clone, Copy, serde::Deserialize, serde::Serialize)]
#[wasm_bindgen(inspectable)]
pub struct $name(casper_types::$name);
#[wasm_bindgen]
impl $name {
#[wasm_bindgen(constructor)]
pub fn from_dec_str(value: &str) -> Result<Self, JsError> {
Ok($name(
casper_types::$name::from_dec_str(value)
.map_err(|e| JsError::new(&format!("{:?}", e)))?
))
}
#[wasm_bindgen(js_name = "fromNumber")]
pub fn from_u32(value: u32) -> Self {
$name(casper_types::$name::from(value))
}
#[wasm_bindgen(js_name = "fromHtmlInput")]
pub fn from_input(input: web_sys::HtmlInputElement) -> Result<Self, JsError> {
let value = input.value();
Self::from_dec_str(value.trim())
}
#[wasm_bindgen(js_name = "fromBigInt")]
pub fn from_js_big_int(value: &js_sys::BigInt) -> Result<Self, JsError> {
let v = value
.to_string(10)
.map(|s| s.as_string())
.unwrap_or_default()
.unwrap_or_default();
Self::from_dec_str(&v)
}
#[wasm_bindgen(js_name = "toString")]
pub fn to_string_js_alias(&self) -> String {
self.0.to_string()
}
#[wasm_bindgen(js_name = "toJson")]
pub fn to_json(&self) -> JsValue {
JsValue::from_serde(self).unwrap_or(JsValue::null())
}
#[wasm_bindgen(js_name = "formatter")]
pub fn formatter(&self, decimals: usize) -> crate::utils::BalanceFormatter {
crate::utils::BalanceFormatter::new(self, decimals)
}
#[wasm_bindgen(js_name = "mul")]
pub fn mul(&self, other: &Self) -> Self {
Self(self.0 * other.0)
}
#[wasm_bindgen(js_name = "mulBigInt")]
pub fn mul_bigint(&self, other: &js_sys::BigInt) -> Result<Self, JsError> {
let other = Self::from_js_big_int(other)?;
Ok(Self(self.0 * other.0))
}
#[wasm_bindgen(js_name = "div")]
pub fn div(&self, other: &Self) -> Self {
Self(self.0 / other.0)
}
#[wasm_bindgen(js_name = "divBigInt")]
pub fn div_bigint(&self, other: &js_sys::BigInt) -> Result<Self, JsError> {
let other = Self::from_js_big_int(other)?;
Ok(Self(self.0 / other.0))
}
#[wasm_bindgen(js_name = "add")]
pub fn add(&self, other: &Self) -> Self {
Self(self.0 + other.0)
}
#[wasm_bindgen(js_name = "addBigInt")]
pub fn add_bigint(&self, other: &js_sys::BigInt) -> Result<Self, JsError> {
let other = Self::from_js_big_int(other)?;
Ok(Self(self.0 + other.0))
}
#[wasm_bindgen(js_name = "sub")]
pub fn sub(&self, other: &Self) -> Self {
Self(self.0 - other.0)
}
#[wasm_bindgen(js_name = "subBigInt")]
pub fn sub_bigint(&self, other: &js_sys::BigInt) -> Result<Self, JsError> {
let other = Self::from_js_big_int(other)?;
Ok(Self(self.0 - other.0))
}
#[wasm_bindgen(js_name = "checkedMul")]
pub fn checked_mul(&self, other: &Self) -> Option<Self> {
self.0.checked_mul(other.0).map(Self)
}
#[wasm_bindgen(js_name = "checkedAdd")]
pub fn checked_add(&self, other: &Self) -> Option<Self> {
self.0.checked_add(other.0).map(Self)
}
#[wasm_bindgen(js_name = "checkedSub")]
pub fn checked_sub(&self, other: &Self) -> Option<Self> {
self.0.checked_sub(other.0).map(Self)
}
#[wasm_bindgen(js_name = "checkedDiv")]
pub fn checked_div(&self, other: &Self) -> Option<Self> {
self.0.checked_div(other.0).map(Self)
}
#[wasm_bindgen(js_name = "checkedRem")]
pub fn checked_rem(&self, other: &Self) -> Option<Self> {
self.0.checked_rem(other.0).map(Self)
}
#[wasm_bindgen(js_name = "checkedPow")]
pub fn checked_pow(&self, exp: u32) -> Option<Self> {
self.0.checked_pow(*Self::from_u32(exp)).map(Self)
}
#[wasm_bindgen(js_name = "toBigInt")]
pub fn to_big_int(&self) -> js_sys::BigInt {
js_sys::BigInt::from_str(&self.0.to_string())
.expect("decimal string must be valid BigInt")
}
#[wasm_bindgen(js_name = "lt")]
pub fn lt(&self, other: &Self) -> bool {
self.0 < other.0
}
#[wasm_bindgen(js_name = "le")]
pub fn le(&self, other: &Self) -> bool {
self.0 <= other.0
}
#[wasm_bindgen(js_name = "gt")]
pub fn gt(&self, other: &Self) -> bool {
self.0 > other.0
}
#[wasm_bindgen(js_name = "ge")]
pub fn ge(&self, other: &Self) -> bool {
self.0 >= other.0
}
#[wasm_bindgen(getter)]
pub fn value(&self) -> String {
self.to_string()
}
#[wasm_bindgen(js_name = "MAX")]
pub fn max_value() -> Self {
Self(casper_types::$name::MAX)
}
#[wasm_bindgen(js_name = "zero")]
pub fn zero() -> Self {
Self(casper_types::$name::zero())
}
}
impl Deref for $name {
type Target = casper_types::$name;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<$name> for casper_types::$name {
fn from(value: $name) -> Self {
value.0
}
}
impl From<casper_types::$name> for $name {
fn from(value: casper_types::$name) -> Self {
$name(value)
}
}
impl From<String> for $name {
fn from(value: String) -> Self {
$name::from_dec_str(&value).unwrap_or_else(|_| $name(casper_types::$name::zero()))
}
}
impl From<&str> for $name {
fn from(value: &str) -> Self {
$name::from_dec_str(value).unwrap_or_else(|_| $name(casper_types::$name::zero()))
}
}
impl Default for $name {
fn default() -> Self {
$name(casper_types::$name::zero())
}
}
impl core::fmt::Display for $name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.0)
}
}
};
}
impl_big_int!(U128);
impl_big_int!(U256);
impl_big_int!(U512);
#[wasm_bindgen]
pub struct OverflowingResultU128 {
#[wasm_bindgen(readonly)]
pub result: U128,
#[wasm_bindgen(readonly)]
pub overflow: bool
}
#[wasm_bindgen]
pub struct OverflowingResultU256 {
#[wasm_bindgen(readonly)]
pub result: U256,
#[wasm_bindgen(readonly)]
pub overflow: bool
}
#[wasm_bindgen]
pub struct OverflowingResultU512 {
#[wasm_bindgen(readonly)]
pub result: U512,
#[wasm_bindgen(readonly)]
pub overflow: bool
}
#[wasm_bindgen]
impl U128 {
#[wasm_bindgen(js_name = "overflowingMul")]
pub fn overflowing_mul(&self, other: &Self) -> OverflowingResultU128 {
let (res, overflow) = self.0.overflowing_mul(other.0);
OverflowingResultU128 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingAdd")]
pub fn overflowing_add(&self, other: &Self) -> OverflowingResultU128 {
let (res, overflow) = self.0.overflowing_add(other.0);
OverflowingResultU128 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingSub")]
pub fn overflowing_sub(&self, other: &Self) -> OverflowingResultU128 {
let (res, overflow) = self.0.overflowing_sub(other.0);
OverflowingResultU128 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingPow")]
pub fn overflowing_pow(&self, exp: u32) -> OverflowingResultU128 {
let (res, overflow) = self.0.overflowing_pow(*Self::from_u32(exp));
OverflowingResultU128 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "fromU512")]
pub fn from_u512(value: U512) -> Result<Self, JsError> {
let max_u128 = (casper_types::U512::one() << 128) - 1;
if value.0 > max_u128 {
return Err(JsError::new("Value exceeds U128 maximum"));
}
let src = value.0 .0;
let mut words = [0u64; 2];
words.copy_from_slice(&src[0..2]);
Ok(casper_types::U128(words).into())
}
#[wasm_bindgen(js_name = "toU512")]
pub fn to_u512(&self) -> U512 {
let mut bytes = [0u8; 16];
self.to_little_endian(&mut bytes);
casper_types::U512::from_little_endian(&bytes).into()
}
#[wasm_bindgen(js_name = "fromU256")]
pub fn from_u256(value: U256) -> Result<Self, JsError> {
let max_u128 = (casper_types::U256::one() << 128) - 1;
if value.0 > max_u128 {
return Err(JsError::new("Value exceeds U128 maximum"));
}
let src = value.0 .0;
let mut words = [0u64; 2];
words.copy_from_slice(&src[0..2]);
Ok(casper_types::U128(words).into())
}
#[wasm_bindgen(js_name = "toU256")]
pub fn to_u256(&self) -> U256 {
let mut bytes = [0u8; 16];
self.to_little_endian(&mut bytes);
casper_types::U256::from_little_endian(&bytes).into()
}
}
#[wasm_bindgen]
impl U256 {
#[wasm_bindgen(js_name = "overflowingMul")]
pub fn overflowing_mul(&self, other: &Self) -> OverflowingResultU256 {
let (res, overflow) = self.0.overflowing_mul(other.0);
OverflowingResultU256 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingAdd")]
pub fn overflowing_add(&self, other: &Self) -> OverflowingResultU256 {
let (res, overflow) = self.0.overflowing_add(other.0);
OverflowingResultU256 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingSub")]
pub fn overflowing_sub(&self, other: &Self) -> OverflowingResultU256 {
let (res, overflow) = self.0.overflowing_sub(other.0);
OverflowingResultU256 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingPow")]
pub fn overflowing_pow(&self, exp: u32) -> OverflowingResultU256 {
let (res, overflow) = self.0.overflowing_pow(*Self::from_u32(exp));
OverflowingResultU256 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "fromU512")]
pub fn from_u512(value: U512) -> Result<Self, JsError> {
let max_u256 = (casper_types::U512::one() << 256) - 1;
if value.0 > max_u256 {
return Err(JsError::new("Value exceeds U256 maximum"));
}
let src = value.0 .0;
let mut words = [0u64; 4];
words.copy_from_slice(&src[0..4]);
Ok(U256(casper_types::U256(words)))
}
#[wasm_bindgen(js_name = "toU512")]
pub fn to_u512(&self) -> U512 {
let mut bytes = [0u8; 32];
self.to_little_endian(&mut bytes);
casper_types::U512::from_little_endian(&bytes).into()
}
}
#[wasm_bindgen]
impl U512 {
#[wasm_bindgen(js_name = "overflowingMul")]
pub fn overflowing_mul(&self, other: &Self) -> OverflowingResultU512 {
let (res, overflow) = self.0.overflowing_mul(other.0);
OverflowingResultU512 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingAdd")]
pub fn overflowing_add(&self, other: &Self) -> OverflowingResultU512 {
let (res, overflow) = self.0.overflowing_add(other.0);
OverflowingResultU512 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingSub")]
pub fn overflowing_sub(&self, other: &Self) -> OverflowingResultU512 {
let (res, overflow) = self.0.overflowing_sub(other.0);
OverflowingResultU512 {
result: Self(res),
overflow
}
}
#[wasm_bindgen(js_name = "overflowingPow")]
pub fn overflowing_pow(&self, exp: u32) -> OverflowingResultU512 {
let (res, overflow) = self.0.overflowing_pow(*Self::from_u32(exp));
OverflowingResultU512 {
result: Self(res),
overflow
}
}
}