1use crate::ast::js_conv::constant_from_js;
4use crate::ast::js_conv::constant_to_js;
5use crate::ergo_box::ErgoBox;
6use crate::error_conversion::to_js;
7use crate::utils::I64;
8use ergo_lib::ergo_chain_types::Base16DecodedBytes;
9use ergo_lib::ergo_chain_types::EcPoint;
10use ergo_lib::ergotree_ir::base16_str::Base16Str;
11use ergo_lib::ergotree_ir::chain::ergo_box::RegisterValue;
12use ergo_lib::ergotree_ir::mir::constant::{TryExtractFrom, TryExtractInto};
13use ergo_lib::ergotree_ir::serialization::SigmaSerializable;
14use ergo_lib::ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
15use gloo_utils::format::JsValueSerdeExt;
16use js_sys::Uint8Array;
17use std::convert::TryFrom;
18use wasm_bindgen::prelude::*;
19
20extern crate derive_more;
21use derive_more::{From, Into};
22use ergo_lib::ergotree_ir::bigint256::BigInt256;
23
24pub mod js_conv;
25
26#[wasm_bindgen]
28#[derive(PartialEq, Eq, Debug, Clone, From, Into)]
29pub struct Constant(ergo_lib::ergotree_ir::mir::constant::Constant);
30
31#[wasm_bindgen]
32impl Constant {
33 pub fn dbg_tpe(&self) -> String {
35 format!("{:?}", self.0.tpe)
36 }
37
38 pub fn dbg_inner(&self) -> String {
40 format!("{:?}", self.0)
41 }
42
43 pub fn decode_from_base16(base16_bytes_str: String) -> Result<Constant, JsValue> {
45 let bytes = Base16DecodedBytes::try_from(base16_bytes_str.clone()).map_err(|_| {
46 JsValue::from_str(&format!(
47 "failed to decode base16 from: {}",
48 base16_bytes_str.clone()
49 ))
50 })?;
51
52 let register_value = RegisterValue::sigma_parse_bytes(bytes.as_ref());
53 register_value
54 .as_constant()
55 .cloned()
56 .map_err(to_js)
57 .map(Constant)
58 }
59
60 pub fn encode_to_base16(&self) -> Result<String, JsValue> {
63 self.0.base16_str().map_err(to_js)
64 }
65
66 pub fn sigma_serialize_bytes(&self) -> Result<Vec<u8>, JsValue> {
68 self.0
69 .sigma_serialize_bytes()
70 .map_err(|e| JsValue::from_str(&format! {"{:?}", e}))
71 }
72
73 pub fn from_i32(v: i32) -> Constant {
75 Constant(v.into())
76 }
77
78 pub fn to_i32(&self) -> Result<i32, JsValue> {
80 i32::try_extract_from(self.0.clone()).map_err(to_js)
81 }
82
83 pub fn from_i64(v: &I64) -> Constant {
85 Constant(i64::from((*v).clone()).into())
86 }
87
88 pub fn to_i64(&self) -> Result<I64, JsValue> {
90 i64::try_extract_from(self.0.clone())
91 .map_err(to_js)
92 .map(I64::from)
93 }
94
95 pub fn from_bigint_signed_bytes_be(num: &[u8]) -> Result<Constant, JsValue> {
97 Ok(Constant(
98 ergo_lib::ergotree_ir::mir::constant::Constant::from(BigInt256::try_from(num)?),
99 ))
100 }
101
102 pub fn from_byte_array(v: &[u8]) -> Constant {
104 Constant(v.to_vec().into())
105 }
106
107 pub fn to_byte_array(&self) -> Result<Uint8Array, JsValue> {
109 Vec::<u8>::try_extract_from(self.0.clone())
110 .map(|v| Uint8Array::from(v.as_slice()))
111 .map_err(to_js)
112 }
113
114 #[allow(clippy::boxed_local)]
116 pub fn from_i32_array(arr: Box<[i32]>) -> Result<Constant, JsValue> {
117 arr.iter()
118 .try_fold(vec![], |mut acc, l| {
119 acc.push(*l);
120 Ok(acc)
121 })
122 .map(|longs| longs.into())
123 .map(Constant)
124 }
125
126 pub fn to_i32_array(&self) -> Result<Vec<i32>, JsValue> {
128 self.0
129 .clone()
130 .try_extract_into::<Vec<i32>>()
131 .map_err(|e| JsValue::from_str(&format!("Constant has wrong type: {:?}", e)))
132 }
133
134 #[allow(clippy::boxed_local)]
136 pub fn from_i64_str_array(arr: Box<[JsValue]>) -> Result<Constant, JsValue> {
137 arr.iter()
138 .try_fold(vec![], |mut acc, l| {
139 let b: i64 = if l.is_string() {
140 let l_str = l
141 .as_string()
142 .ok_or_else(|| JsValue::from_str("i64 as a string"))?;
143 serde_json::from_str(l_str.as_str())
144 } else {
145 JsValueSerdeExt::into_serde(l)
146 }
147 .map_err(|e| {
148 JsValue::from_str(&format!(
149 "Failed to parse i64 from JSON string: {:?} \n with error: {:?}",
150 l, e
151 ))
152 })?;
153 acc.push(b);
154 Ok(acc)
155 })
156 .map(|longs| longs.into())
157 .map(Constant)
158 }
159
160 #[allow(clippy::boxed_local)]
162 pub fn to_i64_str_array(&self) -> Result<Box<[JsValue]>, JsValue> {
163 let vec_i64 = self
164 .0
165 .clone()
166 .try_extract_into::<Vec<i64>>()
167 .map_err(|e| JsValue::from_str(&format!("Constant has wrong type: {:?}", e)))?;
168 Ok(vec_i64
169 .iter()
170 .map(|it| JsValue::from_str(&it.to_string()))
171 .collect())
172 }
173
174 pub fn to_coll_coll_byte(&self) -> Result<Vec<Uint8Array>, JsValue> {
176 let vec_coll_byte = self
177 .0
178 .clone()
179 .try_extract_into::<Vec<Vec<u8>>>()
180 .map_err(to_js)?;
181 Ok(vec_coll_byte
182 .iter()
183 .map(|it| Uint8Array::from(it.as_slice()))
184 .collect())
185 }
186
187 pub fn from_coll_coll_byte(arr: Vec<Uint8Array>) -> Constant {
189 let mut acc: Vec<Vec<u8>> = vec![];
190 for bytes in arr.iter() {
191 acc.push(bytes.to_vec());
192 }
193 let c = ergo_lib::ergotree_ir::mir::constant::Constant::from(acc);
194 c.into()
195 }
196
197 pub fn from_ecpoint_bytes(bytes: &[u8]) -> Result<Constant, JsValue> {
199 let ecp = EcPoint::sigma_parse_bytes(bytes).map_err(to_js)?;
200 let c: ergo_lib::ergotree_ir::mir::constant::Constant = ProveDlog::new(ecp).into();
201 Ok(c.into())
202 }
203
204 pub fn from_ecpoint_bytes_group_element(bytes: &[u8]) -> Result<Constant, JsValue> {
206 let ecp = EcPoint::sigma_parse_bytes(bytes).map_err(to_js)?;
207 let c = ergo_lib::ergotree_ir::mir::constant::Constant::from(ecp);
208 Ok(c.into())
209 }
210
211 pub fn from_tuple_coll_bytes(bytes1: &[u8], bytes2: &[u8]) -> Constant {
213 let t = (bytes1.to_vec(), bytes2.to_vec());
214 let c: ergo_lib::ergotree_ir::mir::constant::Constant = t.into();
215 c.into()
216 }
217
218 pub fn to_tuple_coll_bytes(&self) -> Result<Vec<Uint8Array>, JsValue> {
220 let (bytes1, bytes2) = self
221 .0
222 .clone()
223 .try_extract_into::<(Vec<u8>, Vec<u8>)>()
224 .map_err(to_js)?;
225 Ok(vec![
226 Uint8Array::from(bytes1.as_slice()),
227 Uint8Array::from(bytes2.as_slice()),
228 ])
229 }
230
231 pub fn to_tuple_i32(&self) -> Result<Vec<JsValue>, JsValue> {
233 let (i1, i2) = self
234 .0
235 .clone()
236 .try_extract_into::<(i32, i32)>()
237 .map_err(to_js)?;
238 Ok(vec![
239 JsValue::from_str(&i1.to_string()),
240 JsValue::from_str(&i2.to_string()),
241 ])
242 }
243
244 pub fn from_tuple_i64(l1: &I64, l2: &I64) -> Constant {
246 let c: ergo_lib::ergotree_ir::mir::constant::Constant =
247 (i64::from((*l1).clone()), i64::from((*l2).clone())).into();
248 c.into()
249 }
250
251 pub fn to_tuple_i64(&self) -> Result<Vec<JsValue>, JsValue> {
253 let (l1, l2) = self
254 .0
255 .clone()
256 .try_extract_into::<(i64, i64)>()
257 .map_err(to_js)?;
258 Ok(vec![
259 JsValue::from_str(&l1.to_string()),
260 JsValue::from_str(&l2.to_string()),
261 ])
262 }
263
264 pub fn from_ergo_box(v: &ErgoBox) -> Constant {
266 let b: ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox = v.clone().into();
267 let c: ergo_lib::ergotree_ir::mir::constant::Constant = b.into();
268 Constant(c)
269 }
270
271 pub fn to_ergo_box(&self) -> Result<ErgoBox, JsValue> {
273 self.0
274 .clone()
275 .try_extract_into::<ergo_lib::ergotree_ir::chain::ergo_box::ErgoBox>()
276 .map(Into::into)
277 .map_err(to_js)
278 }
279
280 pub fn unit() -> Constant {
282 Constant(().into())
283 }
284
285 pub fn is_unit(&self) -> bool {
287 self.0.tpe == ergo_lib::ergotree_ir::types::stype::SType::SUnit
288 }
289
290 pub fn from_js(value: &JsValue) -> Result<Constant, JsValue> {
297 constant_from_js(value).map(Into::into).map_err(to_js)
298 }
299
300 pub fn to_js(&self) -> Result<JsValue, JsValue> {
309 constant_to_js(self.0.clone()).map_err(to_js)
310 }
311}