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

ergoplatform / sigma-rust / 14311715155

07 Apr 2025 02:22PM UTC coverage: 78.24% (-0.03%) from 78.273%
14311715155

Pull #822

github

web-flow
Merge e753f1bba into f2e64bb7f
Pull Request #822: fix: updated the transactionhintsbag implementation

13 of 15 new or added lines in 1 file covered. (86.67%)

7 existing lines in 3 files now uncovered.

11517 of 14720 relevant lines covered (78.24%)

3.03 hits per line

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

64.71
/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 impl_trait_for_tuples::impl_for_tuples;
35
use sigma_util::AsVecI8;
36
use sigma_util::AsVecU8;
37

38
mod constant_placeholder;
39

40
pub use constant_placeholder::*;
41

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

48
use thiserror::Error;
49

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

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

96
impl Constant {
97
    /// Create a new Constant::Coll from an iterator of constants.
98
    /// 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
99
    pub fn coll_from_iter(
2✔
100
        i: impl IntoIterator<Item = Constant>,
101
        elem_tpe: Option<SType>,
102
    ) -> Result<Constant, TryExtractFromError> {
103
        let mut stype: Option<SType> = elem_tpe;
2✔
104
        let iter = i
6✔
105
            .into_iter()
106
            .map(|constant| {
1✔
107
                if let Some(ref stype) = stype {
2✔
108
                    if constant.tpe != *stype {
2✔
109
                        return Err(TryExtractFromError(format!(
2✔
110
                            "Constant.from_iter: expected tpe to be {:?}, found {:?}",
×
111
                            stype, constant.tpe
×
112
                        )));
113
                    }
114
                } else {
115
                    stype = Some(constant.tpe);
1✔
116
                }
117
                Ok(constant.v)
1✔
118
            })
119
            .collect::<Result<Arc<[_]>, TryExtractFromError>>()?;
120
        match stype {
4✔
121
            None => Err(TryExtractFromError(
1✔
122
                "Constant.from_iter does not support empty iterators".into(),
1✔
123
            )),
124
            Some(SType::SByte) => Ok(Constant {
×
125
                tpe: SType::SColl(SType::SByte.into()),
×
126
                v: Literal::Coll(CollKind::from_collection(SType::SByte, iter)?),
×
127
            }),
128
            Some(tpe) => Ok(Constant {
4✔
129
                tpe: SType::SColl(tpe.clone().into()),
4✔
130
                v: Literal::Coll(CollKind::from_collection(tpe, iter)?),
4✔
131
            }),
132
        }
133
    }
134
}
135

136
impl core::fmt::Debug for Constant {
137
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
3✔
138
        format!("{:?}: {:?}", self.v, self.tpe).fmt(f)
9✔
139
    }
140
}
141

142
impl core::fmt::Display for Constant {
143
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
×
144
        self.v.fmt(f)
×
145
    }
146
}
147

148
impl core::fmt::Debug for Literal {
149
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
5✔
150
        match self {
6✔
151
            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
1✔
152
                base16::encode_lower(&i8_bytes.as_vec_u8()).fmt(f)
3✔
153
            }
154
            Literal::Coll(CollKind::WrappedColl { elem_tpe: _, items }) => items.fmt(f),
1✔
155
            Literal::Opt(boxed_opt) => boxed_opt.fmt(f),
×
156
            Literal::Tup(items) => items.fmt(f),
1✔
157
            Literal::Unit => ().fmt(f),
×
158
            Literal::Boolean(v) => v.fmt(f),
3✔
159
            Literal::Byte(v) => v.fmt(f),
1✔
160
            Literal::Short(v) => v.fmt(f),
1✔
161
            Literal::Int(v) => v.fmt(f),
4✔
162
            Literal::Long(v) => v.fmt(f),
2✔
163
            Literal::BigInt(v) => v.fmt(f),
1✔
164
            Literal::SigmaProp(v) => v.fmt(f),
1✔
165
            Literal::GroupElement(v) => v.fmt(f),
1✔
166
            Literal::UnsignedBigInt(v) => v.fmt(f),
×
167
            Literal::AvlTree(v) => v.fmt(f),
×
168
            Literal::CBox(v) => v.fmt(f),
×
169
            Literal::String(v) => v.fmt(f),
×
170
        }
171
    }
172
}
173

174
impl core::fmt::Display for Literal {
175
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
×
176
        match self {
×
177
            Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(i8_bytes))) => {
×
178
                write!(f, "Coll[Byte](")?;
×
179
                for (i, b) in i8_bytes.iter().enumerate() {
×
180
                    if i > 0 {
×
181
                        write!(f, ", ")?;
×
182
                    }
183
                    write!(f, "{}", b)?;
×
184
                }
185
                write!(f, ")")
×
186
            }
187
            Literal::Coll(CollKind::WrappedColl { elem_tpe, items }) => {
×
188
                write!(f, "Coll[{}](", elem_tpe)?;
×
189
                for (i, item) in items.iter().enumerate() {
×
190
                    if i > 0 {
×
191
                        write!(f, ", ")?;
×
192
                    }
193
                    item.fmt(f)?;
×
194
                }
195
                write!(f, ")")
×
196
            }
197
            Literal::Opt(boxed_opt) => {
×
198
                if let Some(v) = boxed_opt {
×
199
                    write!(f, "Some(")?;
×
200
                    v.fmt(f)?;
×
201
                    write!(f, ")")
×
202
                } else {
203
                    write!(f, "None")
×
204
                }
205
            }
206
            Literal::Tup(items) => {
×
207
                write!(f, "(")?;
×
208
                for (i, item) in items.iter().enumerate() {
×
209
                    if i > 0 {
×
210
                        write!(f, ", ")?;
×
211
                    }
212
                    item.fmt(f)?;
×
213
                }
214
                write!(f, ")")
×
215
            }
216
            Literal::Unit => write!(f, "()"),
×
217
            Literal::Boolean(v) => v.fmt(f),
×
218
            Literal::Byte(v) => v.fmt(f),
×
219
            Literal::Short(v) => v.fmt(f),
×
220
            Literal::Int(v) => v.fmt(f),
×
221
            Literal::Long(v) => write!(f, "{}L", v),
×
222
            Literal::BigInt(v) => v.fmt(f),
×
223
            Literal::SigmaProp(v) => v.fmt(f),
