• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ergoplatform / sigma-rust / 16405540612

20 Jul 2025 11:50PM UTC coverage: 78.438% (-0.01%) from 78.451%
16405540612

Pull #790

github

web-flow
Merge 7bd76aff4 into 2725f402c
Pull Request #790: Use precomputed tables

62 of 69 new or added lines in 16 files covered. (89.86%)

10 existing lines in 5 files now uncovered.

11961 of 15249 relevant lines covered (78.44%)

2.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.98
/ergotree-ir/src/mir/constant.rs
1
//! Constant(Literal) IR node
2

3
use crate::base16_str::Base16Str;
4
use crate::bigint256::BigInt256;
5
use crate::chain::ergo_box::ErgoBox;
6
use crate::chain::token::TokenId;
7
use crate::mir::value::CollKind;
8
use crate::reference::Ref;
9
use crate::serialization::SigmaParsingError;
10
use crate::serialization::SigmaSerializable;
11
use crate::serialization::SigmaSerializationError;
12
use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
13
use crate::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
14
use crate::sigma_protocol::sigma_boolean::SigmaProp;
15
use crate::sigma_protocol::sigma_boolean::{ProveDhTuple, ProveDlog};
16
use crate::types::stuple::STuple;
17
use crate::types::stuple::TupleItems;
18
use crate::types::stype::LiftIntoSType;
19
use crate::types::stype::SType;
20
use crate::unsignedbigint256::UnsignedBigInt;
21
use alloc::boxed::Box;
22

23
use alloc::string::String;
24
use alloc::string::ToString;
25
use alloc::sync::Arc;
26
use alloc::vec::Vec;
27
use core::convert::TryFrom;
28
use core::convert::TryInto;
29
use core::fmt::Formatter;
30
use ergo_chain_types::ADDigest;
31
use ergo_chain_types::Base16DecodedBytes;
32
use ergo_chain_types::Digest32;
33
use ergo_chain_types::EcPoint;
34
use ergo_chain_types::Header;
35
use impl_trait_for_tuples::impl_for_tuples;
36
use sigma_util::AsVecI8;
37
use sigma_util::AsVecU8;
38

39
mod constant_placeholder;
40

41
pub use constant_placeholder::*;
42

43
use super::avl_tree_data::AvlTreeData;
44
use super::avl_tree_data::AvlTreeFlags;
45
use super::value::NativeColl;
46
use super::value::StoreWrapped;
47
use super::value::Value;
48

49
use thiserror::Error;
50

51
#[derive(PartialEq, Eq, Clone)]
52
/// Constant
53
pub struct Constant {
54
    /// Constant type
55
    pub tpe: SType,
56
    /// Constant value
57
    pub v: Literal,
58
}
59

60
#[derive(PartialEq, Eq, Clone)]
61
/// Possible values for `Constant`
62
pub enum Literal {
63
    /// Unit
64
    Unit,
65
    /// Boolean
66
    Boolean(bool),
67
    /// i8
68
    Byte(i8),
69
    /// Short
70
    Short(i16),
71
    /// Int
72
    Int(i32),
73
    /// Long
74
    Long(i64),
75
    /// String type
76
    String(Arc<str>),
77
    /// Big integer
78
    BigInt(BigInt256),
79
    /// Unsigned 256 BigInteger type
80
    UnsignedBigInt(UnsignedBigInt),
81
    /// Sigma property
82
    SigmaProp(Box<SigmaProp>),
83
    /// GroupElement
84
    GroupElement(Arc<EcPoint>),
85
    /// AVL tree
86
    AvlTree(Box<AvlTreeData>),
87
    /// Block Header type
88
    Header(Box<Header>),
89
    /// Ergo box
90
    CBox(Ref<'static, ErgoBox>),
91
    /// Collection
92
    Coll(CollKind<Literal>),
93
    /// Option type
94
    Opt(Option<Box<Literal>>),
95
    /// Tuple (arbitrary type values)
96
    Tup(TupleItems<Literal>),
97
}
98

99
impl Literal {
100
    fn tpe(&self) -> Result<SType, &'static str> {
1✔
101
        let tpe = match self {
1✔
102
            Literal::Unit => SType::SUnit,
×
103
            Literal::Boolean(_) => SType::SBoolean,
1✔
104
            Literal::Byte(_) => SType::SByte,
1✔
105
            Literal::Short(_) => SType::SShort,
1✔
106
            Literal::Int(_) => SType::SInt,
1✔
107
            Literal::Long(_) => SType::SLong,
1✔
108
            Literal::String(_) => SType::SString,
×
109
            Literal::BigInt(_) => SType::SBigInt,
1✔
110
            Literal::UnsignedBigInt(_) => SType::SUnsignedBigInt,
1✔
111
            Literal::SigmaProp(_) => SType::SSigmaProp,
1✔
112
            Literal::GroupElement(_) => SType::SGroupElement,
1✔
113
            Literal::AvlTree(_) => SType::SAvlTree,
×
114
            Literal::Header(_) => SType::SHeader,
1✔
115
            Literal::CBox(_) => SType::SBox,
×
116
            Literal::Coll(coll_kind) => SType::SColl(coll_kind.elem_tpe().clone().into()),
1✔
117
            Literal::Opt(Some(literal)) => SType::SOption(literal.tpe()?.into()),
×
118
            Literal::Opt(None) => return Err("Can not infer type of Option.None"),
×
119
            Literal::Tup(bounded_vec) => SType::STuple(STuple {
2✔
120
                items: bounded_vec.try_mapped_ref(Literal::tpe)?,
1✔
121
            }),
122
        };
123
        Ok(tpe)
1✔
124
    }
125
}
126

127
impl Constant {
128
    /// Create a new Constant::Coll from an iterator of constants.
129
    /// Returns an error if i is empty and tpe is not provided (type cannot be inferred), or the type for all values isn't the same
130
    pub fn coll_from_iter(
2✔
131
        i: impl IntoIterator<Item = Constant>,
132
        elem_tpe: Option<SType>,
133
    ) -> Result<Constant, TryExtractFromError> {
134
        let mut stype: Option<SType> = elem_tpe;
2✔
135
        let iter = i
6✔
136
            .into_iter()
137
            .map(|constant| {
1✔
138
                if let Some(ref stype) = stype {
2✔
139
                    if constant.tpe != *stype {
2✔
140
                        return Err(TryExtractFromError(format!(
1✔
141
                            "Constant.from_iter: expected tpe to be {:?}, found {:?}",
×
142
                            stype, constant.tpe
×
143
                        )));
144
                    }
145
                } else {
146
                    stype = Some(constant.tpe);
1✔
147
                }
148
                Ok(constant.v)
1✔
149
            })
150
            .collect::<Result<Arc<[_]>, TryExtractFromError>>()?;
151
        match stype {
2✔
152
            None => Err(TryExtractFromError(
1✔
153
                "Constant.from_iter does not support empty iterators".into(),
1✔
154
            )),
155
            Some(SType::SByte) => Ok(Constant {
×
156
                tpe: SType::SColl(SType::SByte.into()),
×
157
                v: Literal::Coll(CollKind::from_collection(SType::SByte, iter)?),
×
158
            }),
159
            Some(tpe) => Ok(Constant {
4✔
160
                tpe: SType::SColl(tpe.clone().into()),
4✔
161
                v: Literal::Coll(CollKind::from_collection(tpe, iter)?),
4✔
162
            }),
163
        }
164
    }
165
}
166

