use crate::ast::js_conv::constant_from_js;
use crate::ast::js_conv::constant_to_js;
use crate::ergo_box::ErgoBox;
use crate::error_conversion::to_js;
use crate::utils::I64;
use ergo_lib::ergo_chain_types::Base16DecodedBytes;
use ergo_lib::ergo_chain_types::EcPoint;
use ergo_lib::ergotree_ir::base16_str::Base16Str;
use ergo_lib::ergotree_ir::mir::constant::{TryExtractFrom, TryExtractInto};
use ergo_lib::ergotree_ir::serialization::SigmaSerializable;
use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
use gloo_utils::format::JsValueSerdeExt;
use js_sys::Uint8Array;
use std::convert::TryFrom;
use wasm_bindgen::prelude::*;
extern crate derive_more;
use derive_more::{From, Into};
use ergo_lib::ergotree_ir::bigint256::BigInt256;
pub mod js_conv;
#[wasm_bindgen]
#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
pub struct Constant(ergo_lib::ergotree_ir::mir::constant::Constant);
#[wasm_bindgen]
impl Constant {
pub fn dbg_tpe(&self) -> String {
format!("{:?}", self.0.tpe)
}
pub fn dbg_inner(&self) -> String {
format!("{:?}", self.0)
}
pub fn decode_from_base16(base16_bytes_str: String) -> Result<Constant, JsValue> {
let bytes = Base16DecodedBytes::try_from(base16_bytes_str.clone()).map_err(|_| {
JsValue::from_str(&format!(
"failed to decode base16 from: {}",
base16_bytes_str.clone()
))
})?;
ergo_lib::ergotree_ir::mir::constant::Constant::try_from(bytes)
.map_err(to_js)
.map(Constant)
}
pub fn encode_to_base16(&self) -> Result<String, JsValue> {
self.0.base16_str().map_err(to_js)
}
pub fn sigma_serialize_bytes(&self) -> Result<Vec<u8>, JsValue> {
self.0
.sigma_serialize_bytes()
.map_err(|e| JsValue::from_str(&format! {"{:?}", e}))
}
pub fn from_i32(v: i32) -> Constant {
Constant(v.into())
}
pub fn to_i32(&self) -> Result<i32, JsValue> {
i32::try_extract_from(self.0.clone()).map_err(to_js)
}
pub fn from_i64(v: &I64) -> Constant {
Constant(i64::from((*v).clone()).into())
}
pub fn to_i64(&self) -> Result<I64, JsValue> {
i64::try_extract_from(self.0.clone())
.map_err(to_js)
.map(I64::from)
}
pub fn from_bigint_signed_bytes_be(num: &[u8]) -> Result<Constant, JsValue> {
Ok(Constant(
ergo_lib::ergotree_ir::mir::constant::Constant::from(BigInt256::try_from(num)?),
))
}
pub fn from_byte_array(v: &[u8]) -> Constant {
Constant(v.to_vec().into())
}
pub fn to_byte_array(&self) -> Result<Uint8Array, JsValue> {
Vec::<u8>::try_extract_from(self.0.clone())
.map(|v| Uint8Array::from(v.as_slice()))
.map_err(to_js)
}
#[allow(clippy::boxed_local)]
pub fn from_i32_array(arr: Box<[i32]>) -> Result<Constant, JsValue> {
arr.iter()
.try_fold(vec![], |mut acc, l| {
acc.push(*l);
Ok(acc)
})
.map(|longs| longs.into())
.map(Constant)
}
pub fn to_i32_array(&self) -> Result<Vec<i32>, JsValue> {
self.0
.clone()
.try_extract_into::<Vec<i32>>()
.map_err(|e| JsValue::from_str(&format!("Constant has wrong type: {:?}", e)))
}
#[allow(clippy::boxed_local)]
pub fn from_i64_str_array(arr: Box<[JsValue]>) -> Result<Constant, JsValue> {
arr.iter()
.try_fold(vec![], |mut acc, l| {
let b: i64 = if l.is_string() {
let l_str = l
.as_string()
.ok_or_else(|| JsValue::from_str("i64 as a string"))?;
serde_json::from_str(l_str.as_str())
} else {
JsValueSerdeExt::into_serde(l)
}
.map_err(|e| {
JsValue::from_str(&format!(
"Failed to parse i64 from JSON string: {:?} \n with error: {:?}",
l, e
))
})?;
acc.push(b);
Ok(acc)
})
.map(|longs| longs.into())
.map(Constant)
}
#[allow(clippy::boxed_local)]
pub fn to_i64_str_array(&self) -> Result<Box<[JsValue]>, JsValue> {
let vec_i64 = self
.0
.clone()
.try_extract_into::<Vec<i64>>()
.map_err(|e| JsValue::from_str(&format!("Constant has wrong type: {:?}", e)))?;
Ok(vec_i64
.iter()
.map(|it| JsValue::from_str(&it.to_string()))
.collect())
}
pub fn to_coll_coll_byte(&self) -> Result<Vec<Uint8Array>, JsValue> {
let vec_coll_byte = self
.0
.clone()
.try_extract_into::<Vec<Vec<u8>>>()
.map_err(to_js)?;
Ok(vec_coll_byte
.iter()
.map(|it| Uint8Array::from(it.as_slice()))
.collect())
}
pub fn from_coll_coll_byte(arr: Vec<Uint8Array>) -> Constant {
let mut acc: Vec<Vec<u8>> = vec![];
for bytes in arr.iter() {
acc.push(bytes.to_vec());
}
let c = ergo_lib::ergotree_ir::mir::constant::Constant::from(acc);
c.into()
}
pub fn from_ecpoint_bytes(bytes: &[u8]) -> Result<Constant, JsValue> {
let ecp = EcPoint::sigma_parse_bytes(bytes).map_err(to_js)?;
let c: ergo_lib::ergotree_ir::mir::constant::Constant = ProveDlog::new(ecp).into();
Ok(c.into())
}
pub fn from_ecpoint_bytes_group_element(bytes: &[u8]) -> Result<Constant, JsValue> {
let ecp = EcPoint::sigma_parse_bytes(bytes).map_err(to_js)?;
let c = ergo_lib::ergotree_ir::mir::constant::Constant::from(ecp);
Ok(c.into())
}
pub fn from_tuple_coll_bytes(bytes1: &[u8], bytes2: &[u8]) -> Constant {
let t = (bytes1.to_vec(), bytes2.to_vec());
let c: ergo_lib::ergotree_ir::mir::constant::Constant = t.into();
c.into()
}
pub fn to_tuple_coll_bytes(&self) -> Result<Vec<Uint8Array>, JsValue> {
let (bytes1, bytes2) = self
.0
.clone()
.try_extract_into::<(Vec<u8>, Vec<u8>)>()
.map_err(to_js)?;
Ok(vec![
Uint8Array::from(bytes1.as_slice()),
Uint8Array::from(bytes2.as_slice()),
])
}
pub fn to_tuple_i32(&self) -> Result<Vec<JsValue>, JsValue> {
let (i1, i2) = self
.0
.clone()
.try_extract_into::<(i32, i32)>()
.map_err(to_js)?;
Ok(vec![
JsValue::from_str(&i1.to_string()),
JsValue::from_str(&i2.to_string()),
])
}
pub fn from_tuple_i64(l1: &I64, l2: &I64) -> Constant {
let c: ergo_lib::ergotree_ir::mir::constant::Constant =
(i64::from((*l1).clone()), i64::from((*l2).clone())).into();
c.into()
}
pub fn to_tuple_i64(&self) -> Result<Vec<JsValue>, JsValue> {
let (l1, l2) = self
.0
.clone()
.try_extract_into::<(i64, i64)>()
.map_err(to_js)?;
Ok(vec![
JsValue::from_str(&l1.to_string()),
JsValue::from_str(&l2.to_string()),
])
}
pub fn from_ergo_box(v: &ErgoBox) -> Constant {
let b: ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox = v.clone().into();
let c: ergo_lib::ergotree_ir::mir::constant::Constant = b.into();
Constant(c)
}
pub fn to_ergo_box(&self) -> Result<ErgoBox, JsValue> {
self.0
.clone()
.try_extract_into::<ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox>()
.map(Into::into)
.map_err(to_js)
}
pub fn unit() -> Constant {
Constant(().into())
}
pub fn is_unit(&self) -> bool {
self.0.tpe == ergo_lib::ergotree_ir::types::stype::SType::SUnit
}
pub fn from_js(value: &JsValue) -> Result<Constant, JsValue> {
constant_from_js(value).map(Into::into).map_err(to_js)
}
pub fn to_js(&self) -> Result<JsValue, JsValue> {
constant_to_js(self.0.clone()).map_err(to_js)
}
}