×
224
            Literal::UnsignedBigInt(v) => v.fmt(f),
×
225
            Literal::GroupElement(v) => v.fmt(f),
×
226
            Literal::AvlTree(v) => write!(f, "AvlTree({:?})", v),
×
227
            Literal::CBox(v) => write!(f, "ErgoBox({:?})", v),
×
228
            Literal::String(v) => write!(f, "String({v})"),
×
229
        }
230
    }
231
}
232

233
impl From<()> for Literal {
234
    fn from(_: ()) -> Literal {
×
235
        Literal::Unit
×
236
    }
237
}
238

239
impl From<bool> for Literal {
240
    fn from(v: bool) -> Literal {
5✔
241
        Literal::Boolean(v)
5✔
242
    }
243
}
244

245
impl From<i8> for Literal {
246
    fn from(v: i8) -> Literal {
5✔
247
        Literal::Byte(v)
5✔
248
    }
249
}
250

251
impl From<i16> for Literal {
252
    fn from(v: i16) -> Literal {
7✔
253
        Literal::Short(v)
7✔
254
    }
255
}
256

257
impl From<i32> for Literal {
258
    fn from(v: i32) -> Literal {
6✔
259
        Literal::Int(v)
6✔
260
    }
261
}
262

263
impl From<i64> for Literal {
264
    fn from(v: i64) -> Literal {
8✔
265
        Literal::Long(v)
8✔
266
    }
267
}
268

269
impl From<BigInt256> for Literal {
270
    fn from(v: BigInt256) -> Literal {
×
271
        Literal::BigInt(v)
×
272
    }
273
}
274

275
impl From<SigmaProp> for Literal {
276
    fn from(v: SigmaProp) -> Literal {
5✔
277
        Literal::SigmaProp(Box::new(v))
7✔
278
    }
279
}
280

281
impl From<UnsignedBigInt> for Literal {
282
    fn from(v: UnsignedBigInt) -> Literal {
3✔
283
        Literal::UnsignedBigInt(v)
3✔
284
    }
285
}
286

287
impl From<EcPoint> for Literal {
288
    fn from(v: EcPoint) -> Literal {
5✔
289
        Literal::GroupElement(Arc::new(v))
5✔
290
    }
291
}
292

293
impl From<Ref<'_, EcPoint>> for Literal {
294
    fn from(value: Ref<'_, EcPoint>) -> Self {
1✔
295
        Literal::GroupElement(value.to_arc())
2✔
296
    }
297
}
298

299
impl From<Ref<'static, ErgoBox>> for Literal {
300
    fn from(b: Ref<'static, ErgoBox>) -> Self {
×
301
        Literal::CBox(b)
×
302
    }
303
}
304

305
impl From<ErgoBox> for Literal {
306
    fn from(b: ErgoBox) -> Self {
×
307
        Literal::CBox(Arc::new(b).into())
×
308
    }
309
}
310

311
impl From<Vec<u8>> for Literal {
312
    fn from(v: Vec<u8>) -> Self {
3✔
313
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
3✔
314
            v.as_vec_i8().into(),
6✔
315
        ))) // TODO: optimize
316
    }
317
}
318

319
impl From<Digest32> for Literal {
320
    fn from(v: Digest32) -> Self {
1✔
321
        let bytes: Vec<u8> = v.into();
1✔
322
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
1✔
323
            bytes.as_vec_i8().into(), // TODO: optimize
2✔
324
        )))
325
    }
326
}
327

328
impl From<TokenId> for Literal {
329
    fn from(v: TokenId) -> Self {
×
330
        Digest32::from(v).into()
×
331
    }
332
}
333

334
impl From<Vec<i8>> for Literal {
335
    fn from(v: Vec<i8>) -> Self {
5✔
336
        Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(v.into()))) // TODO
5✔
337
    }
338
}
339

340
impl<T: LiftIntoSType + StoreWrapped + Into<Literal>> From<Vec<T>> for Literal {
341
    fn from(v: Vec<T>) -> Self {
3✔
342
        Literal::Coll(CollKind::WrappedColl {
6✔
343
            elem_tpe: T::stype(),
3✔
344
            items: v.into_iter().map(|i| i.into()).collect(),
12✔
345
        })
346
    }
347
}
348

349
impl<T: LiftIntoSType + Into<Literal>> From<Option<T>> for Literal {
350
    fn from(opt: Option<T>) -> Self {
×
351
        Literal::Opt(opt.map(|e| e.into()).map(Box::new))
×
352
    }
353
}
354