167
impl core::fmt::Debug for Constant {
168
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3✔
169
        format!("{:?}: {:?}", self.v, self.tpe).fmt(f)
3✔
170
    }
171
}
172

173
impl core::fmt::Display for Constant {
174
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
×
175
        self.v.fmt(f)
×
176
    }
177
}
178

179
impl core::fmt::Debug for Literal {
180
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4✔
181
        match self {
5✔
182
            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
1✔
183
                base16::encode_lower(&i8_bytes.as_vec_u8()).fmt(f)
3✔
184
            }
185
            Literal::Coll(CollKind::WrappedColl { elem_tpe: _, items }) => items.fmt(f),
1✔
186
            Literal::Opt(boxed_opt) => boxed_opt.fmt(f),
×
187
            Literal::Tup(items) => items.fmt(f),
1✔
188
            Literal::Unit => ().fmt(f),
×
189
            Literal::Boolean(v) => v.fmt(f),
3✔
190
            Literal::Byte(v) => v.fmt(f),
1✔
191
            Literal::Short(v) => v.fmt(f),
1✔
192
            Literal::Int(v) => v.fmt(f),
4✔
193
            Literal::Long(v) => v.fmt(f),
2✔
194
            Literal::BigInt(v) => v.fmt(f),
1✔
195
            Literal::SigmaProp(v) => v.fmt(f),
1✔
196
            Literal::GroupElement(v) => v.fmt(f),
1✔
197
            Literal::UnsignedBigInt(v) => v.fmt(f),
×
198
            Literal::AvlTree(v) => v.fmt(f),
×
199
            Literal::Header(v) => v.fmt(f),
×
200
            Literal::CBox(v) => v.fmt(f),
×
201
            Literal::String(v) => v.fmt(f),
×
202
        }
203
    }
204
}
205

206
impl core::fmt::Display for Literal {
207
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
×
208
        match self {
×
209
            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
×
210
                write!(f, "Coll[Byte](")?;
×
211
                for (i, b) in i8_bytes.iter().enumerate() {
×
212
                    if i > 0 {
×
213
                        write!(f, ", ")?;
×
214
                    }
215
                    write!(f, "{}", b)?;
×
216
                }
217
                write!(f, ")")
×
218
            }
219
            Literal::Coll(CollKind::WrappedColl { elem_tpe, items }) => {
×
220
                write!(f, "Coll[{}](", elem_tpe)?;
×
221
                for (i, item) in items.iter().enumerate() {
×
222
                    if i > 0 {
×
223
                        write!(f, ", ")?;
×
224
                    }
225
                    item.fmt(f)?;
×
226
                }
227
                write!(f, ")")
×
228
            }
229
            Literal::Opt(boxed_opt) => {
×
230
                if let Some(v) = boxed_opt {
×
231
                    write!(f, "Some(")?;
×
232
                    v.fmt(f)?;
×
233
                    write!(f, ")")
×
234
                } else {
235
                    write!(f, "None")
×
236
                }
237
            }
238
            Literal::Tup(items) => {
×
239
                write!(f, "(")?;
×
240
                for (i, item) in items.iter().enumerate() {
×
241
                    if i > 0 {
×
242
                        write!(f, ", ")?;
×
243
                    }
244
                    item.fmt(f)?;
×
245
                }
246
                write!(f, ")")
×
247
            }
248
            Literal::Unit => write!(f, "()"),
×
249
            Literal::Boolean(v) => v.fmt(f),
×
250
            Literal::Byte(v) => v.fmt(f),
×
251
            Literal::Short(v) => v.fmt(f),
×
252
            Literal::Int(v) => v.fmt(f),
×
253
            Literal::Long(v) => write!(f, "{}L", v),
×
254
            Literal::BigInt(v) => v.fmt(f),
×
255
            Literal::SigmaProp(v) => v.fmt(f),
×
256
            Literal::UnsignedBigInt(v) => v.fmt(f),
×
257
            Literal::GroupElement(v) => v.fmt(f),
×
258
            Literal::AvlTree(v) => write!(f, "AvlTree({:?})", v),
×
259
            Literal::Header(v) => write!(f, "Header({:?})", v),
×
260
            Literal::CBox(v) => write!(f, "ErgoBox({:?})", v),
×
261
            Literal::String(v) => write!(f, "String({v})"),
×
262
        }
263
    }
264
}
265

266
impl From<()> for Literal {
267
    fn from(_: ()) -> Literal {
×
268
        Literal::Unit
×
269
    }
270
}
271

272
impl From<bool> for Literal {
273
    fn from(v: bool) -> Literal {
5✔
274
        Literal::Boolean(v)
5✔
275
    }
276
}
277

278
impl From<i8> for Literal {
279
    fn from(v: i8) -> Literal {
5✔
280
        Literal::Byte(v)
5✔
281
    }
282
}
283

284
impl From<i16> for Literal {
285
    fn from(v: i16) -> Literal {
5✔
286
        Literal::Short(v)
5✔
287
    }
288
}
289

290
impl From<i32> for Literal {
291
    fn from(v: i32) -> Literal {
7✔
292
        Literal::Int(v)
7✔
293
    }
294
}
295

296
impl From<i64> for Literal {
297
    fn from(v: i64) -> Literal {
7✔
298
        Literal::Long(v)
7✔
299
    }
300
}
301

302
impl From<BigInt256> for Literal {
303
    fn from(v: BigInt256) -> Literal {
2✔
304
        Literal::BigInt(v)
2✔
305
    }
306
}
307

308
impl From<SigmaProp> for Literal {
309
    fn from(v: SigmaProp) -> Literal {
8✔
310
        Literal::SigmaProp(Box::new(v))
6✔
311
    }
312
}
313

314
impl From<UnsignedBigInt> for Literal {
315
    fn from(v: UnsignedBigInt) -> Literal {
3✔
316
        Literal::UnsignedBigInt(v)
3✔
317
    }
318
}
319

320
impl From<EcPoint> for Literal {
321
    fn from(v: EcPoint) -> Literal {
5✔
322
        Literal::GroupElement(Arc::new(v))
5✔
323
    }
324
}
325

326
impl From<Ref<'_, EcPoint>> for Literal {
327
    fn from(value: Ref<'_, EcPoint>) -> Self {
1✔
328
        Literal::GroupElement(value.to_arc())
2✔
329
    }
330
}
331

332
impl From<Ref<'static, ErgoBox>> for Literal {
333
    fn from(b: Ref<'static, ErgoBox>) -> Self {
×
334
        Literal::CBox(b)
×
335
    }
336
}
337

338
impl From<ErgoBox> for Literal {
339
    fn from(b: ErgoBox) -> Self {
×
340
        Literal::CBox(Arc::new(b).into())
×
341
    }
342
}
343

344
impl From<Vec<u8>> for Literal {
345
    fn from(v: Vec<u8>) -> Self {
3✔
346
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
3✔
347
            v.as_vec_i8().into(),
6✔
348
        ))) // TODO: optimize
349
    }
350
}
351

352
impl From<Digest32> for Literal {
353
    fn from(v: Digest32) -> Self {
1✔
354
        let bytes: Vec<u8> = v.into();
1✔
355
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
1✔
356
            bytes.as_vec_i8().into(), // TODO: optimize
2✔
357
        )))
