ergotree_ir/mir/
constant.rs

1//! Constant(Literal) IR node
2
3use crate::base16_str::Base16Str;
4use crate::bigint256::BigInt256;
5use crate::chain::ergo_box::ErgoBox;
6use crate::chain::token::TokenId;
7use crate::mir::value::CollKind;
8use crate::reference::Ref;
9use crate::serialization::SigmaParsingError;
10use crate::serialization::SigmaSerializable;
11use crate::serialization::SigmaSerializationError;
12use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
13use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
14use crate::sigma_protocol::sigma_boolean::SigmaProp;
15use crate::sigma_protocol::sigma_boolean::{ProveDhTuple, ProveDlog};
16use crate::types::stuple::STuple;
17use crate::types::stuple::TupleItems;
18use crate::types::stype::LiftIntoSType;
19use crate::types::stype::SType;
20use ergo_chain_types::ADDigest;
21use ergo_chain_types::Base16DecodedBytes;
22use ergo_chain_types::Digest32;
23use ergo_chain_types::EcPoint;
24use impl_trait_for_tuples::impl_for_tuples;
25use sigma_util::AsVecI8;
26use sigma_util::AsVecU8;
27use std::convert::TryFrom;
28use std::convert::TryInto;
29use std::fmt::Formatter;
30use std::sync::Arc;
31
32mod constant_placeholder;
33
34pub use constant_placeholder::*;
35
36use super::avl_tree_data::AvlTreeData;
37use super::avl_tree_data::AvlTreeFlags;
38use super::value::NativeColl;
39use super::value::StoreWrapped;
40use super::value::Value;
41
42use thiserror::Error;
43
44#[derive(PartialEq, Eq, Clone)]
45/// Constant
46pub struct Constant {
47    /// Constant type
48    pub tpe: SType,
49    /// Constant value
50    pub v: Literal,
51}
52
53#[derive(PartialEq, Eq, Clone)]
54/// Possible values for `Constant`
55pub enum Literal {
56    /// Unit
57    Unit,
58    /// Boolean
59    Boolean(bool),
60    /// i8
61    Byte(i8),
62    /// Short
63    Short(i16),
64    /// Int
65    Int(i32),
66    /// Long
67    Long(i64),
68    /// Big integer
69    BigInt(BigInt256),
70    /// Sigma property
71    SigmaProp(Box<SigmaProp>),
72    /// GroupElement
73    GroupElement(Arc<EcPoint>),
74    /// AVL tree
75    AvlTree(Box<AvlTreeData>),
76    /// Ergo box
77    CBox(Ref<'static, ErgoBox>),
78    /// Collection
79    Coll(CollKind<Literal>),
80    /// Option type
81    Opt(Box<Option<Literal>>),
82    /// Tuple (arbitrary type values)
83    Tup(TupleItems<Literal>),
84}
85
86impl std::fmt::Debug for Constant {
87    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
88        format!("{:?}: {:?}", self.v, self.tpe).fmt(f)
89    }
90}
91
92impl std::fmt::Display for Constant {
93    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
94        self.v.fmt(f)
95    }
96}
97
98impl std::fmt::Debug for Literal {
99    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100        match self {
101            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
102                base16::encode_lower(&i8_bytes.as_vec_u8()).fmt(f)
103            }
104            Literal::Coll(CollKind::WrappedColl { elem_tpe: _, items }) => items.fmt(f),
105            Literal::Opt(boxed_opt) => boxed_opt.fmt(f),
106            Literal::Tup(items) => items.fmt(f),
107            Literal::Unit => ().fmt(f),
108            Literal::Boolean(v) => v.fmt(f),
109            Literal::Byte(v) => v.fmt(f),
110            Literal::Short(v) => v.fmt(f),
111            Literal::Int(v) => v.fmt(f),
112            Literal::Long(v) => v.fmt(f),
113            Literal::BigInt(v) => v.fmt(f),
114            Literal::SigmaProp(v) => v.fmt(f),
115            Literal::GroupElement(v) => v.fmt(f),
116            Literal::AvlTree(v) => v.fmt(f),
117            Literal::CBox(v) => v.fmt(f),
118        }
119    }
120}
121
122impl std::fmt::Display for Literal {
123    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
124        match self {
125            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
126                write!(f, "Coll[Byte](")?;
127                for (i, b) in i8_bytes.iter().enumerate() {
128                    if i > 0 {
129                        write!(f, ", ")?;
130                    }
131                    write!(f, "{}", b)?;
132                }
133                write!(f, ")")
134            }
135            Literal::Coll(CollKind::WrappedColl { elem_tpe, items }) => {
136                write!(f, "Coll[{}](", elem_tpe)?;
137                for (i, item) in items.iter().enumerate() {
138                    if i > 0 {
139                        write!(f, ", ")?;
140                    }
141                    item.fmt(f)?;
142                }
143                write!(f, ")")
144            }
145            Literal::Opt(boxed_opt) => {
146                if let Some(v) = &**boxed_opt {
147                    write!(f, "Some(")?;
148                    v.fmt(f)?;
149                    write!(f, ")")
150                } else {
151                    write!(f, "None")
152                }
153            }
154            Literal::Tup(items) => {
155                write!(f, "(")?;
156                for (i, item) in items.iter().enumerate() {
157                    if i > 0 {
158                        write!(f, ", ")?;
159                    }
160                    item.fmt(f)?;
161                }
162                write!(f, ")")
163            }
164            Literal::Unit => write!(f, "()"),
165            Literal::Boolean(v) => v.fmt(f),
166            Literal::Byte(v) => v.fmt(f),
167            Literal::Short(v) => v.fmt(f),
168            Literal::Int(v) => v.fmt(f),
169            Literal::Long(v) => write!(f, "{}L", v),
170            Literal::BigInt(v) => v.fmt(f),
171            Literal::SigmaProp(v) => v.fmt(f),
172            Literal::GroupElement(v) => v.fmt(f),
173            Literal::AvlTree(v) => write!(f, "AvlTree({:?})", v),
174            Literal::CBox(v) => write!(f, "ErgoBox({:?})", v),
175        }
176    }
177}
178
179impl From<()> for Literal {
180    fn from(_: ()) -> Literal {
181        Literal::Unit
182    }
183}
184
185impl From<bool> for Literal {
186    fn from(v: bool) -> Literal {
187        Literal::Boolean(v)
188    }
189}
190
191impl From<i8> for Literal {
192    fn from(v: i8) -> Literal {
193        Literal::Byte(v)
194    }
195}
196
197impl From<i16> for Literal {
198    fn from(v: i16) -> Literal {
199        Literal::Short(v)
200    }
201}
202
203impl From<i32> for Literal {
204    fn from(v: i32) -> Literal {
205        Literal::Int(v)
206    }
207}
208
209impl From<i64> for Literal {
210    fn from(v: i64) -> Literal {
211        Literal::Long(v)
212    }
213}
214
215impl From<BigInt256> for Literal {
216    fn from(v: BigInt256) -> Literal {
217        Literal::BigInt(v)
218    }
219}
220
221impl From<SigmaProp> for Literal {
222    fn from(v: SigmaProp) -> Literal {
223        Literal::SigmaProp(Box::new(v))
224    }
225}
226
227impl From<EcPoint> for Literal {
228    fn from(v: EcPoint) -> Literal {
229        Literal::GroupElement(Arc::new(v))
230    }
231}
232
233impl From<Ref<'_, EcPoint>> for Literal {
234    fn from(value: Ref<'_, EcPoint>) -> Self {
235        Literal::GroupElement(value.to_arc())
236    }
237}
238
239impl From<Ref<'static, ErgoBox>> for Literal {
240    fn from(b: Ref<'static, ErgoBox>) -> Self {
241        Literal::CBox(b)
242    }
243}
244
245impl From<ErgoBox> for Literal {
246    fn from(b: ErgoBox) -> Self {
247        Literal::CBox(Arc::new(b).into())
248    }
249}
250
251impl From<Vec<u8>> for Literal {
252    fn from(v: Vec<u8>) -> Self {
253        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
254            v.as_vec_i8().into(),
255        ))) // TODO: optimize
256    }
257}
258
259impl From<Digest32> for Literal {
260    fn from(v: Digest32) -> Self {
261        let bytes: Vec<u8> = v.into();
262        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
263            bytes.as_vec_i8().into(), // TODO: optimize
264        )))
265    }
266}
267
268impl From<TokenId> for Literal {
269    fn from(v: TokenId) -> Self {
270        Digest32::from(v).into()
271    }
272}
273
274impl From<Vec<i8>> for Literal {
275    fn from(v: Vec<i8>) -> Self {
276        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v.into()))) // TODO
277    }
278}
279
280impl<T: LiftIntoSType + StoreWrapped + Into<Literal>> From<Vec<T>> for Literal {
281    fn from(v: Vec<T>) -> Self {
282        Literal::Coll(CollKind::WrappedColl {
283            elem_tpe: T::stype(),
284            items: v.into_iter().map(|i| i.into()).collect(),
285        })
286    }
287}
288
289impl<T: LiftIntoSType + Into<Literal>> From<Option<T>> for Literal {
290    fn from(opt: Option<T>) -> Self {
291        Literal::Opt(Box::new(opt.map(|e| e.into())))
292    }
293}
294
295impl<'ctx> TryFrom<Value<'ctx>> for Constant {
296    type Error = String;
297    #[allow(clippy::unwrap_used)]
298    fn try_from(value: Value<'ctx>) -> Result<Self, Self::Error> {
299        match value {
300            Value::Boolean(b) => Ok(Constant::from(b)),
301            Value::Byte(b) => Ok(Constant::from(b)),
302            Value::Short(s) => Ok(Constant::from(s)),
303            Value::Int(i) => Ok(Constant::from(i)),
304            Value::Long(l) => Ok(Constant::from(l)),
305            Value::BigInt(b) => Ok(Constant::from(b)),
306            Value::Unit => Ok(Constant {
307                tpe: SType::SUnit,
308                v: Literal::Unit,
309            }),
310            Value::SigmaProp(s) => Ok(Constant::from(*s)),
311            Value::GroupElement(e) => Ok(Constant::from(e)),
312            Value::CBox(i) => Ok(Constant::from(i.to_static())),
313            Value::Coll(coll) => {
314                let (v, tpe) = match coll {
315                    CollKind::NativeColl(n) => (
316                        Literal::Coll(CollKind::NativeColl(n)),
317                        SType::SColl(Arc::new(SType::SByte)),
318                    ),
319                    CollKind::WrappedColl { elem_tpe, items } => {
320                        let new_items = items
321                            .iter()
322                            .map(|v| Ok(Constant::try_from(v.clone())?.v))
323                            .collect::<Result<Arc<[_]>, String>>()?;
324
325                        (
326                            Literal::Coll(CollKind::WrappedColl {
327                                elem_tpe: elem_tpe.clone(),
328                                items: new_items,
329                            }),
330                            SType::SColl(Arc::new(elem_tpe)),
331                        )
332                    }
333                };
334                Ok(Constant { v, tpe })
335            }
336            Value::Opt(lit) => match *lit {
337                Some(v) => {
338                    let c = Constant::try_from(v)?;
339                    Ok(Constant {
340                        v: Literal::Opt(Box::new(Some(c.v))),
341                        tpe: c.tpe,
342                    })
343                }
344                None => Err("Can't convert from Value::Opt(None) to Constant".into()),
345            },
346            Value::Tup(t) => {
347                if let Ok(t) = t.try_mapped::<_, _, String>(|v| {
348                    let c = Constant::try_from(v)?;
349                    Ok((c.v, c.tpe))
350                }) {
351                    let tuple_items = t.mapped_ref(|(l, _)| l.clone());
352                    let tuple_item_types = SType::STuple(STuple {
353                        items: t.mapped(|(_, tpe)| tpe),
354                    });
355                    Ok(Constant {
356                        v: Literal::Tup(tuple_items),
357                        tpe: tuple_item_types,
358                    })
359                } else {
360                    Err("Can't convert Value:Tup element".into())
361                }
362            }
363            Value::AvlTree(a) => Ok(Constant::from(*a)),
364            Value::Context => Err("Cannot convert Value::Context into Constant".into()),
365            Value::Header(_) => Err("Cannot convert Value::Header(_) into Constant".into()),
366            Value::PreHeader(_) => Err("Cannot convert Value::PreHeader(_) into Constant".into()),
367            Value::Global => Err("Cannot convert Value::Global into Constant".into()),
368            Value::Lambda(_) => Err("Cannot convert Value::Lambda(_) into Constant".into()),
369        }
370    }
371}
372
373impl From<()> for Constant {
374    fn from(_: ()) -> Self {
375        Constant {
376            tpe: SType::SUnit,
377            v: Literal::Unit,
378        }
379    }
380}
381
382impl From<bool> for Constant {
383    fn from(v: bool) -> Self {
384        Constant {
385            tpe: bool::stype(),
386            v: v.into(),
387        }
388    }
389}
390
391impl From<i8> for Constant {
392    fn from(v: i8) -> Self {
393        Constant {
394            tpe: i8::stype(),
395            v: v.into(),
396        }
397    }
398}
399
400impl From<i16> for Constant {
401    fn from(v: i16) -> Self {
402        Constant {
403            tpe: i16::stype(),
404            v: v.into(),
405        }
406    }
407}
408
409impl From<i32> for Constant {
410    fn from(v: i32) -> Self {
411        Constant {
412            tpe: i32::stype(),
413            v: v.into(),
414        }
415    }
416}
417
418impl From<i64> for Constant {
419    fn from(v: i64) -> Self {
420        Constant {
421            tpe: i64::stype(),
422            v: v.into(),
423        }
424    }
425}
426
427impl From<SigmaProp> for Constant {
428    fn from(v: SigmaProp) -> Self {
429        Constant {
430            tpe: SType::SSigmaProp,
431            v: v.into(),
432        }
433    }
434}
435
436impl From<EcPoint> for Constant {
437    fn from(v: EcPoint) -> Constant {
438        Constant {
439            tpe: SType::SGroupElement,
440            v: v.into(),
441        }
442    }
443}
444
445impl From<Ref<'_, EcPoint>> for Constant {
446    fn from(v: Ref<'_, EcPoint>) -> Self {
447        Constant {
448            tpe: SType::SGroupElement,
449            v: v.into(),
450        }
451    }
452}
453
454impl From<&'static ErgoBox> for Constant {
455    fn from(b: &'static ErgoBox) -> Self {
456        Constant {
457            tpe: SType::SBox,
458            v: Literal::CBox(Ref::Borrowed(b)),
459        }
460    }
461}
462
463impl From<ErgoBox> for Constant {
464    fn from(b: ErgoBox) -> Self {
465        Constant {
466            tpe: SType::SBox,
467            v: Literal::CBox(Arc::new(b).into()),
468        }
469    }
470}
471
472impl From<Ref<'static, ErgoBox>> for Constant {
473    fn from(b: Ref<'static, ErgoBox>) -> Self {
474        Constant {
475            tpe: SType::SBox,
476            v: Literal::CBox(b),
477        }
478    }
479}
480
481impl From<Vec<u8>> for Constant {
482    fn from(v: Vec<u8>) -> Self {
483        Constant {
484            tpe: SType::SColl(Arc::new(SType::SByte)),
485            v: v.into(),
486        }
487    }
488}
489
490impl From<Digest32> for Constant {
491    fn from(v: Digest32) -> Self {
492        Constant {
493            tpe: SType::SColl(Arc::new(SType::SByte)),
494            v: v.into(),
495        }
496    }
497}
498
499impl From<TokenId> for Constant {
500    fn from(v: TokenId) -> Self {
501        Digest32::from(v).into()
502    }
503}
504
505impl From<Vec<i8>> for Constant {
506    fn from(v: Vec<i8>) -> Self {
507        Constant {
508            tpe: SType::SColl(Arc::new(SType::SByte)),
509            v: v.into(),
510        }
511    }
512}
513
514impl<T: LiftIntoSType + StoreWrapped + Into<Constant>> From<Vec<T>> for Constant {
515    fn from(v: Vec<T>) -> Self {
516        Constant {
517            tpe: Vec::<T>::stype(),
518            v: Literal::Coll(CollKind::WrappedColl {
519                elem_tpe: T::stype(),
520                items: v.into_iter().map(|i| i.into().v).collect(),
521            }),
522        }
523    }
524}
525
526impl<T: LiftIntoSType + Into<Constant>> From<Option<T>> for Constant {
527    fn from(opt: Option<T>) -> Self {
528        Constant {
529            tpe: SType::SOption(Arc::new(T::stype())),
530            v: Literal::Opt(Box::new(opt.map(|e| e.into().v))),
531        }
532    }
533}
534
535impl From<ProveDlog> for Constant {
536    fn from(v: ProveDlog) -> Self {
537        Constant::from(SigmaProp::from(SigmaBoolean::from(
538            SigmaProofOfKnowledgeTree::from(v),
539        )))
540    }
541}
542
543impl From<ProveDhTuple> for Constant {
544    fn from(dht: ProveDhTuple) -> Self {
545        Constant::from(SigmaProp::from(SigmaBoolean::from(
546            SigmaProofOfKnowledgeTree::from(dht),
547        )))
548    }
549}
550
551impl From<SigmaBoolean> for Constant {
552    fn from(sb: SigmaBoolean) -> Self {
553        Constant::from(SigmaProp::from(sb))
554    }
555}
556
557impl From<BigInt256> for Constant {
558    fn from(b: BigInt256) -> Self {
559        Constant {
560            tpe: SType::SBigInt,
561            v: Literal::BigInt(b),
562        }
563    }
564}
565
566impl From<AvlTreeData> for Constant {
567    fn from(a: AvlTreeData) -> Self {
568        Constant {
569            tpe: SType::SAvlTree,
570            v: Literal::AvlTree(Box::new(a)),
571        }
572    }
573}
574
575impl From<AvlTreeFlags> for Constant {
576    fn from(a: AvlTreeFlags) -> Self {
577        Constant {
578            tpe: SType::SByte,
579            v: Literal::Byte(a.serialize() as i8),
580        }
581    }
582}
583
584impl From<ADDigest> for Constant {
585    fn from(a: ADDigest) -> Self {
586        Constant {
587            tpe: SType::SColl(Arc::new(SType::SByte)),
588            v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
589                a.0.iter().map(|&i| i as i8).collect(),
590            ))),
591        }
592    }
593}
594
595#[allow(clippy::unwrap_used)]
596#[allow(clippy::from_over_into)]
597#[impl_for_tuples(2, 4)]
598impl Into<Constant> for Tuple {
599    fn into(self) -> Constant {
600        let constants: Vec<Constant> = [for_tuples!(  #( Tuple.into() ),* )].to_vec();
601        let (types, values): (Vec<SType>, Vec<Literal>) =
602            constants.into_iter().map(|c| (c.tpe, c.v)).unzip();
603        Constant {
604            tpe: SType::STuple(types.try_into().unwrap()),
605            v: Literal::Tup(values.try_into().unwrap()),
606        }
607    }
608}
609
610/// Extract value wrapped in a type
611pub trait TryExtractInto<F> {
612    /// Extract value of the given type from any type (e.g. ['Constant'], [`super::value::Value`])
613    /// on which [`TryExtractFrom`] is implemented
614    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError>;
615}
616
617impl<F> TryExtractInto<F> for F {
618    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError> {
619        T::try_extract_from(self)
620    }
621}
622
623/// Underlying type is different from requested value type
624#[derive(Error, PartialEq, Eq, Debug, Clone)]
625#[error("Failed TryExtractFrom: {0}")]
626pub struct TryExtractFromError(pub String);
627
628/// Extract underlying value if type matches
629pub trait TryExtractFrom<T>: Sized {
630    /// Extract the value or return an error if type does not match
631    fn try_extract_from(v: T) -> Result<Self, TryExtractFromError>;
632}
633
634impl<T: TryExtractFrom<Literal>> TryExtractFrom<Constant> for T {
635    fn try_extract_from(cv: Constant) -> Result<Self, TryExtractFromError> {
636        T::try_extract_from(cv.v)
637    }
638}
639
640impl TryExtractFrom<Literal> for () {
641    fn try_extract_from(cv: Literal) -> Result<(), TryExtractFromError> {
642        match cv {
643            Literal::Unit => Ok(()),
644            _ => Err(TryExtractFromError(format!(
645                "expected Unit, found {:?}",
646                cv
647            ))),
648        }
649    }
650}
651
652impl TryExtractFrom<Literal> for bool {
653    fn try_extract_from(cv: Literal) -> Result<bool, TryExtractFromError> {
654        match cv {
655            Literal::Boolean(v) => Ok(v),
656            _ => Err(TryExtractFromError(format!(
657                "expected bool, found {:?}",
658                cv
659            ))),
660        }
661    }
662}
663
664impl TryExtractFrom<Literal> for i8 {
665    fn try_extract_from(cv: Literal) -> Result<i8, TryExtractFromError> {
666        match cv {
667            Literal::Byte(v) => Ok(v),
668            _ => Err(TryExtractFromError(format!("expected i8, found {:?}", cv))),
669        }
670    }
671}
672
673impl TryExtractFrom<Literal> for i16 {
674    fn try_extract_from(cv: Literal) -> Result<i16, TryExtractFromError> {
675        match cv {
676            Literal::Short(v) => Ok(v),
677            _ => Err(TryExtractFromError(format!("expected i16, found {:?}", cv))),
678        }
679    }
680}
681
682impl TryExtractFrom<Literal> for i32 {
683    fn try_extract_from(cv: Literal) -> Result<i32, TryExtractFromError> {
684        match cv {
685            Literal::Int(v) => Ok(v),
686            _ => Err(TryExtractFromError(format!("expected i32, found {:?}", cv))),
687        }
688    }
689}
690
691impl TryExtractFrom<Literal> for i64 {
692    fn try_extract_from(cv: Literal) -> Result<i64, TryExtractFromError> {
693        match cv {
694            Literal::Long(v) => Ok(v),
695            _ => Err(TryExtractFromError(format!("expected i64, found {:?}", cv))),
696        }
697    }
698}
699
700impl TryExtractFrom<Literal> for EcPoint {
701    fn try_extract_from(cv: Literal) -> Result<EcPoint, TryExtractFromError> {
702        match cv {
703            Literal::GroupElement(v) => Ok((*v).clone()),
704            _ => Err(TryExtractFromError(format!(
705                "expected EcPoint, found {:?}",
706                cv
707            ))),
708        }
709    }
710}
711
712impl TryExtractFrom<Literal> for SigmaProp {
713    fn try_extract_from(cv: Literal) -> Result<SigmaProp, TryExtractFromError> {
714        match cv {
715            Literal::SigmaProp(v) => Ok(*v),
716            _ => Err(TryExtractFromError(format!(
717                "expected SigmaProp, found {:?}",
718                cv
719            ))),
720        }
721    }
722}
723
724impl TryExtractFrom<Literal> for Ref<'static, ErgoBox> {
725    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
726        match c {
727            Literal::CBox(b) => Ok(b),
728            _ => Err(TryExtractFromError(format!(
729                "expected ErgoBox, found {:?}",
730                c
731            ))),
732        }
733    }
734}
735
736impl TryExtractFrom<Literal> for ErgoBox {
737    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
738        match c {
739            Literal::CBox(b) => Ok((*b).clone()),
740            _ => Err(TryExtractFromError(format!(
741                "expected ErgoBox, found {:?}",
742                c
743            ))),
744        }
745    }
746}
747
748impl<T: TryExtractFrom<Literal> + StoreWrapped> TryExtractFrom<Literal> for Vec<T> {
749    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
750        match c {
751            Literal::Coll(coll) => match coll {
752                CollKind::WrappedColl {
753                    elem_tpe: _,
754                    items: v,
755                } => v.iter().cloned().map(T::try_extract_from).collect(),
756                _ => Err(TryExtractFromError(format!(
757                    "expected {:?}, found {:?}",
758                    std::any::type_name::<Self>(),
759                    coll
760                ))),
761            },
762            _ => Err(TryExtractFromError(format!(
763                "expected {:?}, found {:?}",
764                std::any::type_name::<Self>(),
765                c
766            ))),
767        }
768    }
769}
770
771impl TryExtractFrom<Literal> for Vec<i8> {
772    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
773        match v {
774            Literal::Coll(v) => match v {
775                CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO: optimize
776                _ => Err(TryExtractFromError(format!(
777                    "expected {:?}, found {:?}",
778                    std::any::type_name::<Self>(),
779                    v
780                ))),
781            },
782            _ => Err(TryExtractFromError(format!(
783                "expected {:?}, found {:?}",
784                std::any::type_name::<Self>(),
785                v
786            ))),
787        }
788    }
789}
790
791impl TryExtractFrom<Literal> for Vec<u8> {
792    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
793        use sigma_util::FromVecI8;
794        Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)
795    }
796}
797
798impl TryExtractFrom<Literal> for Digest32 {
799    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
800        use sigma_util::FromVecI8;
801        let bytes = Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)?;
802        Digest32::try_from(bytes).map_err(|e| {
803            TryExtractFromError(format!("failed to extract Digest32 with error: {:?}", e))
804        })
805    }
806}
807
808impl TryExtractFrom<Literal> for TokenId {
809    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
810        Digest32::try_extract_from(v).map(Into::into)
811    }
812}
813
814impl TryExtractFrom<Literal> for Literal {
815    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
816        Ok(v)
817    }
818}
819
820impl TryExtractFrom<Literal> for BigInt256 {
821    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
822        match v {
823            Literal::BigInt(bi) => Ok(bi),
824            _ => Err(TryExtractFromError(format!(
825                "expected {:?}, found {:?}",
826                std::any::type_name::<Self>(),
827                v
828            ))),
829        }
830    }
831}
832
833impl TryExtractFrom<Literal> for AvlTreeData {
834    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
835        match v {
836            Literal::AvlTree(a) => Ok(*a),
837            _ => Err(TryExtractFromError(format!(
838                "expected {:?}, found {:?}",
839                std::any::type_name::<Self>(),
840                v
841            ))),
842        }
843    }
844}
845
846impl<T: TryExtractFrom<Literal>> TryExtractFrom<Literal> for Option<T> {
847    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
848        match v {
849            Literal::Opt(opt) => opt.map(T::try_extract_from).transpose(),
850            _ => Err(TryExtractFromError(format!(
851                "expected Option, found {:?}",
852                v
853            ))),
854        }
855    }
856}
857
858#[impl_for_tuples(2, 4)]
859impl TryExtractFrom<Literal> for Tuple {
860    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
861        match v {
862            Literal::Tup(items) => {
863                let mut iter = items.iter();
864                Ok(for_tuples!( ( #(
865                                Tuple::try_extract_from(
866                                    iter
867                                        .next()
868                                        .cloned()
869                                        .ok_or_else(|| TryExtractFromError("not enough items in STuple".to_string()))?
870                                )?
871                                ),* ) ))
872            }
873            _ => Err(TryExtractFromError(format!(
874                "expected Context, found {:?}",
875                v
876            ))),
877        }
878    }
879}
880
881impl TryFrom<Literal> for ProveDlog {
882    type Error = TryExtractFromError;
883    fn try_from(cv: Literal) -> Result<Self, Self::Error> {
884        match cv {
885            Literal::SigmaProp(sp) => match sp.value() {
886                SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(
887                    prove_dlog,
888                )) => Ok(prove_dlog.clone()),
889                _ => Err(TryExtractFromError(format!(
890                    "expected ProveDlog, found {:?}",
891                    sp
892                ))),
893            },
894            _ => Err(TryExtractFromError(format!(
895                "expected SigmaProp, found {:?}",
896                cv
897            ))),
898        }
899    }
900}
901
902impl Base16Str for &Constant {
903    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
904        self.sigma_serialize_bytes()
905            .map(|bytes| base16::encode_lower(&bytes))
906    }
907}
908
909impl Base16Str for Constant {
910    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
911        self.sigma_serialize_bytes()
912            .map(|bytes| base16::encode_lower(&bytes))
913    }
914}
915
916impl TryFrom<Base16DecodedBytes> for Constant {
917    type Error = SigmaParsingError;
918
919    fn try_from(value: Base16DecodedBytes) -> Result<Self, Self::Error> {
920        Constant::sigma_parse_bytes(&value.0)
921    }
922}
923
924#[cfg(feature = "arbitrary")]
925#[allow(clippy::unwrap_used)]
926#[allow(clippy::todo)]
927/// Arbitrary impl
928pub(crate) mod arbitrary {
929    use std::convert::TryFrom;
930
931    use super::*;
932    use crate::mir::value::CollKind;
933    use crate::types::stuple::STuple;
934    use proptest::collection::vec;
935    use proptest::prelude::*;
936
937    extern crate derive_more;
938    use derive_more::From;
939    use derive_more::TryInto;
940
941    fn primitive_type_value() -> BoxedStrategy<Constant> {
942        prop_oneof![
943            any::<bool>().prop_map_into(),
944            any::<i8>().prop_map_into(),
945            any::<i16>().prop_map_into(),
946            any::<i32>().prop_map_into(),
947            any::<i64>().prop_map_into(),
948            any::<i64>().prop_map(|v| BigInt256::from(v).into()),
949            any::<EcPoint>().prop_map_into(),
950            any::<SigmaProp>().prop_map_into(),
951            // although it's not strictly a primitive type, byte array is widely used as one
952            vec(any::<i8>(), 0..100).prop_map_into(),
953        ]
954        .boxed()
955    }
956
957    fn coll_from_constant(c: Constant, length: usize) -> Constant {
958        Constant {
959            tpe: SType::SColl(Arc::new(c.tpe.clone())),
960            v: Literal::Coll(if c.tpe == SType::SByte {
961                let mut values: Vec<i8> = Vec::with_capacity(length);
962                let byte: i8 = c.v.try_extract_into().unwrap();
963                for _ in 0..length {
964                    values.push(byte);
965                }
966                CollKind::NativeColl(NativeColl::CollByte(values.into())) // TODO: optimize
967            } else {
968                let mut values: Vec<Literal> = Vec::with_capacity(length);
969                for _ in 0..length {
970                    values.push(c.v.clone());
971                }
972                CollKind::WrappedColl {
973                    elem_tpe: c.tpe,
974                    items: values.into(),
975                }
976            }),
977        }
978    }
979
980    fn const_with_type(tpe: SType) -> BoxedStrategy<Constant> {
981        match tpe {
982            SType::SAny => any::<Constant>(),
983            SType::SBoolean => any::<bool>().prop_map_into().boxed(),
984            SType::SByte => any::<i8>().prop_map_into().boxed(),
985            SType::SShort => any::<i16>().prop_map_into().boxed(),
986            SType::SInt => any::<i32>().prop_map_into().boxed(),
987            SType::SLong => any::<i64>().prop_map_into().boxed(),
988            SType::SBigInt => any::<i64>().prop_map(|v| BigInt256::from(v).into()).boxed(),
989            SType::SGroupElement => any::<EcPoint>().prop_map_into().boxed(),
990            SType::SSigmaProp => any::<SigmaProp>().prop_map_into().boxed(),
991            SType::SBox => any::<ErgoBox>().prop_map_into().boxed(),
992            SType::SAvlTree => any::<AvlTreeData>().prop_map_into().boxed(),
993            // SType::SOption(tpe) =>
994            SType::SOption(tpe) => match *tpe {
995                SType::SBoolean => any::<Option<bool>>().prop_map_into().boxed(),
996                SType::SByte => any::<Option<i8>>().prop_map_into().boxed(),
997                SType::SShort => any::<Option<i16>>().prop_map_into().boxed(),
998                SType::SInt => any::<Option<i32>>().prop_map_into().boxed(),
999                SType::SLong => any::<Option<i64>>().prop_map_into().boxed(),
1000                _ => todo!(),
1001            },
1002            SType::SColl(elem_tpe) => match *elem_tpe {
1003                SType::SBoolean => vec(any::<bool>(), 0..400).prop_map_into().boxed(),
1004                SType::SByte => vec(any::<u8>(), 0..400).prop_map_into().boxed(),
1005                SType::SShort => vec(any::<i16>(), 0..400).prop_map_into().boxed(),
1006                SType::SInt => vec(any::<i32>(), 0..400).prop_map_into().boxed(),
1007                SType::SLong => vec(any::<i64>(), 0..400).prop_map_into().boxed(),
1008                SType::SSigmaProp => vec(any::<SigmaProp>(), 0..3).prop_map_into().boxed(),
1009                _ => todo!(),
1010            },
1011            // SType::STuple(_) => {}
1012            _ => todo!("{0:?} not yet implemented", tpe),
1013        }
1014    }
1015
1016    impl Default for ArbConstantParams {
1017        fn default() -> Self {
1018            ArbConstantParams::AnyWithDepth(1)
1019        }
1020    }
1021
1022    /// Parameters for arbitrary Constant generation
1023    #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
1024    pub enum ArbConstantParams {
1025        /// Constant of any type with a structrure of a given depth
1026        AnyWithDepth(u8),
1027        /// Constant of a given type
1028        Exact(SType),
1029    }
1030
1031    impl Arbitrary for Constant {
1032        type Parameters = ArbConstantParams;
1033        type Strategy = BoxedStrategy<Self>;
1034
1035        fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
1036            match args {
1037                ArbConstantParams::AnyWithDepth(depth) => {
1038                    prop_oneof![primitive_type_value().prop_recursive(
1039                        depth as u32,
1040                        16,
1041                        8,
1042                        |elem| {
1043                            prop_oneof![
1044                                // Coll[_]
1045                                elem.clone().prop_map(|c| coll_from_constant(c, 0)),
1046                                elem.clone().prop_map(|c| coll_from_constant(c, 1)),
1047                                elem.clone().prop_map(|c| coll_from_constant(c, 2)),
1048                                elem.clone().prop_map(|c| coll_from_constant(c, 10)),
1049                                // no Option[_] since it cannot be serialized (for now)
1050                                // // Some(v)
1051                                // elem.clone().prop_map(|c| Constant {
1052                                //     tpe: SType::SOption(Box::new(c.tpe)),
1053                                //     v: Value::Opt(Box::new(Some(c.v)))
1054                                // }),
1055                                // // None
1056                                // elem.prop_map(|c| Constant {
1057                                //     tpe: SType::SOption(Box::new(c.tpe)),
1058                                //     v: Value::Opt(Box::new(None))
1059                                // })
1060
1061                                // Tuple
1062                                vec(elem, 2..=4).prop_map(|constants| Constant {
1063                                    tpe: SType::STuple(
1064                                        STuple::try_from(
1065                                            constants
1066                                                .clone()
1067                                                .into_iter()
1068                                                .map(|c| c.tpe)
1069                                                .collect::<Vec<SType>>()
1070                                        )
1071                                        .unwrap()
1072                                    ),
1073                                    v: Literal::Tup(
1074                                        constants
1075                                            .into_iter()
1076                                            .map(|c| c.v)
1077                                            .collect::<Vec<Literal>>()
1078                                            .try_into()
1079                                            .unwrap()
1080                                    )
1081                                }),
1082                            ]
1083                        }
1084                    )]
1085                    .boxed()
1086                }
1087                ArbConstantParams::Exact(tpe) => const_with_type(tpe),
1088            }
1089        }
1090    }
1091}
1092
1093#[allow(clippy::unwrap_used)]
1094#[cfg(test)]
1095#[allow(clippy::panic)]
1096pub mod tests {
1097    use super::*;
1098    use core::fmt;
1099    use proptest::prelude::*;
1100
1101    fn test_constant_roundtrip<T>(v: T)
1102    where
1103        T: TryExtractInto<T>
1104            + TryExtractFrom<Literal>
1105            + Into<Constant>
1106            + fmt::Debug
1107            + Eq
1108            + Clone
1109            + 'static,
1110    {
1111        let constant: Constant = v.clone().into();
1112        let v_extracted: T = constant.try_extract_into::<T>().unwrap();
1113        assert_eq!(v, v_extracted);
1114    }
1115
1116    #[test]
1117    fn unit_roundtrip() {
1118        test_constant_roundtrip(());
1119    }
1120
1121    proptest! {
1122
1123        #![proptest_config(ProptestConfig::with_cases(8))]
1124
1125        #[test]
1126        fn bool_roundtrip(v in any::<bool>()) {
1127            test_constant_roundtrip(v);
1128        }
1129
1130        #[test]
1131        fn i8_roundtrip(v in any::<i8>()) {
1132            test_constant_roundtrip(v);
1133        }
1134
1135        #[test]
1136        fn i16_roundtrip(v in any::<i16>()) {
1137            test_constant_roundtrip(v);
1138        }
1139
1140        #[test]
1141        fn i32_roundtrip(v in any::<i32>()) {
1142            test_constant_roundtrip(v);
1143        }
1144
1145        #[test]
1146        fn i64_roundtrip(v in any::<i64>()) {
1147            test_constant_roundtrip(v);
1148        }
1149
1150        #[test]
1151        fn bigint_roundtrip(raw in any::<i64>()) {
1152            let v = BigInt256::from(raw);
1153            test_constant_roundtrip(v);
1154        }
1155
1156        #[test]
1157        fn group_element_roundtrip(v in any::<EcPoint>()) {
1158            test_constant_roundtrip(v);
1159        }
1160
1161        #[test]
1162        fn sigma_prop_roundtrip(v in any::<SigmaProp>()) {
1163            test_constant_roundtrip(v);
1164        }
1165
1166        #[test]
1167        fn vec_i8_roundtrip(v in any::<Vec<i8>>()) {
1168            test_constant_roundtrip(v);
1169        }
1170
1171        #[test]
1172        fn vec_u8_roundtrip(v in any::<Vec<u8>>()) {
1173            // eprintln!("{:?}", Constant::from(v.clone()));
1174            test_constant_roundtrip(v);
1175        }
1176
1177        #[test]
1178        fn token_id_roundtrip(v in any::<TokenId>()) {
1179            // eprintln!("{:?}", Constant::from(v.clone()));
1180            test_constant_roundtrip(v);
1181        }
1182
1183        #[test]
1184        fn digest32_roundtrip(v in any::<Digest32>()) {
1185            test_constant_roundtrip(v);
1186        }
1187
1188
1189        #[test]
1190        fn vec_i16_roundtrip(v in any::<Vec<i16>>()) {
1191            test_constant_roundtrip(v);
1192        }
1193
1194        #[test]
1195        fn vec_i32_roundtrip(v in any::<Vec<i32>>()) {
1196            test_constant_roundtrip(v);
1197        }
1198
1199        #[test]
1200        fn vec_i64_roundtrip(v in any::<Vec<i64>>()) {
1201            // eprintln!("{:?}", Constant::from(v.clone()));
1202            test_constant_roundtrip(v);
1203        }
1204
1205        #[test]
1206        fn vec_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1207            let v: Vec<BigInt256> = raw.into_iter().map(BigInt256::from).collect();
1208            // eprintln!("{:?}", Constant::from(v.clone()));
1209            test_constant_roundtrip(v);
1210        }
1211
1212        #[test]
1213        fn vec_option_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1214            let v: Vec<Option<BigInt256>> = raw.into_iter().map(|i| Some(BigInt256::from(i))).collect();
1215            // eprintln!("{:?}", Constant::from(v.clone()));
1216            test_constant_roundtrip(v);
1217        }
1218
1219        #[test]
1220        fn vec_sigmaprop_roundtrip(v in any::<Vec<SigmaProp>>()) {
1221            test_constant_roundtrip(v);
1222        }
1223
1224        #[test]
1225        fn option_primitive_type_roundtrip(v in any::<Option<i64>>()) {
1226            test_constant_roundtrip(v);
1227        }
1228
1229        #[test]
1230        fn option_nested_vector_type_roundtrip(v in any::<Option<Vec<(i64, bool)>>>()) {
1231            // eprintln!("{:?}", Constant::from(v.clone()));
1232            test_constant_roundtrip(v);
1233        }
1234
1235        #[test]
1236        fn option_nested_tuple_type_roundtrip(v in any::<Option<(i64, bool)>>()) {
1237            test_constant_roundtrip(v);
1238        }
1239
1240
1241        #[test]
1242        fn tuple_primitive_types_roundtrip(v in any::<(i64, bool)>()) {
1243            // let constant: Constant = v.into();
1244            // eprintln!("{:?}", constant);
1245            test_constant_roundtrip(v);
1246        }
1247
1248        #[test]
1249        fn tuple_nested_types_roundtrip(v in any::<(Option<i64>, Vec<SigmaProp>)>()) {
1250            test_constant_roundtrip(v);
1251        }
1252
1253    }
1254}