355
impl<'ctx> TryFrom<Value<'ctx>> for Constant {
356
    type Error = String;
357
    #[allow(clippy::unwrap_used)]
358
    fn try_from(value: Value<'ctx>) -> Result<Self, Self::Error> {
2✔
359
        match value {
2✔
360
            Value::Boolean(b) => Ok(Constant::from(b)),
2✔
361
            Value::Byte(b) => Ok(Constant::from(b)),
2✔
362
            Value::Short(s) => Ok(Constant::from(s)),
2✔
363
            Value::Int(i) => Ok(Constant::from(i)),
2✔
364
            Value::Long(l) => Ok(Constant::from(l)),
2✔
365
            Value::BigInt(b) => Ok(Constant::from(b)),
2✔
366
            Value::Unit => Ok(Constant {
×
367
                tpe: SType::SUnit,
×
368
                v: Literal::Unit,
×
369
            }),
370
            Value::SigmaProp(s) => Ok(Constant::from(*s)),
2✔
371
            Value::UnsignedBigInt(b) => Ok(Constant::from(b)),
2✔
372
            Value::GroupElement(e) => Ok(Constant::from(e)),
2✔
373
            Value::CBox(i) => Ok(Constant::from(i.to_static())),
×
374
            Value::Coll(coll) => {
1✔
375
                let (v, tpe) = match coll {
2✔
376
                    CollKind::NativeColl(n) => (
2✔
377
                        Literal::Coll(CollKind::NativeColl(n)),
1✔
378
                        SType::SColl(Arc::new(SType::SByte)),
2✔
379
                    ),
380
                    CollKind::WrappedColl { elem_tpe, items } => {
1✔
381
                        let new_items = items
2✔
382
                            .iter()
383
                            .map(|v| Ok(Constant::try_from(v.clone())?.v))
2✔
384
                            .collect::<Result<Arc<[_]>, String>>()?;
385

386
                        (
387
                            Literal::Coll(CollKind::WrappedColl {
1✔
388
                                elem_tpe: elem_tpe.clone(),
1✔
389
                                items: new_items,
1✔
390
                            }),
391
                            SType::SColl(Arc::new(elem_tpe)),
2✔
392
                        )
393
                    }
394
                };
395
                Ok(Constant { v, tpe })
1✔
396
            }
397
            Value::Opt(lit) => match lit {
×
398
                Some(v) => {
×
399
                    let c = Constant::try_from((*v).clone())?;
×
400
                    Ok(Constant {
×
401
                        v: Literal::Opt(Some(Box::new(c.v))),
×
402
                        tpe: c.tpe,
×
403
                    })
404
                }
405
                None => Err("Can't convert from Value::Opt(None) to Constant".into()),
×
406
            },
407
            Value::Tup(t) => {
1✔
408
                if let Ok(t) = t.try_mapped::<_, _, String>(|v| {
3✔
409
                    let c = Constant::try_from(v)?;
1✔
410
                    Ok((c.v, c.tpe))
1✔
411
                }) {
412
                    let tuple_items = t.mapped_ref(|(l, _)| l.clone());
3✔
413
                    let tuple_item_types = SType::STuple(STuple {
1✔
414
                        items: t.mapped(|(_, tpe)| tpe),
3✔
415
                    });
416
                    Ok(Constant {
1✔
417
                        v: Literal::Tup(tuple_items),
1✔
418
                        tpe: tuple_item_types,
×
419
                    })
420
                } else {
421
                    Err("Can't convert Value:Tup element".into())
×
422
                }
423
            }
424
            Value::AvlTree(a) => Ok(Constant::from(*a)),
×
425
            Value::String(s) => Ok(Constant::from(s)),
×
426
            Value::Context => Err("Cannot convert Value::Context into Constant".into()),
×
427
            Value::Header(_) => Err("Cannot convert Value::Header(_) into Constant".into()),
×
428
            Value::PreHeader(_) => Err("Cannot convert Value::PreHeader(_) into Constant".into()),
×
429
            Value::Global => Err("Cannot convert Value::Global into Constant".into()),
×
430
            Value::Lambda(_) => Err("Cannot convert Value::Lambda(_) into Constant".into()),
×
431
        }
432
    }
433
}
434

435
impl From<()> for Constant {
436
    fn from(_: ()) -> Self {
1✔
437
        Constant {
438
            tpe: SType::SUnit,
439
            v: Literal::Unit,
440
        }
441
    }
442
}
443

444
impl From<bool> for Constant {
445
    fn from(v: bool) -> Self {
5✔
446
        Constant {
447
            tpe: bool::stype(),
5✔
448
            v: v.into(),
5✔
449
        }
450
    }
451
}
452

453
impl From<i8> for Constant {
454
    fn from(v: i8) -> Self {
5✔
455
        Constant {
456
            tpe: i8::stype(),
5✔
457
            v: v.into(),
5✔
458
        }
459
    }
460
}
461

462
impl From<i16> for Constant {
463
    fn from(v: i16) -> Self {
5✔
464
        Constant {
465
            tpe: i16::stype(),
5✔
466
            v: v.into(),
7✔
467
        }
468
    }
469
}
470

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

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

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

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

507
impl From<EcPoint> for Constant {
508
    fn from(v: EcPoint) -> Constant {
5✔
509
        Constant {
510
            tpe: SType::SGroupElement,
511
            v: v.into(),
5✔
512
        }
513
    }
514
}
515

516
impl From<Ref<'_, EcPoint>> for Constant {
517
    fn from(v: Ref<'_, EcPoint>) -> Self {
1✔
518
        Constant {
519
            tpe: SType::SGroupElement,
520
            v: v.into(),
1✔
521
        }
522
    }
523
}
524

525
impl From<&'static ErgoBox> for Constant {
526
    fn from(b: &'static ErgoBox) -> Self {
×
527
        Constant {
528
            tpe: SType::SBox,
529
            v: Literal::CBox(Ref::Borrowed(b)),
×
530
        }
531
    }
532
}
533

534
impl From<ErgoBox> for Constant {
535
    fn from(b: ErgoBox) -> Self {
1✔
536
        Constant {
537
            tpe: SType::SBox,
538
            v: Literal::CBox(Arc::new(b).into()),
2✔
539
        }
540
    }
541
}
542

543
impl From<Ref<'static, ErgoBox>> for Constant {
544
    fn from(b: Ref<'static, ErgoBox>) -> Self {
×
545
        Constant {
546
            tpe: SType::SBox,
547
            v: Literal::CBox(b),
×
548
        }
549
    }
550
}
551

552
impl From<Vec<u8>> for Constant {
553
    fn from(v: Vec<u8>) -> Self {
3✔
554
        Constant {
555
            tpe: SType::SColl(Arc::new(SType::SByte)),
6✔
556
            v: v.into(),
3✔
557
        }
558
    }
559
}
560

561
impl From<Digest32> for Constant {
562
    fn from(v: Digest32) -> Self {
1✔
563
        Constant {
564
            tpe: SType::SColl(Arc::new(SType::SByte)),
1✔
565
            v: v.into(),
1✔
566
        }
567
    }
568
}
569

570
impl From<TokenId> for Constant {
571
    fn from(v: TokenId) -> Self {
1✔
572
        Digest32::from(v).into()
1✔
573
    }
574
}
575

576
impl From<Vec<i8>> for Constant {
577
    fn from(v: Vec<i8>) -> Self {
5✔
578
        Constant {
579
            tpe: SType::SColl(Arc::new(SType::SByte)),
10✔
580
            v: v.into(),
5✔
581
        }
582
    }
583
}
584

585
impl<T: LiftIntoSType + StoreWrapped + Into<Constant>> From<Vec<T>> for Constant {
586
    fn from(v: Vec<T>) -> Self {
14✔
587
        Constant {
588
            tpe: Vec::<T>::stype(),
14✔
589
            v: Literal::Coll(CollKind::WrappedColl {
14✔
590
                elem_tpe: T::stype(),
591
                items: v.into_iter().map(|i| i.into().v).collect(),
592
            }),
593
        }
594
    }
595
}
596