358
    }
359
}
360

361
impl From<TokenId> for Literal {
362
    fn from(v: TokenId) -> Self {
×
363
        Digest32::from(v).into()
×
364
    }
365
}
366

367
impl From<Vec<i8>> for Literal {
368
    fn from(v: Vec<i8>) -> Self {
5✔
369
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v.into()))) // TODO
5✔
370
    }
371
}
372

373
impl<T: LiftIntoSType + StoreWrapped + Into<Literal>> From<Vec<T>> for Literal {
374
    fn from(v: Vec<T>) -> Self {
3✔
375
        Literal::Coll(CollKind::WrappedColl {
6✔
376
            elem_tpe: T::stype(),
3✔
377
            items: v.into_iter().map(|i| i.into()).collect(),
12✔
378
        })
379
    }
380
}
381

382
impl<T: LiftIntoSType + Into<Literal>> From<Option<T>> for Literal {
383
    fn from(opt: Option<T>) -> Self {
×
384
        Literal::Opt(opt.map(|e| e.into()).map(Box::new))
×
385
    }
386
}
387

388
impl<'ctx> TryFrom<Value<'ctx>> for Literal {
389
    type Error = String;
390
    #[allow(clippy::unwrap_used)]
391
    fn try_from(value: Value<'ctx>) -> Result<Self, Self::Error> {
1✔
392
        match value {
1✔
393
            Value::Boolean(b) => Ok(Literal::from(b)),
2✔
394
            Value::Byte(b) => Ok(Literal::from(b)),
2✔
395
            Value::Short(s) => Ok(Literal::from(s)),
2✔
396
            Value::Int(i) => Ok(Literal::from(i)),
2✔
397
            Value::Long(l) => Ok(Literal::from(l)),
2✔
398
            Value::BigInt(b) => Ok(Literal::from(b)),
2✔
399
            Value::Unit => Ok(Literal::Unit),
×
400
            Value::SigmaProp(s) => Ok(Literal::from(*s)),
2✔
401
            Value::UnsignedBigInt(b) => Ok(Literal::from(b)),
2✔
402
            Value::GroupElement(e) => Ok(Literal::from(e)),
2✔
403
            Value::CBox(i) => Ok(Literal::from(i.to_static())),
×
404
            Value::Coll(coll) => {
1✔
405
                let v = match coll {
1✔
406
                    CollKind::NativeColl(n) => Literal::Coll(CollKind::NativeColl(n)),
1✔
407
                    CollKind::WrappedColl { elem_tpe, items } => {
1✔
408
                        let new_items = items
2✔
409
                            .iter()
410
                            .map(|v| Literal::try_from(v.clone()))
2✔
411
                            .collect::<Result<Arc<[_]>, String>>()?;
412

413
                        Literal::Coll(CollKind::WrappedColl {
1✔
414
                            elem_tpe: elem_tpe.clone(),
1✔
415
                            items: new_items,
1✔
416
                        })
417
                    }
418
                };
419
                Ok(v)
1✔
420
            }
421
            Value::Opt(lit) => match lit {
×
422
                Some(v) => {
×
423
                    let v = Literal::try_from((*v).clone())?;
×
424
                    Ok(Literal::Opt(Some(Box::new(v))))
×
425
                }
426
                None => Ok(Literal::Opt(None)),
×
427
            },
428
            Value::Tup(t) => {
1✔
429
                if let Ok(t) = t.try_mapped::<_, _, String>(Literal::try_from) {
3✔
430
                    Ok(Literal::Tup(t))
1✔
431
                } else {
432
                    Err("Can't convert Value:Tup element".into())
×
433
                }
434
            }
435
            Value::AvlTree(a) => Ok(Literal::from(*a)),
×
436
            Value::String(s) => Ok(Literal::from(s)),
×
437
            Value::Header(h) => Ok(Literal::from(*h)),
2✔
438
            Value::Context => Err("Cannot convert Value::Context into Literal".into()),
×
439
            Value::PreHeader(_) => Err("Cannot convert Value::PreHeader(_) into Literal".into()),
×
440
            Value::Global => Err("Cannot convert Value::Global into Literal".into()),
×
441
            Value::Lambda(_) => Err("Cannot convert Value::Lambda(_) into Literal".into()),
×
442
        }
443
    }
444
}
445

446
impl TryFrom<Literal> for Constant {
447
    type Error = &'static str;
448

449
    fn try_from(v: Literal) -> Result<Self, Self::Error> {
1✔
450
        Ok(Self { tpe: v.tpe()?, v })
2✔
451
    }
452
}
453

454
impl<'ctx> TryFrom<Value<'ctx>> for Constant {
455
    type Error = String;
456
    #[allow(clippy::unwrap_used)]
457
    fn try_from(value: Value<'ctx>) -> Result<Self, Self::Error> {
1✔
458
        Literal::try_from(value)?.try_into().map_err(Into::into)
1✔
459
    }
460
}
461

462
impl From<()> for Constant {
463
    fn from(_: ()) -> Self {
1✔
464
        Constant {
465
            tpe: SType::SUnit,
466
            v: Literal::Unit,
467
        }
468
    }
469
}
470

471
impl From<bool> for Constant {
472
    fn from(v: bool) -> Self {
5✔
473
        Constant {
474
            tpe: bool::stype(),
5✔
475
            v: v.into(),
5✔
476
        }
477
    }
478
}
479

480
impl From<i8> for Constant {
481
    fn from(v: i8) -> Self {
5✔
482
        Constant {
483
            tpe: i8::stype(),
5✔
484
            v: v.into(),
5✔
485
        }
486
    }
487
}
488

489
impl From<i16> for Constant {
490
    fn from(v: i16) -> Self {
5✔
491
        Constant {
492
            tpe: i16::stype(),
5✔
493
            v: v.into(),
5✔
494
        }
495
    }
496
}
497

498
impl From<i32> for Constant {
499
    fn from(v: i32) -> Self {
7✔
500
        Constant {
501
            tpe: i32::stype(),
7✔
502
            v: v.into(),
7✔
503
        }
504
    }
505
}
506

507
impl From<i64> for Constant {
508
    fn from(v: i64) -> Self {
8✔
509
        Constant {
510
            tpe: i64::stype(),
7✔
511
            v: v.into(),
7✔
512
        }
513
    }
514
}
515

516
impl From<SigmaProp> for Constant {
517
    fn from(v: SigmaProp) -> Self {
7✔
518
        Constant {
519
            tpe: SType::SSigmaProp,
520
            v: v.into(),
6✔
521
        }
522
    }
523
}
524

525
impl From<UnsignedBigInt> for Constant {
526
    fn from(v: UnsignedBigInt) -> Self {
3✔
527
        Constant {
528
            tpe: SType::SUnsignedBigInt,
529
            v: v.into(),
3✔
530
        }
531
    }
532
}
533

534
impl From<EcPoint> for Constant {
535
    fn from(v: EcPoint) -> Constant {
5✔
536
        Constant {
537
            tpe: SType::SGroupElement,
538
            v: v.into(),
5✔
539
        }
540
    }
541
}
542

543
impl From<Ref<'_, EcPoint>> for Constant {
544
    fn from(v: Ref<'_, EcPoint>) -> Self {
×
545
        Constant {
546
            tpe: SType::SGroupElement,
547
            v: v.into(),
×
548
        }
549
    }
