1use 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)]
45pub struct Constant {
47 pub tpe: SType,
49 pub v: Literal,
51}
52
53#[derive(PartialEq, Eq, Clone)]
54pub enum Literal {
56 Unit,
58 Boolean(bool),
60 Byte(i8),
62 Short(i16),
64 Int(i32),
66 Long(i64),
68 BigInt(BigInt256),
70 SigmaProp(Box<SigmaProp>),
72 GroupElement(Arc<EcPoint>),
74 AvlTree(Box<AvlTreeData>),
76 CBox(Ref<'static, ErgoBox>),
78 Coll(CollKind<Literal>),
80 Opt(Box<Option<Literal>>),
82 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 ))) }
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(), )))
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()))) }
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
610pub trait TryExtractInto<F> {
612 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#[derive(Error, PartialEq, Eq, Debug, Clone)]
625#[error("Failed TryExtractFrom: {0}")]
626pub struct TryExtractFromError(pub String);
627
628pub trait TryExtractFrom<T>: Sized {
630 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()), _ => 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)]
927pub(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 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())) } 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) => 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 _ => 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 #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
1024 pub enum ArbConstantParams {
1025 AnyWithDepth(u8),
1027 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 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 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 test_constant_roundtrip(v);
1175 }
1176
1177 #[test]
1178 fn token_id_roundtrip(v in any::<TokenId>()) {
1179 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 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 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 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 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 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}