597
impl<T: LiftIntoSType + Into<Constant>> From<Option<T>> for Constant {
598
    fn from(opt: Option<T>) -> Self {
6✔
599
        Constant {
600
            tpe: SType::SOption(Arc::new(T::stype())),
13✔
601
            v: Literal::Opt(opt.map(|e| e.into().v).map(Box::new)),
28✔
602
        }
603
    }
604
}
605

606
impl From<ProveDlog> for Constant {
607
    fn from(v: ProveDlog) -> Self {
7✔
608
        Constant::from(SigmaProp::from(SigmaBoolean::from(
7✔
609
            SigmaProofOfKnowledgeTree::from(v),
6✔
610
        )))
611
    }
612
}
613

614
impl From<ProveDhTuple> for Constant {
615
    fn from(dht: ProveDhTuple) -> Self {
3✔
616
        Constant::from(SigmaProp::from(SigmaBoolean::from(
3✔
617
            SigmaProofOfKnowledgeTree::from(dht),
3✔
618
        )))
619
    }
620
}
621

622
impl From<SigmaBoolean> for Constant {
623
    fn from(sb: SigmaBoolean) -> Self {
1✔
624
        Constant::from(SigmaProp::from(sb))
1✔
625
    }
626
}
627

628
impl From<BigInt256> for Constant {
629
    fn from(b: BigInt256) -> Self {
5✔
630
        Constant {
631
            tpe: SType::SBigInt,
632
            v: Literal::BigInt(b),
5✔
633
        }
634
    }
635
}
636

637
impl From<AvlTreeData> for Constant {
638
    fn from(a: AvlTreeData) -> Self {
2✔
639
        Constant {
640
            tpe: SType::SAvlTree,
641
            v: Literal::AvlTree(Box::new(a)),
2✔
642
        }
643
    }
644
}
645

646
impl From<AvlTreeFlags> for Constant {
647
    fn from(a: AvlTreeFlags) -> Self {
1✔
648
        Constant {
649
            tpe: SType::SByte,
650
            v: Literal::Byte(a.serialize() as i8),
2✔
651
        }
652
    }
653
}
654

655
impl From<ADDigest> for Constant {
656
    fn from(a: ADDigest) -> Self {
1✔
657
        Constant {
658
            tpe: SType::SColl(Arc::new(SType::SByte)),
1✔
659
            v: Literal::Coll(CollKind::NativeColl(NativeColl::CollByte(
1✔
660
                a.0.iter().map(|&i| i as i8).collect(),
661
            ))),
662
        }
663
    }
664
}
665

666
impl From<Arc<str>> for Constant {
667
    fn from(s: Arc<str>) -> Self {
×
668
        Constant {
669
            tpe: SType::SString,
670
            v: Literal::String(s),
×
671
        }
672
    }
673
}
674

675
impl From<String> for Constant {
676
    fn from(s: String) -> Self {
1✔
677
        Constant {
678
            tpe: SType::SString,
679
            v: Literal::String(s.into()),
2✔
680
        }
681
    }
682
}
683

684
#[allow(clippy::unwrap_used)]
685
#[allow(clippy::from_over_into)]
686
#[impl_for_tuples(2, 4)]
687
impl Into<Constant> for Tuple {
688
    fn into(self) -> Constant {
6✔
689
        let constants: Vec<Constant> = [for_tuples!(  #( Tuple.into() ),* )].to_vec();
6✔
690
        let (types, values): (Vec<SType>, Vec<Literal>) =
18✔
691
            constants.into_iter().map(|c| (c.tpe, c.v)).unzip();
692
        Constant {
693
            tpe: SType::STuple(types.try_into().unwrap()),
13✔
694
            v: Literal::Tup(values.try_into().unwrap()),
14✔
695
        }
696
    }
697
}
698

699
/// Extract value wrapped in a type
700
pub trait TryExtractInto<F> {
701
    /// Extract value of the given type from any type (e.g. ['Constant'], [`super::value::Value`])
702
    /// on which [`TryExtractFrom`] is implemented
703
    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError>;
704
}
705

706
impl<F> TryExtractInto<F> for F {
707
    fn try_extract_into<T: TryExtractFrom<F>>(self) -> Result<T, TryExtractFromError> {
77✔
708
        T::try_extract_from(self)
77✔
709
    }
710
}
711

712
/// Underlying type is different from requested value type
713
#[derive(Error, PartialEq, Eq, Debug, Clone)]
714
#[error("Failed TryExtractFrom: {0}")]
715
pub struct TryExtractFromError(pub String);
716

717
/// Extract underlying value if type matches
718
pub trait TryExtractFrom<T>: Sized {
719
    /// Extract the value or return an error if type does not match
720
    fn try_extract_from(v: T) -> Result<Self, TryExtractFromError>;
721
}
722

723
impl<T: TryExtractFrom<Literal>> TryExtractFrom<Constant> for T {
724
    fn try_extract_from(cv: Constant) -> Result<Self, TryExtractFromError> {
28✔
725
        T::try_extract_from(cv.v)
28✔
726
    }
727
}
728

729
impl TryExtractFrom<Literal> for () {
730
    fn try_extract_from(cv: Literal) -> Result<(), TryExtractFromError> {
1✔
731
        match cv {
1✔
732
            Literal::Unit => Ok(()),
1✔
733
            _ => Err(TryExtractFromError(format!(
×
734
                "expected Unit, found {:?}",
735
                cv
736
            ))),
737
        }
738
    }
739
}
740

741
impl TryExtractFrom<Literal> for bool {
742
    fn try_extract_from(cv: Literal) -> Result<bool, TryExtractFromError> {
5✔
743
        match cv {
5✔
744
            Literal::Boolean(v) => Ok(v),
5✔
745
            _ => Err(TryExtractFromError(format!(
×
746
                "expected bool, found {:?}",
747
                cv
748
            ))),
749
        }
750
    }
751
}
752

753
impl TryExtractFrom<Literal> for i8 {
754
    fn try_extract_from(cv: Literal) -> Result<i8, TryExtractFromError> {
6✔
755
        match cv {
6✔
756
            Literal::Byte(v) => Ok(v),
6✔
757
            _ => Err(TryExtractFromError(format!("expected i8, found {:?}", cv))),
×
758
        }
759
    }
760
}
761

762
impl TryExtractFrom<Literal> for i16 {
763
    fn try_extract_from(cv: Literal) -> Result<i16, TryExtractFromError> {
1✔
764
        match cv {
1✔
765
            Literal::Short(v) => Ok(v),
1✔
766
            _ => Err(TryExtractFromError(format!("expected i16, found {:?}", cv))),
×
767
        }
768
    }
769
}
770

771
impl TryExtractFrom<Literal> for i32 {
772
    fn try_extract_from(cv: Literal) -> Result<i32, TryExtractFromError> {
1✔
773
        match cv {
1✔
774
            Literal::Int(v) => Ok(v),
1✔
775
            _ => Err(TryExtractFromError(format!("expected i32, found {:?}", cv))),
×
776
        }
777
    }
778
}
779

780
impl TryExtractFrom<Literal> for i64 {
781
    fn try_extract_from(cv: Literal) -> Result<i64, TryExtractFromError> {
1✔
782
        match cv {
1✔
783
            Literal::Long(v) => Ok(v),
1✔
784
            _ => Err(TryExtractFromError(format!("expected i64, found {:?}", cv))),
×
785
        }
786
    }
787
}
788

789
impl TryExtractFrom<Literal> for EcPoint {
790
    fn try_extract_from(cv: Literal) -> Result<EcPoint, TryExtractFromError> {
1✔
791
        match cv {
1✔
792
            Literal::GroupElement(v) => Ok((*v).clone()),
1✔
793
            _ => Err(TryExtractFromError(format!(
×
794
                "expected EcPoint, found {:?}",
795
                cv
796
            ))),
797
        }
798
    }
799
}
800

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

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

825
impl TryExtractFrom<Literal> for Ref<'static, ErgoBox> {
826
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
×
827
        match c {
×
828
            Literal::CBox(b) => Ok(b),
×
829
            _ => Err(TryExtractFromError(format!(
×
830
                "expected ErgoBox, found {:?}",
831
                c
832
            ))),
833
        }
834
    }
835
}
836