550
}
551

552
impl From<ErgoBox> for Constant {
553
    fn from(b: ErgoBox) -> Self {
1✔
554
        Constant {
555
            tpe: SType::SBox,
556
            v: Literal::CBox(Arc::new(b).into()),
2✔
557
        }
558
    }
559
}
560

561
impl From<Ref<'static, ErgoBox>> for Constant {
562
    fn from(b: Ref<'static, ErgoBox>) -> Self {
×
563
        Constant {
564
            tpe: SType::SBox,
565
            v: Literal::CBox(b),
×
566
        }
567
    }
568
}
569

570
impl From<Vec<u8>> for Constant {
571
    fn from(v: Vec<u8>) -> Self {
3✔
572
        Constant {
573
            tpe: SType::SColl(Arc::new(SType::SByte)),
6✔
574
            v: v.into(),
3✔
575
        }
576
    }
577
}
578

579
impl From<Digest32> for Constant {
580
    fn from(v: Digest32) -> Self {
1✔
581
        Constant {
582
            tpe: SType::SColl(Arc::new(SType::SByte)),
1✔
583
            v: v.into(),
1✔
584
        }
585
    }
586
}
587

588
impl From<TokenId> for Constant {
589
    fn from(v: TokenId) -> Self {
1✔
590
        Digest32::from(v).into()
1✔
591
    }
592
}
593

594
impl From<Vec<i8>> for Constant {
595
    fn from(v: Vec<i8>) -> Self {
5✔
596
        Constant {
597
            tpe: SType::SColl(Arc::new(SType::SByte)),
10✔
598
            v: v.into(),
5✔
599
        }
600
    }
601
}
602

603
impl<T: LiftIntoSType + StoreWrapped + Into<Constant>> From<Vec<T>> for Constant {
604
    fn from(v: Vec<T>) -> Self {
14✔
605
        Constant {
606
            tpe: Vec::<T>::stype(),
15✔
607
            v: Literal::Coll(CollKind::WrappedColl {
15✔
608
                elem_tpe: T::stype(),
609
                items: v.into_iter().map(|i| i.into().v).collect(),
610
            }),
611
        }
612
    }
613
}
614

615
impl<T: LiftIntoSType + Into<Constant>> From<Option<T>> for Constant {
616
    fn from(opt: Option<T>) -> Self {
7✔
617
        Constant {
618
            tpe: SType::SOption(Arc::new(T::stype())),
14✔
619
            v: Literal::Opt(opt.map(|e| e.into().v).map(Box::new)),
29✔
620
        }
621
    }
622
}
623

624
impl From<ProveDlog> for Literal {
625
    fn from(v: ProveDlog) -> Self {
×
626
        Literal::from(SigmaProp::from(SigmaBoolean::from(
×
627
            SigmaProofOfKnowledgeTree::from(v),
×
628
        )))
629
    }
630
}
631

632
impl From<ProveDhTuple> for Literal {
633
    fn from(dht: ProveDhTuple) -> Self {
×
634
        Literal::from(SigmaProp::from(SigmaBoolean::from(
×
635
            SigmaProofOfKnowledgeTree::from(dht),
×
636
        )))
637
    }
638
}
639

640
impl From<SigmaBoolean> for Literal {
641
    fn from(sb: SigmaBoolean) -> Self {
×
642
        Literal::from(SigmaProp::from(sb))
×
643
    }
644
}
645

646
impl From<AvlTreeData> for Literal {
647
    fn from(a: AvlTreeData) -> Self {
×
648
        Literal::AvlTree(Box::new(a))
×
649
    }
650
}
651

652
impl From<Header> for Literal {
653
    fn from(h: Header) -> Self {
1✔
654
        Literal::Header(h.into())
1✔
655
    }
656
}
657

658
impl From<AvlTreeFlags> for Literal {
659
    fn from(a: AvlTreeFlags) -> Self {
×
660
        Literal::Byte(a.serialize() as i8)
×
661
    }
662
}
663

664
impl From<Arc<str>> for Literal {
665
    fn from(s: Arc<str>) -> Self {
×
666
        Literal::String(s)
×
667
    }
668
}
669

670
impl From<ProveDlog> for Constant {
671
    fn from(v: ProveDlog) -> Self {
5✔
672
        Constant::from(SigmaProp::from(SigmaBoolean::from(
5✔
673
            SigmaProofOfKnowledgeTree::from(v),
7✔
674
        )))
675
    }
676
}
677

678
impl From<ProveDhTuple> for Constant {
679
    fn from(dht: ProveDhTuple) -> Self {
3✔
680
        Constant::from(SigmaProp::from(SigmaBoolean::from(
3✔
681
            SigmaProofOfKnowledgeTree::from(dht),
3✔
682
        )))
683
    }
684
}
685

686
impl From<SigmaBoolean> for Constant {
687
    fn from(sb: SigmaBoolean) -> Self {
1✔
688
        Constant::from(SigmaProp::from(sb))
1✔
689
    }
690
}
691

692
impl From<BigInt256> for Constant {
693
    fn from(b: BigInt256) -> Self {
6✔
694
        Constant {
695
            tpe: SType::SBigInt,
696
            v: Literal::BigInt(b),
6✔
697
        }
698
    }
699
}
700

701
impl From<AvlTreeData> for Constant {
702
    fn from(a: AvlTreeData) -> Self {
2✔
703
        Constant {
704
            tpe: SType::SAvlTree,
705
            v: Literal::AvlTree(Box::new(a)),
4✔
706
        }
707
    }
708
}
709

710
impl From<Header> for Constant {
711
    fn from(h: Header) -> Self {
2✔
712
        Constant {
713
            tpe: SType::SHeader,
714
            v: Literal::Header(h.into()),
4✔
715
        }
716
    }
717
}
718

719
impl From<AvlTreeFlags> for Constant {
720
    fn from(a: AvlTreeFlags) -> Self {
1✔
721
        Constant {
722
            tpe: SType::SByte,
723
            v: Literal::Byte(a.serialize() as i8),
2✔
724
        }
725
    }
726
}
727

728
impl From<ADDigest> for Constant {
729
    fn from(a: ADDigest) -> Self {
1✔
730
        Constant {
731
            tpe: SType::SColl(Arc::new(SType::SByte)),
1✔
732
            v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
1✔
733
                a.0.iter().map(|&i| i as i8).collect(),
734
            ))),
735
        }
736
    }
737
}
738

739
impl From<Arc<str>> for Constant {
740
    fn from(s: Arc<str>) -> Self {
×
741
        Constant {
742
            tpe: SType::SString,
743
            v: Literal::String(s),
×
744
        }
745
    }
746
}
747

748
impl From<String> for Constant {
749
    fn from(s: String) -> Self {
1✔
750
        Constant {
751
            tpe: SType::SString,
752
            v: Literal::String(s.into()),
2✔
753
        }
754
    }
755
}
756

