1use alloc::collections::BTreeMap;
25
26use aluvm::{Lib, LibId, LibSite};
27use amplify::confinement::TinyBlob;
28use indexmap::IndexMap;
29use sonic_callreq::StateName;
30use strict_encoding::StrictDumb;
31use strict_types::value::{EnumTag, StrictNum};
32use strict_types::{SemId, StrictVal, TypeSystem};
33use ultrasonic::CellAddr;
34
35use crate::{StateAtom, LIB_NAME_SONIC};
36
37#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
40#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
41#[strict_type(lib = LIB_NAME_SONIC, tags = custom, dumb = Self::Aggregated(strict_dumb!()))]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
43pub enum StateSelector {
44 #[strict_type(tag = 0)]
45 Global(
46 StateName,
47 bool,
50 ),
51 #[strict_type(tag = 1)]
52 Aggregated(StateName),
53}
54
55#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
57#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
58#[strict_type(lib = LIB_NAME_SONIC, tags = custom, dumb = Self::Some(strict_dumb!()))]
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
60pub enum Aggregator {
61 #[strict_type(tag = 0)]
63 None,
64
65 #[strict_type(tag = 1)]
69 #[cfg_attr(feature = "serde", serde(with = "serde_yaml::with::singleton_map"))]
70 Some(SubAggregator),
71
72 #[strict_type(tag = 2)]
76 #[cfg_attr(feature = "serde", serde(with = "serde_yaml::with::singleton_map"))]
79 Take(SubAggregator),
80
81 #[strict_type(tag = 3)]
85 Or(
86 #[cfg_attr(feature = "serde", serde(with = "serde_yaml::with::singleton_map"))] SubAggregator,
87 #[cfg_attr(feature = "serde", serde(with = "serde_yaml::with::singleton_map"))] SubAggregator,
88 ),
89
90 #[strict_type(tag = 0xFF)]
92 AluVM(
93 LibSite,
96 ),
97}
98
99impl Aggregator {
100 pub fn depends_on(&self) -> impl Iterator<Item = &StateName> {
103 match self {
104 Self::Some(sub) | Self::Take(sub) => sub.depends_on(),
105 Self::Or(some, other) => {
106 let mut deps = some.depends_on();
107 deps.append(&mut other.depends_on());
108 deps
109 }
110 Self::None | Self::AluVM(_) => vec![],
111 }
112 .into_iter()
113 }
114
115 pub fn aggregate<'libs>(
121 &self,
122 global: &BTreeMap<StateName, BTreeMap<CellAddr, StateAtom>>,
123 aggregated: &BTreeMap<StateName, StrictVal>,
124 libs: impl IntoIterator<Item = &'libs Lib>,
125 types: &TypeSystem,
126 ) -> Option<StrictVal> {
127 match self {
128 Self::None => Some(StrictVal::none()),
129
130 Self::Take(sub) => sub.aggregate(global, aggregated, types),
131
132 Self::Some(sub) => Some(match sub.aggregate(global, aggregated, types) {
133 Some(val) => StrictVal::some(val),
134 None => StrictVal::none(),
135 }),
136
137 Self::Or(some, other) => some
138 .aggregate(global, aggregated, types)
139 .or_else(|| other.aggregate(global, aggregated, types)),
140
141 Self::AluVM(entry) => {
142 let libs = libs
143 .into_iter()
144 .map(|lib| (lib.lib_id(), lib))
145 .collect::<IndexMap<_, _>>();
146 let mut vm = aluvm::Vm::<aluvm::isa::Instr<LibId>>::new();
147 let _status = vm.exec(*entry, &(), |id| libs.get(&id));
151 None
152 }
153 }
154 }
155}
156
157#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
159#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
160#[strict_type(lib = LIB_NAME_SONIC, tags = custom, dumb = Self::Neg(strict_dumb!()))]
161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
162pub enum SubAggregator {
163 #[strict_type(tag = 0)]
167 Const(SemId, TinyBlob),
168
169 #[strict_type(tag = 1)]
173 TheOnly(StateName),
174
175 #[strict_type(tag = 2)]
179 Copy(StateName),
180
181 #[strict_type(tag = 3)]
185 Unwrap(StateName),
186
187 #[strict_type(tag = 4)]
202 First(StateName),
203
204 #[strict_type(tag = 5)]
220 Nth(StateName, u16),
221
222 #[strict_type(tag = 6)]
237 Last(StateName),
238
239 #[strict_type(tag = 7)]
255 NthBack(StateName, u16),
256
257 #[strict_type(tag = 0x10)]
262 Neg(StateSelector),
263
264 #[strict_type(tag = 0x11)]
269 Add(StateSelector, StateSelector),
270
271 #[strict_type(tag = 0x12)]
276 Sub(StateSelector, StateSelector),
277
278 #[strict_type(tag = 0x13)]
283 Mul(StateSelector, StateSelector),
284
285 #[strict_type(tag = 0x14)]
291 Div(StateSelector, StateSelector),
292
293 #[strict_type(tag = 0x15)]
298 Rem(StateSelector, StateSelector),
299
300 #[strict_type(tag = 0x16)]
307 Exp(StateSelector, StateSelector),
308
309 #[strict_type(tag = 0x20)]
311 Count(StateName),
312
313 #[strict_type(tag = 0x21)]
315 CountUnique(StateName),
316
317 #[strict_type(tag = 0x22)]
323 SetV(StateName),
324
325 #[strict_type(tag = 0x23)]
346 MapV2U(StateName),
347
348 #[strict_type(tag = 0x24)]
369 MapV2ListU(StateName),
370
371 #[strict_type(tag = 0x25)]
392 MapV2SetU(StateName),
393
394 #[strict_type(tag = 0x30)]
401 SumUnwrap(StateName),
402
403 #[strict_type(tag = 0x31)]
411 SumOrDefault(StateName),
412
413 #[strict_type(tag = 0x32)]
420 ProdUnwrap(StateName),
421
422 #[strict_type(tag = 0x33)]
430 ProdOrDefault(StateName),
431}
432
433impl SubAggregator {
434 pub fn depends_on(&self) -> Vec<&StateName> {
437 match self {
438 Self::Neg(StateSelector::Aggregated(state))
439 | Self::Add(StateSelector::Global(_, _), StateSelector::Aggregated(state))
440 | Self::Sub(StateSelector::Global(_, _), StateSelector::Aggregated(state))
441 | Self::Mul(StateSelector::Global(_, _), StateSelector::Aggregated(state))
442 | Self::Div(StateSelector::Global(_, _), StateSelector::Aggregated(state))
443 | Self::Rem(StateSelector::Global(_, _), StateSelector::Aggregated(state))
444 | Self::Exp(StateSelector::Global(_, _), StateSelector::Aggregated(state))
445 | Self::Add(StateSelector::Aggregated(state), StateSelector::Global(_, _))
446 | Self::Sub(StateSelector::Aggregated(state), StateSelector::Global(_, _))
447 | Self::Mul(StateSelector::Aggregated(state), StateSelector::Global(_, _))
448 | Self::Div(StateSelector::Aggregated(state), StateSelector::Global(_, _))
449 | Self::Rem(StateSelector::Aggregated(state), StateSelector::Global(_, _))
450 | Self::Exp(StateSelector::Aggregated(state), StateSelector::Global(_, _)) => vec![state],
451
452 Self::Add(StateSelector::Aggregated(a), StateSelector::Aggregated(b))
453 | Self::Sub(StateSelector::Aggregated(a), StateSelector::Aggregated(b))
454 | Self::Mul(StateSelector::Aggregated(a), StateSelector::Aggregated(b))
455 | Self::Div(StateSelector::Aggregated(a), StateSelector::Aggregated(b))
456 | Self::Rem(StateSelector::Aggregated(a), StateSelector::Aggregated(b))
457 | Self::Exp(StateSelector::Aggregated(a), StateSelector::Aggregated(b)) => vec![a, b],
458
459 Self::Const(_, _)
460 | Self::TheOnly(_)
461 | Self::Count(_)
462 | Self::CountUnique(_)
463 | Self::Copy(_)
464 | Self::Unwrap(_)
465 | Self::First(_)
466 | Self::Nth(_, _)
467 | Self::Last(_)
468 | Self::NthBack(_, _)
469 | Self::Neg(_)
470 | Self::Add(_, _)
471 | Self::Sub(_, _)
472 | Self::Mul(_, _)
473 | Self::Div(_, _)
474 | Self::Rem(_, _)
475 | Self::Exp(_, _)
476 | Self::SetV(_)
477 | Self::MapV2U(_)
478 | Self::MapV2ListU(_)
479 | Self::MapV2SetU(_)
480 | Self::SumUnwrap(_)
481 | Self::SumOrDefault(_)
482 | Self::ProdUnwrap(_)
483 | Self::ProdOrDefault(_) => vec![],
484 }
485 }
486
487 pub fn aggregate(
494 &self,
495 global: &BTreeMap<StateName, BTreeMap<CellAddr, StateAtom>>,
496 aggregated: &BTreeMap<StateName, StrictVal>,
497 types: &TypeSystem,
498 ) -> Option<StrictVal> {
499 let get_u64 = |sel: &StateSelector| -> Option<u64> {
500 let state = match sel {
501 StateSelector::Global(name, first) => {
502 let map = global.get(name)?;
503 if map.len() != 1 && !*first {
504 return None;
505 }
506 let (_, atom) = map.first_key_value()?;
507 &atom.verified
508 }
509 StateSelector::Aggregated(name) => aggregated.get(name)?,
510 };
511 match state {
512 StrictVal::Number(StrictNum::Uint(val)) => Some(*val),
513 _ => None,
514 }
515 };
516
517 match self {
518 Self::Const(sem_id, val) => deserialize(*sem_id, val, types),
519
520 Self::TheOnly(name) => {
521 let state = global.get(name)?;
522 if state.len() != 1 {
523 return None;
524 }
525 Some(state.first_key_value()?.1.verified.clone())
526 }
527
528 Self::Copy(name) => aggregated.get(name).cloned(),
529
530 Self::Unwrap(name) => {
531 let state = global.get(name)?;
532 if state.len() != 1 {
533 return None;
534 }
535 let (_, atom) = state.first_key_value()?;
536 let StrictVal::Union(tag, sv) = &atom.verified else {
537 return None;
538 };
539 Some(match tag {
540 EnumTag::Name(name) if name.as_str() == "some" => sv.as_ref().clone(),
541 EnumTag::Ord(1) => sv.as_ref().clone(),
542 _ => return None,
543 })
544 }
545
546 Self::First(name) => {
547 let state = global.get(name)?;
548 Some(state.first_key_value()?.1.verified.clone())
549 }
550
551 Self::Nth(name, pos) => {
552 let state = global.get(name)?;
553 Some(state.iter().nth(*pos as usize)?.1.verified.clone())
554 }
555
556 Self::Last(name) => {
557 let state = global.get(name)?;
558 Some(state.last_key_value()?.1.verified.clone())
559 }
560
561 Self::NthBack(name, pos) => {
562 let state = global.get(name)?;
563 Some(state.iter().nth_back(*pos as usize)?.1.verified.clone())
564 }
565
566 Self::Neg(name) => {
567 let val = get_u64(name)?;
568 let neg = (val as i64).checked_neg()?;
569 Some(svnum!(neg))
570 }
571 Self::Add(a, b) => {
572 let a = get_u64(a)?;
573 let b = get_u64(b)?;
574 let sum = a.checked_add(b)?;
575 Some(svnum!(sum))
576 }
577 Self::Sub(a, b) => {
578 let a = get_u64(a)?;
579 let b = get_u64(b)?;
580 let sub = a.checked_sub(b)?;
581 Some(svnum!(sub))
582 }
583 Self::Mul(a, b) => {
584 let a = get_u64(a)?;
585 let b = get_u64(b)?;
586 let sub = a.checked_mul(b)?;
587 Some(svnum!(sub))
588 }
589 Self::Div(a, b) => {
590 let a = get_u64(a)?;
591 let b = get_u64(b)?;
592 let sub = a.checked_div(b)?;
593 Some(svnum!(sub))
594 }
595 Self::Rem(a, b) => {
596 let a = get_u64(a)?;
597 let b = get_u64(b)?;
598 let sub = a.checked_rem(b)?;
599 Some(svnum!(sub))
600 }
601 Self::Exp(a, b) => {
602 let a = get_u64(a)?;
603 let b = get_u64(b)?;
604 let sub = a.checked_pow(b.try_into().ok()?)?;
605 Some(svnum!(sub))
606 }
607
608 Self::Count(name) => {
609 let count = global
610 .get(name)
611 .into_iter()
612 .flat_map(BTreeMap::values)
613 .count();
614 Some(svnum!(count as u64))
615 }
616
617 Self::CountUnique(name) => {
618 let mut unique = Vec::new();
619 for item in global.get(name)?.values() {
620 if !unique.contains(&item) {
621 unique.push(item);
622 }
623 }
624 Some(svnum!(unique.len() as u64))
625 }
626
627 Self::SetV(name) => {
628 let mut set = Vec::new();
629 for state in global.get(name).into_iter().flat_map(BTreeMap::values) {
630 if !set.contains(&state.verified) {
631 set.push(state.verified.clone());
632 }
633 }
634 Some(StrictVal::Set(set))
635 }
636
637 Self::MapV2U(name) => {
638 let mut map = Vec::new();
639 for atom in global.get(name)?.values() {
640 let Some(val) = &atom.unverified else { continue };
641 if map.iter().any(|(key, _)| &atom.verified == key) {
642 continue;
643 }
644 map.push((atom.verified.clone(), val.clone()));
645 }
646 Some(StrictVal::Map(map))
647 }
648
649 Self::MapV2ListU(name) => {
650 let mut map = Vec::<(StrictVal, StrictVal)>::new();
651 for atom in global.get(name)?.values() {
652 let Some(val) = &atom.unverified else { continue };
653 if let Some((_key, list)) = map.iter_mut().find(|(key, _)| &atom.verified == key) {
654 let StrictVal::List(list) = list else {
655 unreachable!();
656 };
657 list.push(val.clone());
658 } else {
659 map.push((atom.verified.clone(), StrictVal::List(vec![val.clone()])));
660 }
661 }
662 Some(StrictVal::Map(map))
663 }
664
665 Self::MapV2SetU(name) => {
666 let mut map = Vec::<(StrictVal, StrictVal)>::new();
667 for atom in global.get(name)?.values() {
668 let Some(val) = &atom.unverified else { continue };
669 if let Some((_key, list)) = map.iter_mut().find(|(key, _)| &atom.verified == key) {
670 let StrictVal::Set(list) = list else {
671 unreachable!();
672 };
673 if !list.contains(val) {
674 list.push(val.clone());
675 }
676 } else {
677 map.push((atom.verified.clone(), StrictVal::Set(vec![val.clone()])));
678 }
679 }
680 Some(StrictVal::Map(map))
681 }
682
683 Self::SumUnwrap(name) => {
684 let sum = global
685 .get(name)
686 .into_iter()
687 .flat_map(BTreeMap::values)
688 .try_fold(0u64, |sum, val| match &val.verified {
689 StrictVal::Number(StrictNum::Uint(val)) => sum.checked_add(*val),
690 _ => None,
691 })?;
692 Some(svnum!(sum))
693 }
694
695 Self::SumOrDefault(name) => {
696 let sum = global
697 .get(name)
698 .into_iter()
699 .flat_map(BTreeMap::values)
700 .try_fold(0u64, |sum, val| match &val.verified {
701 StrictVal::Number(StrictNum::Uint(val)) => sum.checked_add(*val),
702 _ => Some(sum),
703 })?;
704 Some(svnum!(sum))
705 }
706
707 Self::ProdUnwrap(name) => {
708 let sum = global
709 .get(name)
710 .into_iter()
711 .flat_map(BTreeMap::values)
712 .try_fold(1u64, |prod, val| match &val.verified {
713 StrictVal::Number(StrictNum::Uint(val)) => prod.checked_mul(*val),
714 _ => None,
715 })?;
716 Some(svnum!(sum))
717 }
718
719 Self::ProdOrDefault(name) => {
720 let sum = global
721 .get(name)
722 .into_iter()
723 .flat_map(BTreeMap::values)
724 .try_fold(1u64, |prod, val| match &val.verified {
725 StrictVal::Number(StrictNum::Uint(val)) => prod.checked_mul(*val),
726 _ => Some(prod),
727 })?;
728 Some(svnum!(sum))
729 }
730 }
731 }
732}
733
734fn deserialize(sem_id: SemId, val: &TinyBlob, types: &TypeSystem) -> Option<StrictVal> {
735 let ty = types
736 .strict_deserialize_type(sem_id, val.as_slice())
737 .unwrap();
738 Some(ty.unbox())
739}
740
741#[cfg(test)]
742mod test {
743 #![cfg_attr(coverage_nightly, coverage(off))]
744
745 use aluvm::aluasm;
746 use strict_types::stl::std_stl;
747 use strict_types::SystemBuilder;
748
749 use super::*;
750
751 fn addr(no: u16) -> CellAddr { CellAddr::new(strict_dumb!(), no) }
752 fn state() -> BTreeMap<StateName, BTreeMap<CellAddr, StateAtom>> {
753 bmap! {
754 vname!("pairs") => bmap! {
755 addr(0) => StateAtom::with(5u64, "state 1"),
756 addr(1) => StateAtom::with(1u64, "state 2"),
757 addr(2) => StateAtom::with(2u64, "state 3"),
758 addr(3) => StateAtom::with(3u64, "state 4"),
759 addr(4) => StateAtom::with(4u64, "state 5"),
760 addr(5) => StateAtom::with(5u64, "state 6"),
761 },
762 vname!("verified") => bmap! {
763 addr(0) => StateAtom::new_verified(5u64),
764 addr(1) => StateAtom::new_verified(1u64),
765 addr(2) => StateAtom::new_verified(2u64),
766 addr(3) => StateAtom::new_verified(3u64),
767 addr(4) => StateAtom::new_verified(4u64),
768 addr(5) => StateAtom::new_verified(5u64),
769 },
770 vname!("unverified") => bmap! {
771 addr(0) => StateAtom::new_unverified("state 1"),
772 addr(1) => StateAtom::new_unverified("state 2"),
773 addr(2) => StateAtom::new_unverified("state 3"),
774 addr(3) => StateAtom::new_unverified("state 4"),
775 addr(4) => StateAtom::new_unverified("state 5"),
776 addr(5) => StateAtom::new_unverified("state 6"),
777 },
778 }
779 }
780 fn types() -> TypeSystem {
781 let sys = SystemBuilder::new()
782 .import(std_stl())
783 .unwrap()
784 .finalize()
785 .unwrap();
786 let types = std_stl()
787 .types
788 .into_iter()
789 .map(|(tn, ty)| ty.sem_id_named(&tn));
790 sys.as_types().extract(types).unwrap()
791 }
792 fn success_lib() -> Lib {
793 let code = aluasm! { ret; };
794 Lib::assemble(&code).unwrap()
795 }
796 fn call(aggregator: &Aggregator) -> StrictVal {
797 aggregator
798 .aggregate(&state(), &none!(), &[success_lib()], &types())
799 .unwrap()
800 }
801 fn call2(aggregator: &Aggregator) -> StrictVal {
802 let aggregated = bmap! {
803 vname!("zero") => svnum!(0u64),
804 vname!("two") => svnum!(2u64),
805 vname!("three") => svnum!(3u64),
806 vname!("str") => svstr!("Hi"),
807 };
808 aggregator
809 .aggregate(&state(), &aggregated, &[success_lib()], &types())
810 .unwrap()
811 }
812
813 #[test]
814 fn none() {
815 let agg = Aggregator::None;
816 assert_eq!(call(&agg), svnone!());
817 assert_eq!(agg.depends_on().count(), 0);
818 }
819
820 #[test]
821 fn some() {
822 let agg = Aggregator::Some(SubAggregator::Count(vname!("verified")));
823 assert_eq!(call(&agg), svsome!(6u64));
824 assert_eq!(agg.depends_on().count(), 0);
825 }
826
827 #[test]
828 fn or() {
829 let agg =
830 Aggregator::Or(SubAggregator::Unwrap(vname!("nonExisting")), SubAggregator::Count(vname!("verified")));
831 assert_eq!(call(&agg), svnum!(6u64));
832 assert_eq!(agg.depends_on().count(), 0);
833 }
834
835 #[test]
836 #[should_panic]
837 fn non_existing() { call(&Aggregator::Take(SubAggregator::Unwrap(vname!("nonExisting")))); }
838
839 #[test]
840 fn sum() {
841 #![allow(clippy::identity_op)]
842 let agg = Aggregator::Take(SubAggregator::SumUnwrap(vname!("verified")));
843 assert_eq!(call(&agg), svnum!(5u64 + 1 + 2 + 3 + 4 + 5));
844 assert_eq!(agg.depends_on().count(), 0);
845
846 let agg = Aggregator::Take(SubAggregator::SumOrDefault(vname!("verified")));
847 assert_eq!(call(&agg), svnum!(5u64 + 1 + 2 + 3 + 4 + 5));
848 assert_eq!(agg.depends_on().count(), 0);
849
850 let agg = Aggregator::Take(SubAggregator::SumOrDefault(vname!("unverified")));
851 assert_eq!(call(&agg), svnum!(0u64));
852 assert_eq!(agg.depends_on().count(), 0);
853 }
854
855 #[test]
856 fn prod() {
857 #![allow(clippy::identity_op)]
858 let agg = Aggregator::Take(SubAggregator::ProdUnwrap(vname!("verified")));
859 assert_eq!(call(&agg), svnum!(5u64 * 1 * 2 * 3 * 4 * 5));
860 assert_eq!(agg.depends_on().count(), 0);
861
862 let agg = Aggregator::Take(SubAggregator::ProdOrDefault(vname!("verified")));
863 assert_eq!(call(&agg), svnum!(5u64 * 1 * 2 * 3 * 4 * 5));
864 assert_eq!(agg.depends_on().count(), 0);
865
866 let agg = Aggregator::Take(SubAggregator::ProdOrDefault(vname!("unverified")));
867 assert_eq!(call(&agg), svnum!(1u64));
868 assert_eq!(agg.depends_on().count(), 0);
869 }
870
871 #[test]
872 fn add() {
873 let agg = Aggregator::Take(SubAggregator::Add(
874 StateSelector::Aggregated(vname!("two")),
875 StateSelector::Aggregated(vname!("three")),
876 ));
877 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two"), &vname!("three")]);
878 assert_eq!(call2(&agg), svnum!(5u64));
879 }
880
881 #[test]
882 fn meg() {
883 let agg = Aggregator::Take(SubAggregator::Neg(StateSelector::Aggregated(vname!("two"))));
884 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two")]);
885 assert_eq!(call2(&agg), svnum!(-2i64));
886 }
887
888 #[test]
889 fn sub() {
890 let agg = Aggregator::Take(SubAggregator::Sub(
891 StateSelector::Aggregated(vname!("three")),
892 StateSelector::Aggregated(vname!("two")),
893 ));
894 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("three"), &vname!("two")]);
895 assert_eq!(call2(&agg), svnum!(1u64));
896 }
897
898 #[test]
899 #[should_panic]
900 fn sub_overflow() {
901 let agg = Aggregator::Take(SubAggregator::Sub(
902 StateSelector::Aggregated(vname!("two")),
903 StateSelector::Aggregated(vname!("three")),
904 ));
905 call2(&agg);
906 }
907
908 #[test]
909 fn mul() {
910 let agg = Aggregator::Take(SubAggregator::Mul(
911 StateSelector::Aggregated(vname!("two")),
912 StateSelector::Aggregated(vname!("three")),
913 ));
914 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two"), &vname!("three")]);
915 assert_eq!(call2(&agg), svnum!(6u64));
916 }
917
918 #[test]
919 fn div() {
920 let agg = Aggregator::Take(SubAggregator::Div(
921 StateSelector::Aggregated(vname!("two")),
922 StateSelector::Aggregated(vname!("three")),
923 ));
924 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two"), &vname!("three")]);
925 assert_eq!(call2(&agg), svnum!(0u64));
926 }
927
928 #[test]
929 #[should_panic]
930 fn div_zero() {
931 let agg = Aggregator::Take(SubAggregator::Div(
932 StateSelector::Aggregated(vname!("two")),
933 StateSelector::Aggregated(vname!("zero")),
934 ));
935 call2(&agg);
936 }
937
938 #[test]
939 fn rem() {
940 let agg = Aggregator::Take(SubAggregator::Rem(
941 StateSelector::Aggregated(vname!("two")),
942 StateSelector::Aggregated(vname!("three")),
943 ));
944 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two"), &vname!("three")]);
945 assert_eq!(call2(&agg), svnum!(2u64));
946 }
947
948 #[test]
949 fn exp() {
950 let agg = Aggregator::Take(SubAggregator::Exp(
951 StateSelector::Aggregated(vname!("two")),
952 StateSelector::Aggregated(vname!("three")),
953 ));
954 assert_eq!(agg.depends_on().collect::<Vec<_>>(), vec![&vname!("two"), &vname!("three")]);
955 assert_eq!(call2(&agg), svnum!(8u64));
956 }
957
958 #[test]
959 #[should_panic]
960 fn math_sum_fail() { call(&Aggregator::Take(SubAggregator::SumUnwrap(vname!("unverified")))); }
961
962 #[test]
963 #[should_panic]
964 fn math_prod_fail() { call(&Aggregator::Take(SubAggregator::ProdUnwrap(vname!("unverified")))); }
965
966 fn independent(agg: Aggregator, val: StrictVal) {
967 assert_eq!(call(&agg), val);
968 assert_eq!(agg.depends_on().count(), 0);
969 }
970
971 #[test]
972 fn verified_readers() {
973 independent(Aggregator::Take(SubAggregator::First(vname!("verified"))), svnum!(5u64));
974 independent(Aggregator::Take(SubAggregator::Nth(vname!("verified"), 0)), svnum!(5u64));
975 independent(Aggregator::Take(SubAggregator::Nth(vname!("verified"), 1)), svnum!(1u64));
976 independent(Aggregator::Take(SubAggregator::Last(vname!("verified"))), svnum!(5u64));
977 independent(Aggregator::Take(SubAggregator::NthBack(vname!("verified"), 0)), svnum!(5u64));
978 independent(Aggregator::Take(SubAggregator::NthBack(vname!("verified"), 1)), svnum!(4u64));
979 independent(Aggregator::Take(SubAggregator::Count(vname!("verified"))), svnum!(6u64));
980 independent(Aggregator::Take(SubAggregator::CountUnique(vname!("verified"))), svnum!(5u64));
981 independent(Aggregator::Take(SubAggregator::SetV(vname!("verified"))), svset!([5u64, 1u64, 2u64, 3u64, 4u64]));
982 independent(Aggregator::Take(SubAggregator::MapV2U(vname!("verified"))), StrictVal::Map(none!()));
983 independent(Aggregator::Take(SubAggregator::MapV2ListU(vname!("verified"))), StrictVal::Map(none!()));
984 independent(Aggregator::Take(SubAggregator::MapV2SetU(vname!("verified"))), StrictVal::Map(none!()));
985 }
986
987 #[test]
988 fn unverified_readers() {
989 independent(Aggregator::Take(SubAggregator::Count(vname!("verified"))), svnum!(6u64));
990 independent(Aggregator::Take(SubAggregator::SetV(vname!("unverified"))), svset!([()]));
991 independent(
992 Aggregator::Take(SubAggregator::MapV2U(vname!("unverified"))),
993 StrictVal::Map(vec![(StrictVal::Unit, svstr!("state 1"))]),
994 );
995 independent(
996 Aggregator::Take(SubAggregator::MapV2ListU(vname!("unverified"))),
997 StrictVal::Map(vec![(StrictVal::Unit, svlist![[
998 svstr!("state 1"),
999 svstr!("state 2"),
1000 svstr!("state 3"),
1001 svstr!("state 4"),
1002 svstr!("state 5"),
1003 svstr!("state 6"),
1004 ]])]),
1005 );
1006 independent(
1007 Aggregator::Take(SubAggregator::MapV2SetU(vname!("unverified"))),
1008 StrictVal::Map(vec![(StrictVal::Unit, svset![[
1009 svstr!("state 1"),
1010 svstr!("state 2"),
1011 svstr!("state 3"),
1012 svstr!("state 4"),
1013 svstr!("state 5"),
1014 svstr!("state 6"),
1015 ]])]),
1016 );
1017 }
1018
1019 #[test]
1020 #[should_panic]
1021 fn unverified_sum() { call(&Aggregator::Take(SubAggregator::SumUnwrap(vname!("unverified")))); }
1022
1023 #[test]
1024 fn unverified_sum_default() {
1025 independent(Aggregator::Take(SubAggregator::SumOrDefault(vname!("unverified"))), svnum!(0u64));
1026 }
1027
1028 #[test]
1029 fn pair_readers() {
1030 independent(Aggregator::Take(SubAggregator::Count(vname!("verified"))), svnum!(6u64));
1031 independent(Aggregator::Take(SubAggregator::SumUnwrap(vname!("pairs"))), svnum!(5u64 + 1 + 2 + 3 + 4 + 5));
1032 independent(Aggregator::Take(SubAggregator::SetV(vname!("pairs"))), svset!([5u64, 1u64, 2u64, 3u64, 4u64]));
1033 independent(
1034 Aggregator::Take(SubAggregator::MapV2U(vname!("pairs"))),
1035 StrictVal::Map(vec![
1036 (svnum!(5u64), svstr!("state 1")),
1037 (svnum!(1u64), svstr!("state 2")),
1038 (svnum!(2u64), svstr!("state 3")),
1039 (svnum!(3u64), svstr!("state 4")),
1040 (svnum!(4u64), svstr!("state 5")),
1041 ]),
1042 );
1043 independent(
1044 Aggregator::Take(SubAggregator::MapV2ListU(vname!("pairs"))),
1045 StrictVal::Map(vec![
1046 (svnum!(5u64), svlist![[svstr!("state 1"), svstr!("state 6")]]),
1047 (svnum!(1u64), svlist![[svstr!("state 2")]]),
1048 (svnum!(2u64), svlist![[svstr!("state 3")]]),
1049 (svnum!(3u64), svlist![[svstr!("state 4")]]),
1050 (svnum!(4u64), svlist![[svstr!("state 5")]]),
1051 ]),
1052 );
1053 }
1054
1055 #[test]
1056 #[should_panic]
1057 fn aluvm() { call(&Aggregator::AluVM(LibSite::new(success_lib().lib_id(), 0))); }
1059}