837
impl TryExtractFrom<Literal> for ErgoBox {
838
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
×
839
        match c {
×
840
            Literal::CBox(b) => Ok((*b).clone()),
×
841
            _ => Err(TryExtractFromError(format!(
×
842
                "expected ErgoBox, found {:?}",
843
                c
844
            ))),
845
        }
846
    }
847
}
848

849
impl<T: TryExtractFrom<Literal> + StoreWrapped> TryExtractFrom<Literal> for Vec<T> {
850
    fn try_extract_from(c: Literal) -> Result<Self, TryExtractFromError> {
7✔
851
        match c {
7✔
852
            Literal::Coll(coll) => match coll {
7✔
853
                CollKind::WrappedColl {
7✔
854
                    elem_tpe: _,
×
855
                    items: v,
×
856
                } => v.iter().cloned().map(T::try_extract_from).collect(),
×
857
                _ => Err(TryExtractFromError(format!(
×
858
                    "expected {:?}, found {:?}",
×
859
                    core::any::type_name::<Self>(),
×
860
                    coll
×
861
                ))),
862
            },
863
            _ => Err(TryExtractFromError(format!(
×
864
                "expected {:?}, found {:?}",
×
865
                core::any::type_name::<Self>(),
×
866
                c
×
867
            ))),
868
        }
869
    }
870
}
871

872
impl TryExtractFrom<Literal> for Vec<i8> {
873
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
874
        match v {
2✔
875
            Literal::Coll(v) => match v {
2✔
876
                CollKind::NativeColl(NativeColl::CollByte(bs)) => Ok(bs.iter().copied().collect()), // TODO: optimize
2✔
877
                _ => Err(TryExtractFromError(format!(
×
878
                    "expected {:?}, found {:?}",
879
                    core::any::type_name::<Self>(),
×
880
                    v
881
                ))),
882
            },
883
            _ => Err(TryExtractFromError(format!(
2✔
884
                "expected {:?}, found {:?}",
885
                core::any::type_name::<Self>(),
2✔
886
                v
887
            ))),
888
        }
889
    }
890
}
891

892
impl TryExtractFrom<Literal> for Vec<u8> {
893
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
894
        use sigma_util::FromVecI8;
895
        Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)
2✔
896
    }
897
}
898

899
impl TryExtractFrom<Literal> for Digest32 {
900
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
901
        use sigma_util::FromVecI8;
902
        let bytes = Vec::<i8>::try_extract_from(v).map(Vec::<u8>::from_vec_i8)?;
1✔
903
        Digest32::try_from(bytes).map_err(|e| {
2✔
904
            TryExtractFromError(format!("failed to extract Digest32 with error: {:?}", e))
×
905
        })
906
    }
907
}
908

909
impl TryExtractFrom<Literal> for TokenId {
910
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
911
        Digest32::try_extract_from(v).map(Into::into)
1✔
912
    }
913
}
914

915
impl TryExtractFrom<Literal> for Literal {
916
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
×
917
        Ok(v)
×
918
    }
919
}
920

921
impl TryExtractFrom<Literal> for BigInt256 {
922
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
923
        match v {
1✔
924
            Literal::BigInt(bi) => Ok(bi),
1✔
925
            _ => Err(TryExtractFromError(format!(
×
926
                "expected {:?}, found {:?}",
927
                core::any::type_name::<Self>(),
×
928
                v
929
            ))),
930
        }
931
    }
932
}
933

934
impl TryExtractFrom<Literal> for String {
935
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
1✔
936
        match v {
1✔
937
            Literal::String(s) => Ok(String::from(&*s)),
1✔
938
            _ => Err(TryExtractFromError(format!(
×
939
                "expected {:?}, found {:?}",
940
                core::any::type_name::<Self>(),
×
941
                v
942
            ))),
943
        }
944
    }
945
}
946

947
impl TryExtractFrom<Literal> for AvlTreeData {
948
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
×
949
        match v {
×
950
            Literal::AvlTree(a) => Ok(*a),
×
951
            _ => Err(TryExtractFromError(format!(
×
952
                "expected {:?}, found {:?}",
953
                core::any::type_name::<Self>(),
×
954
                v
955
            ))),
956
        }
957
    }
958
}
959

960
impl<T: TryExtractFrom<Literal>> TryExtractFrom<Literal> for Option<T> {
961
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
4✔
962
        match v {
4✔
963
            Literal::Opt(opt) => opt.map(|boxed| *boxed).map(T::try_extract_from).transpose(),
16✔
964
            _ => Err(TryExtractFromError(format!(
×
965
                "expected Option, found {:?}",
×
966
                v
×
967
            ))),
968
        }
969
    }
970
}
971

972
#[impl_for_tuples(2, 4)]
973
impl TryExtractFrom<Literal> for Tuple {
974
    fn try_extract_from(v: Literal) -> Result<Self, TryExtractFromError> {
2✔
975
        match v {
2✔
976
            Literal::Tup(items) => {
2✔
977
                let mut iter = items.iter();
4✔
978
                Ok(for_tuples!( ( #(
3✔
979
                                Tuple::try_extract_from(
980
                                    iter
6✔
981
                                        .next()
982
                                        .cloned()
983
                                        .ok_or_else(|| TryExtractFromError("not enough items in STuple".to_string()))?
×
984
                                )?
985
                                ),* ) ))
×
986
            }
987
            _ => Err(TryExtractFromError(format!(
×
988
                "expected Context, found {:?}",
989
                v
990
            ))),
991
        }
992
    }
993
}
994

995
impl TryFrom<Literal> for ProveDlog {
996
    type Error = TryExtractFromError;
997
    fn try_from(cv: Literal) -> Result<Self, Self::Error> {
2✔
998
        match cv {
2✔
999
            Literal::SigmaProp(sp) => match sp.value() {
4✔
1000
                SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(
2✔
1001
                    prove_dlog,
1002
                )) => Ok(prove_dlog.clone()),
1003
                _ => Err(TryExtractFromError(format!(
×
1004
                    "expected ProveDlog, found {:?}",
1005
                    sp
1006
                ))),
1007
            },
1008
            _ => Err(TryExtractFromError(format!(
×
1009
                "expected SigmaProp, found {:?}",
1010
                cv
1011
            ))),
1012
        }
1013
    }
1014
}
1015

1016
impl Base16Str for &Constant {
1017
    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
×
1018
        self.sigma_serialize_bytes()
×
1019
            .map(|bytes| base16::encode_lower(&bytes))
×
1020
    }
1021
}
1022

1023
impl Base16Str for Constant {
1024
    fn base16_str(&self) -> Result<String, SigmaSerializationError> {
1✔
1025
        self.sigma_serialize_bytes()
1✔
1026
            .map(|bytes| base16::encode_lower(&bytes))
2✔
1027
    }
1028
}
1029

1030
impl TryFrom<Base16DecodedBytes> for Constant {
1031
    type Error = SigmaParsingError;
1032

1033
    fn try_from(value: Base16DecodedBytes) -> Result<Self, Self::Error> {
×
1034
        Constant::sigma_parse_bytes(&value.0)
×
1035
    }
1036
}
1037

1038
#[cfg(feature = "arbitrary")]
1039
#[allow(clippy::unwrap_used)]
1040
#[allow(clippy::todo)]
1041
/// Arbitrary impl
1042
pub(crate) mod arbitrary {
1043
    use core::convert::TryFrom;
1044

1045
    use super::*;
1046
    use crate::mir::value::CollKind;
1047
    use crate::types::stuple::STuple;
1048
    use proptest::collection::vec;
1049
    use proptest::prelude::*;
1050

1051
    extern crate derive_more;
1052
    use derive_more::From;
1053
    use derive_more::TryInto;
1054

1055
    fn primitive_type_value() -> BoxedStrategy<Constant> {
8✔
1056
        prop_oneof![
59✔
1057
            any::<bool>().prop_map_into(),
5✔
1058
            any::<i8>().prop_map_into(),
13✔
1059
            any::<i16>().prop_map_into(),
13✔
1060
            any::<i32>().prop_map_into(),
13✔
1061
            any::<i64>().prop_map_into(),
13✔
1062
            any::<i64>().prop_map(|v| BigInt256::from(v).into()),
23✔
1063
            any::<EcPoint>().prop_map_into(),
13✔
1064
            any::<SigmaProp>().prop_map_into(),
13✔
1065
            // although it's not strictly a primitive type, byte array is widely used as one
1066
            vec(any::<i8>(), 0..100).prop_map_into(),
13✔
1067
        ]
1068
        .boxed()
1069
    }
1070

1071
    fn coll_from_constant(c: Constant, length: usize) -> Constant {
5✔
1072
        Constant {
1073
            tpe: SType::SColl(Arc::new(c.tpe.clone())),
10✔
1074
            v: Literal::Coll(if c.tpe == SType::SByte {
24✔
1075
                let mut values: Vec<i8> = Vec::with_capacity(length);
1076
                let byte: i8 = c.v.try_extract_into().unwrap();
1077
                for _ in 0..length {
1078
                    values.push(byte);
1079
                }
1080
                CollKind::NativeColl(NativeColl::CollByte(values.into())) // TODO: optimize
1081
            } else {
1082
                let mut values: Vec<Literal> = Vec::with_capacity(length);
1083
                for _ in 0..length {
1084
                    values.push(c.v.clone());
1085
                }
1086
                CollKind::WrappedColl {
1087
                    elem_tpe: c.tpe,
1088
                    items: values.into(),
1089
                }
1090
            }),
1091
        }
1092
    }
1093

1094
    fn const_with_type(tpe: SType) -> BoxedStrategy<Constant> {
11✔
1095
        match tpe {
11✔
1096
            SType::SAny => any::<Constant>(),
4✔
1097
            SType::SBoolean => any::<bool>().prop_map_into().boxed(),
4✔
1098
            SType::SByte => any::<i8>().prop_map_into().boxed(),
2✔
1099
            SType::SShort => any::<i16>().prop_map_into().boxed(),
2✔
1100
            SType::SInt => any::<i32>().prop_map_into().boxed(),
2✔
1101
            SType::SLong => any::<i64>().prop_map_into().boxed(),
2✔
1102
            SType::SBigInt => any::<i64>().prop_map(|v| BigInt256::from(v).into()).boxed(),
4✔
1103
            SType::SGroupElement => any::<EcPoint>().prop_map_into().boxed(),
2✔
1104
            SType::SSigmaProp => any::<SigmaProp>().prop_map_into().boxed(),
21✔
1105
            SType::SBox => any::<ErgoBox>().prop_map_into().boxed(),
2✔
1106
            SType::SAvlTree => any::<AvlTreeData>().prop_map_into().boxed(),
2✔
1107
            // SType::SOption(tpe) =>
1108
            SType::SOption(tpe) => match *tpe {
×
1109
                SType::SBoolean => any::<Option<bool>>().prop_map_into().boxed(),
×
1110
                SType::SByte => any::<Option<i8>>().prop_map_into().boxed(),
×
1111
                SType::SShort => any::<Option<i16>>().prop_map_into().boxed(),
×
1112
                SType::SInt => any::<Option<i32>>().prop_map_into().boxed(),
×
1113
                SType::SLong => any::<Option<i64>>().prop_map_into().boxed(),
×
1114
                _ => todo!(),
1115
            },
1116
            SType::SColl(elem_tpe) => match *elem_tpe {
4✔
1117
                SType::SBoolean => vec(any::<bool>(), 0..400).prop_map_into().boxed(),
4✔
1118
                SType::SByte => vec(any::<u8>(), 0..400).prop_map_into().boxed(),
2✔
1119
                SType::SShort => vec(any::<i16>(), 0..400).prop_map_into().boxed(),
2✔
1120
                SType::SInt => vec(any::<i32>(), 0..400).prop_map_into().boxed(),
2✔
UNCOV
1121
                SType::SLong => vec(any::<i64>(), 0..400).prop_map_into().boxed(),
×
1122
                SType::SSigmaProp => vec(any::<SigmaProp>(), 0..3).prop_map_into().boxed(),
×
1123
                _ => todo!(),
1124
            },
1125
            // SType::STuple(_) => {}
1126
            _ => todo!("{0:?} not yet implemented", tpe),
1127
        }
1128
    }
1129

1130
    impl Default for ArbConstantParams {
1131
        fn default() -> Self {
8✔
1132
            ArbConstantParams::AnyWithDepth(1)
5✔
1133
        }
1134
    }
1135

1136
    /// Parameters for arbitrary Constant generation
1137
    #[derive(PartialEq, Eq, Debug, Clone, From, TryInto)]
1138
    pub enum ArbConstantParams {
1139
        /// Constant of any type with a structrure of a given depth
1140
        AnyWithDepth(u8),
1141
        /// Constant of a given type
1142
        Exact(SType),
1143
    }
1144

1145
    impl Arbitrary for Constant {
1146
        type Parameters = ArbConstantParams;
1147
        type Strategy = BoxedStrategy<Self>;
1148

1149
        fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
11✔
1150
            match args {
11✔
1151
                ArbConstantParams::AnyWithDepth(depth) => {
8✔
1152
                    prop_oneof![primitive_type_value().prop_recursive(
12✔
1153
                        depth as u32,
6✔
1154
                        16,
1155
                        8,
1156
                        |elem| {
6✔
1157
                            prop_oneof![
31✔
1158
                                // Coll[_]
1159
                                elem.clone().prop_map(|c| coll_from_constant(c, 0)),
24✔
1160
                                elem.clone().prop_map(|c| coll_from_constant(c, 1)),
24✔
1161
                                elem.clone().prop_map(|c| coll_from_constant(c, 2)),
22✔
1162
                                elem.clone().prop_map(|c| coll_from_constant(c, 10)),
24✔
1163
                                // no Option[_] since it cannot be serialized (for now)
1164
                                // // Some(v)
1165
                                // elem.clone().prop_map(|c| Constant {
1166
                                //     tpe: SType::SOption(Box::new(c.tpe)),
1167
                                //     v: Value::Opt(Box::new(Some(c.v)))
1168
                                // }),
1169
                                // // None
1170
                                // elem.prop_map(|c| Constant {
1171
                                //     tpe: SType::SOption(Box::new(c.tpe)),
1172
                                //     v: Value::Opt(Box::new(None))
1173
                                // })
1174

1175
                                // Tuple
1176
                                vec(elem, 2..=4).prop_map(|constants| Constant {
19✔
1177
                                    tpe: SType::STuple(
12✔
1178
                                        STuple::try_from(
6✔
1179
                                            constants
10✔
1180
                                                .clone()
1181
                                                .into_iter()
1182
                                                .map(|c| c.tpe)
10✔
1183
                                                .collect::<Vec<SType>>()
1184
                                        )
1185
                                        .unwrap()
1186
                                    ),
1187
                                    v: Literal::Tup(
6✔
1188
                                        constants
13✔
1189
                                            .into_iter()
1190
                                            .map(|c| c.v)
13✔
1191
                                            .collect::<Vec<Literal>>()
1192
                                            .try_into()
1193
                                            .unwrap()
1194
                                    )
1195
                                }),
1196
                            ]
1197
                        }
1198
                    )]
1199
                    .boxed()
1200
                }
1201
                ArbConstantParams::Exact(tpe) => const_with_type(tpe),
11✔
1202
            }
1203
        }
1204
    }
1205
}
1206

1207
#[allow(clippy::unwrap_used)]
1208
#[cfg(test)]
1209
#[cfg(feature = "arbitrary")]
1210
#[allow(clippy::panic)]
1211
pub mod tests {
1212
    use super::*;
1213
    use core::fmt;
1214
    use proptest::prelude::*;
1215

1216
    fn test_constant_roundtrip<T>(v: T)
1217
    where
1218
        T: TryExtractInto<T>
1219
            + TryExtractFrom<Literal>
1220
            + Into<Constant>
1221
            + fmt::Debug
1222
            + Eq
1223
            + Clone
1224
            + 'static,
1225
    {
1226
        let constant: Constant = v.clone().into();
1227
        let v_extracted: T = constant.try_extract_into::<T>().unwrap();
1228
        assert_eq!(v, v_extracted);
1229
    }
1230

1231
    #[test]
1232
    fn unit_roundtrip() {
1233
        test_constant_roundtrip(());
1234
    }
1235

1236
    // test that invalid strings don't error but are instead parsed lossily to match reference impl
1237
    #[test]
1238
    fn parse_invalid_string() {
1239
        let mut bytes = Constant::from(".".to_string())
1240
            .sigma_serialize_bytes()
1241
            .unwrap();
1242
        *bytes.last_mut().unwrap() = 0xf0;
1243
        assert_eq!(
1244
            Constant::sigma_parse_bytes(&bytes).unwrap().v,
1245
            Literal::String("�".into())
1246
        );
1247
    }
1248

1249
    #[test]
1250
    fn constant_from_iter() {
1251
        let iter1 = [
1252
            Constant::from(1i32),
1253
            Constant::from(2i32),
1254
            Constant::from(3i32),
1255
        ];
1256
        assert_eq!(
1257
            Constant::coll_from_iter(iter1, None).unwrap(),
1258
            Constant {
1259
                tpe: SType::SColl(SType::SInt.into()),
1260
                v: Literal::Coll(CollKind::WrappedColl {
1261
                    elem_tpe: SType::SInt,
1262
                    items: [
1263
                        Literal::from(1i32),
1264
                        Literal::from(2i32),
1265
                        Literal::from(3i32)
1266
                    ]
1267
                    .into()
1268
                })
1269
            }
1270
        );
1271
        assert!(Constant::coll_from_iter([], None).is_err());
1272
        assert!(Constant::coll_from_iter([], Some(SType::SBoolean)).is_ok());
1273
        // tpe mismatch
1274
        assert!(Constant::coll_from_iter(
1275
            [
1276
                Constant::from(1i32),
1277
                Constant::from(2i64),
1278
                Constant::from(3i64)
1279
            ],
1280
            None
1281
        )
1282
        .is_err());
1283
    }
1284

1285
    proptest! {
1286

1287
        #![proptest_config(ProptestConfig::with_cases(8))]
1288

1289
        #[test]
1290
        fn bool_roundtrip(v in any::<bool>()) {
1291
            test_constant_roundtrip(v);
1292
        }
1293

1294
        #[test]
1295
        fn i8_roundtrip(v in any::<i8>()) {
1296
            test_constant_roundtrip(v);
1297
        }
1298

1299
        #[test]
1300
        fn i16_roundtrip(v in any::<i16>()) {
1301
            test_constant_roundtrip(v);
1302
        }
1303

1304
        #[test]
1305
        fn i32_roundtrip(v in any::<i32>()) {
1306
            test_constant_roundtrip(v);
1307
        }
1308

1309
        #[test]
1310
        fn i64_roundtrip(v in any::<i64>()) {
1311
            test_constant_roundtrip(v);
1312
        }
1313

1314
        #[test]
1315
        fn bigint_roundtrip(raw in any::<i64>()) {
1316
            let v = BigInt256::from(raw);
1317
            test_constant_roundtrip(v);
1318
        }
1319

1320
        #[test]
1321
        fn group_element_roundtrip(v in any::<EcPoint>()) {
1322
            test_constant_roundtrip(v);
1323
        }
1324

1325
        #[test]
1326
        fn sigma_prop_roundtrip(v in any::<SigmaProp>()) {
1327
            test_constant_roundtrip(v);
1328
        }
1329

1330
        #[test]
1331
        fn unsigned_bigint_roundtrip(v in any::<UnsignedBigInt>()) {
1332
             test_constant_roundtrip(v);
1333
        }
1334

1335
        #[test]
1336
        fn vec_i8_roundtrip(v in any::<Vec<i8>>()) {
1337
            test_constant_roundtrip(v);
1338
        }
1339

1340
        #[test]
1341
        fn vec_u8_roundtrip(v in any::<Vec<u8>>()) {
1342
            // eprintln!("{:?}", Constant::from(v.clone()));
1343
            test_constant_roundtrip(v);
1344
        }
1345

1346
        #[test]
1347
        fn token_id_roundtrip(v in any::<TokenId>()) {
1348
            // eprintln!("{:?}", Constant::from(v.clone()));
1349
            test_constant_roundtrip(v);
1350
        }
1351

1352
        #[test]
1353
        fn digest32_roundtrip(v in any::<Digest32>()) {
1354
            test_constant_roundtrip(v);
1355
        }
1356

1357

1358
        #[test]
1359
        fn vec_i16_roundtrip(v in any::<Vec<i16>>()) {
1360
            test_constant_roundtrip(v);
1361
        }
1362

1363
        #[test]
1364
        fn vec_i32_roundtrip(v in any::<Vec<i32>>()) {
1365
            test_constant_roundtrip(v);
1366
        }
1367

1368
        #[test]
1369
        fn vec_i64_roundtrip(v in any::<Vec<i64>>()) {
1370
            // eprintln!("{:?}", Constant::from(v.clone()));
1371
            test_constant_roundtrip(v);
1372
        }
1373

1374
        #[test]
1375
        fn vec_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1376
            let v: Vec<BigInt256> = raw.into_iter().map(BigInt256::from).collect();
1377
            // eprintln!("{:?}", Constant::from(v.clone()));
1378
            test_constant_roundtrip(v);
1379
        }
1380

1381
        #[test]
1382
        fn vec_option_bigint_roundtrip(raw in any::<Vec<i64>>()) {
1383
            let v: Vec<Option<BigInt256>> = raw.into_iter().map(|i| Some(BigInt256::from(i))).collect();
1384
            // eprintln!("{:?}", Constant::from(v.clone()));
1385
            test_constant_roundtrip(v);
1386
        }
1387

1388
        #[test]
1389
        fn vec_sigmaprop_roundtrip(v in any::<Vec<SigmaProp>>()) {
1390
            test_constant_roundtrip(v);
1391
        }
1392

1393
        #[test]
1394
        fn option_primitive_type_roundtrip(v in any::<Option<i64>>()) {
1395
            test_constant_roundtrip(v);
1396
        }
1397

1398
        #[test]
1399
        fn option_nested_vector_type_roundtrip(v in any::<Option<Vec<(i64, bool)>>>()) {
1400
            // eprintln!("{:?}", Constant::from(v.clone()));
1401
            test_constant_roundtrip(v);
1402
        }
1403

1404
        #[test]
1405
        fn option_nested_tuple_type_roundtrip(v in any::<Option<(i64, bool)>>()) {
1406
            test_constant_roundtrip(v);
1407
        }
1408

1409

1410
        #[test]
1411
        fn tuple_primitive_types_roundtrip(v in any::<(i64, bool)>()) {
1412
            // let constant: Constant = v.into();
1413
            // eprintln!("{:?}", constant);
1414
            test_constant_roundtrip(v);
1415
        }
1416

1417
        #[test]
1418
        fn tuple_nested_types_roundtrip(v in any::<(Option<i64>, Vec<SigmaProp>)>()) {
1419
            test_constant_roundtrip(v);
1420
        }
1421

1422
        #[test]
1423
        fn string_roundtrip(v in any::<String>()) {
1424
            test_constant_roundtrip(v);
1425
        }
1426

1427
    }
1428
}
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