757
#[allow(clippy::unwrap_used)]
758
#[allow(clippy::from_over_into)]
759
#[impl_for_tuples(2, 4)]
760
impl Into<Constant> for Tuple {
761
    fn into(self) -> Constant {
7✔
762
        let constants: Vec<Constant> = [for_tuples!(  #( Tuple.into() ),* )].to_vec();
10✔
763
        let (types, values): (Vec<SType>, Vec<Literal>) =
15✔
764
            constants.into_iter().map(|c| (c.tpe, c.v)).unzip();
765
        Constant {
766
            tpe: SType::STuple(types.try_into().unwrap()),
14✔
767
            v: Literal::Tup(values.try_into().unwrap()),
14✔
768
        }
769
    }
770
}
771

772
/// Extract value wrapped in a type
773
pub trait TryExtractInto<F> {
774
    /// Extract value of the given type from any type (e.g. ['Constant'], [`super::value::Value`])
775
    /// on which [`TryExtractFrom`] is implemented
776
    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError>;
777
}
778

779
impl<F> TryExtractInto<F> for F {
780
    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError> {
77✔
781
        T::try_extract_from(self)
77✔
782
    }
783
}
784

785
/// Underlying type is different from requested value type
786
#[derive(Error, PartialEq, Eq, Debug, Clone)]
787
#[error("Failed TryExtractFrom: {0}")]
788
pub struct TryExtractFromError(pub String);
789

790
/// Extract underlying value if type matches
791
pub trait TryExtractFrom<T>: Sized {
792
    /// Extract the value or return an error if type does not match
793
    fn try_extract_from(v: T) -> Result<Self, TryExtractFromError>;
794
}
795

796
impl<T: TryExtractFrom<Literal>> TryExtractFrom<Constant> for T {
797
    fn try_extract_from(cv: Constant) -> Result<Self, TryExtractFromError> {
28✔
798
        T::try_extract_from(cv.v)
28✔
799
    }
800
}
801

802
impl TryExtractFrom<Literal> for () {
803
    fn try_extract_from(cv: Literal) -> Result<(), TryExtractFromError> {
1✔
804
        match cv {
1✔
805
            Literal::Unit => Ok(()),
1✔
806
            _ => Err(TryExtractFromError(format!(
×
807
                "expected Unit, found {:?}",
808
                cv
809
            ))),
810
        }
811
    }
812
}
813

814
impl TryExtractFrom<Literal> for bool {
815
    fn try_extract_from(cv: Literal) -> Result<bool, TryExtractFromError> {
5✔
816
        match cv {
5✔
817
            Literal::Boolean(v) => Ok(v),
5✔
818
            _ => Err(TryExtractFromError(format!(
×
819
                "expected bool, found {:?}",
820
                cv
821
            ))),
822
        }
823
    }
824
}
825

826
impl TryExtractFrom<Literal> for i8 {
827
    fn try_extract_from(cv: Literal) -> Result<i8, TryExtractFromError> {
5✔
828
        match cv {
5✔
829
            Literal::Byte(v) => Ok(v),
5✔
830
            _ => Err(TryExtractFromError(format!("expected i8, found {:?}", cv))),
×
831
        }
832
    }
833
}
834

835
impl TryExtractFrom<Literal> for i16 {
836
    fn try_extract_from(cv: Literal) -> Result<i16, TryExtractFromError> {
1✔
837
        match cv {
1✔
838
            Literal::Short(v) => Ok(v),
1✔
839
            _ => Err(TryExtractFromError(format!("expected i16, found {:?}", cv))),
×
840
        }
841
    }
842
}
843

844
impl TryExtractFrom<Literal> for i32 {
845
    fn try_extract_from(cv: Literal) -> Result<i32, TryExtractFromError> {
1✔
846
        match cv {
1✔
847
            Literal::Int(v) => Ok(v),
1✔
848
            _ => Err(TryExtractFromError(format!("expected i32, found {:?}", cv))),
×
849
        }
850
    }
851
}
852

853
impl TryExtractFrom<Literal> for i64 {
854
    fn try_extract_from(cv: Literal) -> Result<i64, TryExtractFromError> {
1✔
855
        match cv {
1✔
856
            Literal::Long(v) => Ok(v),
1✔
857
            _ => Err(TryExtractFromError(format!("expected i64, found {:?}", cv))),
×
858
        }
859
    }
860
}
861

862
impl TryExtractFrom<Literal> for EcPoint {
863
    fn try_extract_from(cv: Literal) -> Result<EcPoint, TryExtractFromError> {
1✔
864
        match cv {
1✔
865
            Literal::GroupElement(v) => Ok(*v),
1✔
866
            _ => Err(TryExtractFromError(format!(
×
867
                "expected EcPoint, found {:?}",
868
                cv
869
            ))),
870
        }
871
    }
872
}
873

874
impl TryExtractFrom<Literal> for SigmaProp {
875
    fn try_extract_from(cv: Literal) -> Result<SigmaProp, TryExtractFromError> {
1✔
876
        match cv {
1✔
877
            Literal::SigmaProp(v) => Ok(*v),
3✔
878
            _ => Err(TryExtractFromError(format!(
×
879
                "expected SigmaProp, found {:?}",
880
                cv
881
            ))),
882
        }
883
    }
884
}
885

886
impl TryExtractFrom<Literal> for UnsignedBigInt {
887
    fn try_extract_from(cv: Literal) -> Result<UnsignedBigInt, TryExtractFromError> {
1✔
888
        match cv {
1✔
889
            Literal::UnsignedBigInt(v) => Ok(v),
1✔
890
            _ => Err(TryExtractFromError(format!(
×
891
                "expected UnsignedBigInt, found {:?}",
892
                cv
893
            ))),
894
        }
895
    }
896
}
897

898
impl TryExtractFrom<Literal> for Ref<'static, ErgoBox> {
899
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
×
900
        match c {
×
901
            Literal::CBox(b) => Ok(b),
×
902
            _ => Err(TryExtractFromError(format!(
×
903
                "expected ErgoBox, found {:?}",
904
                c
905
            ))),
906
        }
907
    }
908
}
909

910
impl TryExtractFrom<Literal> for ErgoBox {
911
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
×
912
        match c {
×
913
            Literal::CBox(b) => Ok((*b).clone()),
×
914
            _ => Err(TryExtractFromError(format!(
×
915
                "expected ErgoBox, found {:?}",
916
                c
917
            ))),
918
        }
919
    }
920
}
921

922
impl<T: TryExtractFrom<Literal> + StoreWrapped> TryExtractFrom<Literal> for Vec<T> {
923
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
7✔
924
        match c {
7✔
925
            Literal::Coll(coll) => match coll {
7✔
926
                CollKind::WrappedColl {
7✔
927
                    elem_tpe: _,
×
928
                    items: v,
×
929
                } => v.iter().cloned().map(T::try_extract_from).collect(),
×
930
                _ => Err(TryExtractFromError(format!(
×
931
                    "expected {:?}, found {:?}",
×
932
                    core::any::type_name::<Self>(),
×
933
                    coll
×
934
                ))),
935
            },
936
            _ => Err(TryExtractFromError(format!(
×
937
                "expected {:?}, found {:?}",
×
938
                core::any::type_name::<Self>(),
×
939
                c
×
940
            ))),
941
        }
942
    }
943
}
944

945
impl TryExtractFrom<Literal> for Vec<i8> {
946
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
947
        match v {
2✔
948
            Literal::Coll(v) => match v {
2✔
949
                CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO: optimize
2✔
950
                _ => Err(TryExtractFromError(format!(
×
951
                    "expected {:?}, found {:?}",
952
                    core::any::type_name::<Self>(),
×
953
                    v
954
                ))),
955
            },
956
            _ => Err(TryExtractFromError(format!(
1✔
957
                "expected {:?}, found {:?}",
958
                core::any::type_name::<Self>(),
2✔
959
                v
960
            ))),
961
        }
962
    }
963
}
964

965
impl TryExtractFrom<Literal> for Vec<u8> {
966
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
967
        use sigma_util::FromVecI8;
968
        Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)
2✔
969
    }
970
}
971

972
impl TryExtractFrom<Literal> for Digest32 {
973
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
974
        use sigma_util::FromVecI8;
975
        let bytes = Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)?;
2✔
976
        Digest32::try_from(bytes).map_err(|e| {
2✔
977
            TryExtractFromError(format!("failed to extract Digest32 with error: {:?}", e))
×
978
        })
979
    }
980
}
981

982
impl TryExtractFrom<Literal> for TokenId {
983
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
984
        Digest32::try_extract_from(v).map(Into::into)
1✔
985
    }
986
}
987

988
impl TryExtractFrom<Literal> for Literal {
989
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
×
990
        Ok(v)
×
991
    }
992
}
993

994
impl TryExtractFrom<Literal> for BigInt256 {
995
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
996
        match v {
1✔
997
            Literal::BigInt(bi) => Ok(bi),
1✔
998
            _ => Err(TryExtractFromError(format!(
×
999
                "expected {:?}, found {:?}",
1000
                core::any::type_name::<Self>(),
×
1001
                v
1002
            ))),
1003
        }
1004
    }
1005
}
1006

1007
impl TryExtractFrom<Literal> for String {
1008
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
1009
        match v {
1✔
1010
            Literal::String(s) => Ok(String::from(&*s)),
1✔
1011
            _ => Err(TryExtractFromError(format!(
×
1012
                "expected {:?}, found {:?}",
1013
                core::any::type_name::<Self>(),
×
1014
                v
1015
            ))),
1016
        }
1017
    }
1018
}
1019

1020
impl TryExtractFrom<Literal> for AvlTreeData {
1021
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
×
1022
        match v {
×
1023
            Literal::AvlTree(a) => Ok(*a),
×
1024
            _ => Err(TryExtractFromError(format!(
×
1025
                "expected {:?}, found {:?}",
1026
                core::any::type_name::<Self>(),
×
1027
                v
1028
            ))),
1029
        }
1030
    }
1031
}
1032

1033
impl<T: TryExtractFrom<Literal>> TryExtractFrom<Literal> for Option<T> {
1034
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
4✔
1035
        match v {
4✔
1036
            Literal::Opt(opt) => opt.map(|boxed| *boxed).map(T::try_extract_from).transpose(),
16✔
1037
            _ => Err(TryExtractFromError(format!(
×
1038
                "expected Option, found {:?}",
×
1039
                v
×
1040
            ))),
1041
        }
1042
    }
1043
}
1044

1045
#[impl_for_tuples(2, 4)]
1046
impl TryExtractFrom<Literal> for Tuple {
1047
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
1048
        match v {
2✔
1049
            Literal::Tup(items) => {
2✔
1050
                let mut iter = items.iter();
4✔
1051
                Ok(for_tuples!( ( #(
2✔
1052
                                Tuple::try_extract_from(
1053
                                    iter
6✔
1054
                                        .next()
1055
                                        .cloned()
1056
                                        .ok_or_else(|| TryExtractFromError("not enough items in STuple".to_string()))?
×
1057
                                )?
1058
                                ),* ) ))
×
1059
            }
1060
            _ => Err(TryExtractFromError(format!(
×
1061
                "expected Context, found {:?}",
1062
                v
1063
            ))),
1064
        }
1065
    }
1066
}
1067

1068
impl TryFrom<Literal> for ProveDlog {
1069
    type Error = TryExtractFromError;
1070
    fn try_from(cv: Literal) -> Result<Self, Self::Error> {
2✔
1071
        match cv {
2✔
1072
            Literal::SigmaProp(sp) => match sp.value() {
6✔
1073
                SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(
2✔
1074
                    prove_dlog,
1075
                )) => Ok(prove_dlog.clone()),
1076
                _ => Err(TryExtractFromError(format!(
×
1077
                    "expected ProveDlog, found {:?}",
1078
                    sp
1079
                ))),
1080
            },
1081
            _ => Err(TryExtractFromError(format!(
×
1082
                "expected SigmaProp, found {:?}",
1083
                cv
1084
            ))),
1085
        }
1086
    }
1087
}
1088

1089
impl Base16Str for &Constant {
1090
    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
×
1091
        self.sigma_serialize_bytes()
×
1092
            .map(|bytes| base16::encode_lower(&bytes))
×
1093
    }
1094
}
1095

1096
impl Base16Str for Constant {
1097
    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
1✔
1098
        self.sigma_serialize_bytes()
1✔
1099
            .map(|bytes| base16::encode_lower(&bytes))
2✔
1100
    }
1101
}
1102

1103
impl TryFrom<Base16DecodedBytes> for Constant {
1104
    type Error = SigmaParsingError;
1105

1106
    fn try_from(value: Base16DecodedBytes) -> Result<Self, Self::Error> {
×
1107
        Constant::sigma_parse_bytes(&value.0)
×
1108
    }
1109
}
1110

1111
#[cfg(feature = "arbitrary")]
1112
#[allow(clippy::unwrap_used)]
1113
#[allow(clippy::todo)]
1114
/// Arbitrary impl
1115
pub(crate) mod arbitrary {
1116
    use core::convert::TryFrom;
1117

1118
    use super::*;
1119
    use crate::mir::value::CollKind;
1120
    use crate::types::stuple::STuple;
1121
    use proptest::collection::vec;
1122
    use proptest::prelude::*;
1123

1124
    extern crate derive_more;
1125
    use derive_more::From;
1126
    use derive_more::TryInto;
1127

1128
    fn primitive_type_value() -> BoxedStrategy<Constant> {
7✔
1129
        prop_oneof![
58✔
1130
            any::<bool>().prop_map_into(),
6✔
1131
            any::<i8>().prop_map_into(),
13✔
1132
            any::<i16>().prop_map_into(),
13✔
1133
            any::<i32>().prop_map_into(),
13✔
1134
            any::<i64>().prop_map_into(),
13✔
1135
            any::<i64>().prop_map(|v| BigInt256::from(v).into()),
23✔
1136
            any::<EcPoint>().prop_map_into(),
13✔
1137
            any::<SigmaProp>().prop_map_into(),
13✔
1138
            // although it's not strictly a primitive type, byte array is widely used as one
1139
            vec(any::<i8>(), 0..100).prop_map_into(),
13✔
1140
        ]
1141
        .boxed()
1142
    }
1143

1144
    fn coll_from_constant(c: Constant, length: usize) -> Constant {
5✔
1145
        Constant {
1146
            tpe: SType::SColl(Arc::new(c.tpe.clone())),
10✔
1147
            v: Literal::Coll(if c.tpe == SType::SByte {
24✔
1148
                let mut values: Vec<i8> = Vec::with_capacity(length);
1149
                let byte: i8 = c.v.try_extract_into().unwrap();
1150
                for _ in 0..length {
1151
                    values.push(byte);
1152
                }
1153
                CollKind::NativeColl(NativeColl::CollByte(values.into())) // TODO: optimize
1154
            } else {
1155
                let mut values: Vec<Literal> = Vec::with_capacity(length);
1156
                for _ in 0..length {
1157
                    values.push(c.v.clone());
1158
                }
1159
                CollKind::WrappedColl {
1160
                    elem_tpe: c.tpe,
1161
                    items: values.into(),
1162
                }
1163
            }),
1164
        }
1165
    }
1166

1167
    fn const_with_type(tpe: SType) -> BoxedStrategy<Constant> {
7✔
1168
        match tpe {
9✔
1169
            SType::SAny => any::<Constant>(),
4✔
1170
            SType::SBoolean => any::<bool>().prop_map_into().boxed(),
4✔
1171
            SType::SByte => any::<i8>().prop_map_into().boxed(),
2✔
1172
            SType::SShort => any::<i16>().prop_map_into().boxed(),
2✔
1173
            SType::SInt => any::<i32>().prop_map_into().boxed(),
2✔
1174
            SType::SLong => any::<i64>().prop_map_into().boxed(),
2✔
1175
            SType::SBigInt => any::<i64>().prop_map(|v| BigInt256::from(v).into()).boxed(),
4✔
1176
            SType::SGroupElement => any::<EcPoint>().prop_map_into().boxed(),
2✔
1177
            SType::SSigmaProp => any::<SigmaProp>().prop_map_into().boxed(),
13✔
1178
            SType::SBox => any::<ErgoBox>().prop_map_into().boxed(),
2✔
1179
            SType::SAvlTree => any::<AvlTreeData>().prop_map_into().boxed(),
2✔
1180
            // SType::SOption(tpe) =>
1181
            SType::SOption(tpe) => match *tpe {
×
1182
                SType::SBoolean => any::<Option<bool>>().prop_map_into().boxed(),
×
1183
                SType::SByte => any::<Option<i8>>().prop_map_into().boxed(),
×
1184
                SType::SShort => any::<Option<i16>>().prop_map_into().boxed(),
×
1185
                SType::SInt => any::<Option<i32>>().prop_map_into().boxed(),
×
1186
                SType::SLong => any::<Option<i64>>().prop_map_into().boxed(),
×
1187
                _ => todo!(),
1188
            },
1189
            SType::SColl(elem_tpe) => match *elem_tpe {
4✔
1190
                SType::SBoolean => vec(any::<bool>(), 0..400).prop_map_into().boxed(),
4✔
1191
                SType::SByte => vec(any::<u8>(), 0..400).prop_map_into().boxed(),
2✔
1192
                SType::SShort => vec(any::<i16>(), 0..400).prop_map_into().boxed(),
2✔
1193
                SType::SInt => vec(any::<i32>(), 0..400).prop_map_into().boxed(),
2✔
UNCOV
1194
                SType::SLong => vec(any::<i64>(), 0..400).prop_map_into().boxed(),
×
1195
                SType::SSigmaProp => vec(any::<SigmaProp>(), 0..3).prop_map_into().boxed(),
×
1196
                _ => todo!(),
1197
            },
1198
            // SType::STuple(_) => {}
1199
            _ => todo!("{0:?} not yet implemented", tpe),
1200
        }
1201
    }
1202

1203
    impl Default for ArbConstantParams {
1204
        fn default() -> Self {
8✔
1205
            ArbConstantParams::AnyWithDepth(1)
5✔
1206
        }
1207
    }
1208

1209
    /// Parameters for arbitrary Constant generation
1210
    #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
1211
    pub enum ArbConstantParams {
1212
        /// Constant of any type with a structrure of a given depth
1213
        AnyWithDepth(u8),
1214
        /// Constant of a given type
1215
        Exact(SType),
1216
    }
1217

1218
    impl Arbitrary for Constant {
1219
        type Parameters = ArbConstantParams;
1220
        type Strategy = BoxedStrategy<Self>;
1221

1222
        fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
10✔
1223
            match args {
8✔
1224
                ArbConstantParams::AnyWithDepth(depth) => {
8✔
1225
                    prop_oneof![primitive_type_value().prop_recursive(
12✔
1226
                        depth as u32,
6✔
1227
                        16,
1228
                        8,
1229
                        |elem| {
6✔
1230
                            prop_oneof![
35✔
1231
                                // Coll[_]
1232
                                elem.clone().prop_map(|c| coll_from_constant(c, 0)),
21✔
1233
                                elem.clone().prop_map(|c| coll_from_constant(c, 1)),
22✔
1234
                                elem.clone().prop_map(|c| coll_from_constant(c, 2)),
27✔
1235
                                elem.clone().prop_map(|c| coll_from_constant(c, 10)),
29✔
1236
                                // no Option[_] since it cannot be serialized (for now)
1237
                                // // Some(v)
1238
                                // elem.clone().prop_map(|c| Constant {
1239
                                //     tpe: SType::SOption(Box::new(c.tpe)),
1240
                                //     v: Value::Opt(Box::new(Some(c.v)))
1241
                                // }),
1242
                                // // None
1243
                                // elem.prop_map(|c| Constant {
1244
                                //     tpe: SType::SOption(Box::new(c.tpe)),
1245
                                //     v: Value::Opt(Box::new(None))
1246
                                // })
1247

1248
                                // Tuple
1249
                                vec(elem, 2..=4).prop_map(|constants| Constant {
22✔
1250
                                    tpe: SType::STuple(
13✔
1251
                                        STuple::try_from(
6✔
1252
                                            constants
12✔
1253
                                                .clone()
1254
                                                .into_iter()
1255
                                                .map(|c| c.tpe)
12✔
1256
                                                .collect::<Vec<SType>>()
1257
                                        )
1258
                                        .unwrap()
1259
                                    ),
1260
                                    v: Literal::Tup(
7✔
1261
                                        constants
14✔
1262
                                            .into_iter()
1263
                                            .map(|c| c.v)
14✔
1264
                                            .collect::<Vec<Literal>>()
1265
                                            .try_into()
1266
                                            .unwrap()
1267
                                    )
1268
                                }),
1269
                            ]
1270
                        }
1271
                    )]
1272
                    .boxed()
1273
                }
1274
                ArbConstantParams::Exact(tpe) => const_with_type(tpe),
10✔
1275
            }
1276
        }
1277
    }
1278
}
1279

1280
#[allow(clippy::unwrap_used)]
1281
#[cfg(test)]
1282
#[cfg(feature = "arbitrary")]
1283
#[allow(clippy::panic)]
1284
mod tests {
1285
    use crate::{ergo_tree::ErgoTreeVersion, serialization::roundtrip_new_feature};
1286

1287
    use super::*;
1288
    use core::fmt;
1289
    use proptest::prelude::*;
1290

1291
    fn test_constant_roundtrip<T>(v: T)
1292
    where
1293
        T: TryExtractInto<T>
1294
            + TryExtractFrom<Literal>
1295
            + Into<Constant>
1296
            + fmt::Debug
1297
            + Eq
1298
            + Clone
1299
            + 'static,
1300
    {
1301
        let constant: Constant = v.clone().into();
1302
        let v_extracted: T = constant.try_extract_into::<T>().unwrap();
1303
        assert_eq!(v, v_extracted);
1304
    }
1305

1306
    #[test]
1307
    fn unit_roundtrip() {
1308
        test_constant_roundtrip(());
1309
    }
1310

1311
    // test that invalid strings don't error but are instead parsed lossily to match reference impl
1312
    #[test]
1313
    fn parse_invalid_string() {
1314
        let mut bytes = Constant::from(".".to_string())
1315
            .sigma_serialize_bytes()
1316
            .unwrap();
1317
        *bytes.last_mut().unwrap() = 0xf0;
1318
        assert_eq!(
1319
            Constant::sigma_parse_bytes(&bytes).unwrap().v,
1320
            Literal::String("�".into())
1321
        );
1322
    }
1323

1324
    #[test]
1325
    fn constant_from_iter() {
1326
        let iter1 = [
1327
            Constant::from(1i32),
1328
            Constant::from(2i32),
1329
            Constant::from(3i32),
1330
        ];
1331
        assert_eq!(
1332
            Constant::coll_from_iter(iter1, None).unwrap(),
1333
            Constant {
1334
                tpe: SType::SColl(SType::SInt.into()),
1335
                v: Literal::Coll(CollKind::WrappedColl {
1336
                    elem_tpe: SType::SInt,
1337
                    items: [
1338
                        Literal::from(1i32),
1339
                        Literal::from(2i32),
1340
                        Literal::from(3i32)
1341
                    ]
1342
                    .into()
1343
                })
1344
            }
1345
        );
1346
        assert!(Constant::coll_from_iter([], None).is_err());
1347
        assert!(Constant::coll_from_iter([], Some(SType::SBoolean)).is_ok());
1348
        // tpe mismatch
1349
        assert!(Constant::coll_from_iter(
1350
            [
1351
                Constant::from(1i32),
1352
                Constant::from(2i64),
1353
                Constant::from(3i64)
1354
            ],
1355
            None
1356
        )
1357
        .is_err());
1358
    }
1359

1360
    proptest! {
1361

1362
        #![proptest_config(ProptestConfig::with_cases(8))]
1363

1364
        #[test]
1365
        fn bool_roundtrip(v in any::<bool>()) {
1366
            test_constant_roundtrip(v);
1367
        }
1368

1369
        #[test]
1370
        fn i8_roundtrip(v in any::<i8>()) {
1371
            test_constant_roundtrip(v);
1372
        }
1373

1374
        #[test]
1375
        fn i16_roundtrip(v in any::<i16>()) {
1376
            test_constant_roundtrip(v);
1377
        }
1378

1379
        #[test]
1380
        fn i32_roundtrip(v in any::<i32>()) {
1381
            test_constant_roundtrip(v);
1382
        }
1383

1384
        #[test]
1385
        fn i64_roundtrip(v in any::<i64>()) {
1386
            test_constant_roundtrip(v);
1387
        }
1388

1389
        #[test]
1390
        fn bigint_roundtrip(raw in any::<i64>()) {
1391
            let v = BigInt256::from(raw);
1392
            test_constant_roundtrip(v);
1393
        }
1394

1395
        #[test]
1396
        fn group_element_roundtrip(v in any::<EcPoint>()) {
1397
            test_constant_roundtrip(v);
1398
        }
1399

1400
        #[test]
1401
        fn sigma_prop_roundtrip(v in any::<SigmaProp>()) {
1402
            test_constant_roundtrip(v);
1403
        }
1404

1405
        #[test]
1406
        fn unsigned_bigint_roundtrip(v in any::<UnsignedBigInt>()) {
1407
             test_constant_roundtrip(v);
1408
        }
1409

1410
        #[test]
1411
        fn vec_i8_roundtrip(v in any::<Vec<i8>>()) {
1412
            test_constant_roundtrip(v);
1413
        }
1414

1415
        #[test]
1416
        fn vec_u8_roundtrip(v in any::<Vec<u8>>()) {
1417
            // eprintln!("{:?}", Constant::from(v.clone()));
1418
            test_constant_roundtrip(v);
1419
        }
1420

1421
        #[test]
1422
        fn token_id_roundtrip(v in any::<TokenId>()) {
1423
            // eprintln!("{:?}", Constant::from(v.clone()));
1424
            test_constant_roundtrip(v);
1425
        }
1426

1427
        #[test]
1428
        fn digest32_roundtrip(v in any::<Digest32>()) {
1429
            test_constant_roundtrip(v);
1430
        }
1431

1432

1433
        #[test]
1434
        fn vec_i16_roundtrip(v in any::<Vec<i16>>()) {
1435
            test_constant_roundtrip(v);
1436
        }
1437

1438
        #[test]
1439
        fn vec_i32_roundtrip(v in any::<Vec<i32>>()) {
1440
            test_constant_roundtrip(v);
1441
        }
1442

1443
        #[test]
1444
        fn vec_i64_roundtrip(v in any::<Vec<i64>>()) {
1445
            // eprintln!("{:?}", Constant::from(v.clone()));
1446
            test_constant_roundtrip(v);
1447
        }
1448

1449
        #[test]
1450
        fn vec_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1451
            let v: Vec<BigInt256> = raw.into_iter().map(BigInt256::from).collect();
1452
            // eprintln!("{:?}", Constant::from(v.clone()));
1453
            test_constant_roundtrip(v);
1454
        }
1455

1456
        #[test]
1457
        fn vec_option_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1458
            let v: Vec<Option<BigInt256>> = raw.into_iter().map(|i| Some(BigInt256::from(i))).collect();
1459
            // eprintln!("{:?}", Constant::from(v.clone()));
1460
            test_constant_roundtrip(v);
1461
        }
1462

1463
        #[test]
1464
        fn vec_sigmaprop_roundtrip(v in any::<Vec<SigmaProp>>()) {
1465
            test_constant_roundtrip(v);
1466
        }
1467

1468
        #[test]
1469
        fn option_primitive_type_roundtrip(v in any::<Option<i64>>()) {
1470
            test_constant_roundtrip(v);
1471
        }
1472

1473
        #[test]
1474
        fn option_nested_vector_type_roundtrip(v in any::<Option<Vec<(i64, bool)>>>()) {
1475
            // eprintln!("{:?}", Constant::from(v.clone()));
1476
            test_constant_roundtrip(v);
1477
        }
1478

1479
        #[test]
1480
        fn option_nested_tuple_type_roundtrip(v in any::<Option<(i64, bool)>>()) {
1481
            test_constant_roundtrip(v);
1482
        }
1483

1484

1485
        #[test]
1486
        fn tuple_primitive_types_roundtrip(v in any::<(i64, bool)>()) {
1487
            // let constant: Constant = v.into();
1488
            // eprintln!("{:?}", constant);
1489
            test_constant_roundtrip(v);
1490
        }
1491

1492
        #[test]
1493
        fn tuple_nested_types_roundtrip(v in any::<(Option<i64>, Vec<SigmaProp>)>()) {
1494
            test_constant_roundtrip(v);
1495
        }
1496

1497
        #[test]
1498
        fn string_roundtrip(v in any::<String>()) {
1499
            test_constant_roundtrip(v);
1500
        }
1501

1502
        #[test]
1503
        fn header_ser_roundtrip(h in any::<Header>()) {
1504
            roundtrip_new_feature(&Constant::from(h), ErgoTreeVersion::V3);
1505
        }
1506

1507
    }
1508
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc