pczt/roles/combiner/
mod.rs1use alloc::collections::BTreeMap;
6use alloc::vec::Vec;
7
8use crate::Pczt;
9
10pub struct Combiner {
11 pczts: Vec<Pczt>,
12}
13
14impl Combiner {
15 pub fn new(pczts: Vec<Pczt>) -> Self {
17 Self { pczts }
18 }
19
20 pub fn combine(self) -> Result<Pczt, Error> {
22 self.pczts
23 .into_iter()
24 .try_fold(None, |acc, pczt| match acc {
25 None => Ok(Some(pczt)),
26 Some(acc) => merge(acc, pczt).map(Some),
27 })
28 .transpose()
29 .unwrap_or(Err(Error::NoPczts))
30 }
31}
32
33fn merge(lhs: Pczt, rhs: Pczt) -> Result<Pczt, Error> {
34 let transparent = lhs
37 .transparent
38 .merge(rhs.transparent, &lhs.global, &rhs.global)
39 .ok_or(Error::DataMismatch)?;
40 let sapling = lhs
41 .sapling
42 .merge(rhs.sapling, &lhs.global, &rhs.global)
43 .ok_or(Error::DataMismatch)?;
44 let orchard = lhs
45 .orchard
46 .merge(rhs.orchard, &lhs.global, &rhs.global)
47 .ok_or(Error::DataMismatch)?;
48 let ironwood = lhs
49 .ironwood
50 .merge(rhs.ironwood, &lhs.global, &rhs.global)
51 .ok_or(Error::DataMismatch)?;
52
53 let global = lhs.global.merge(rhs.global).ok_or(Error::DataMismatch)?;
55
56 Ok(Pczt {
57 global,
58 transparent,
59 sapling,
60 orchard,
61 ironwood,
62 })
63}
64
65pub(crate) fn merge_optional<T: PartialEq>(lhs: &mut Option<T>, rhs: Option<T>) -> bool {
69 match (&lhs, rhs) {
70 (_, None) => (),
72 (None, Some(rhs)) => *lhs = Some(rhs),
74 (Some(lhs), Some(rhs)) if lhs == &rhs => (),
76 (Some(_), Some(_)) => return false,
78 }
79
80 true
82}
83
84pub(crate) fn merge_map<K: Ord, V: PartialEq>(
88 lhs: &mut BTreeMap<K, V>,
89 rhs: BTreeMap<K, V>,
90) -> bool {
91 for (key, rhs_value) in rhs.into_iter() {
92 if let Some(lhs_value) = lhs.get_mut(&key) {
93 if lhs_value != &rhs_value {
96 return false;
97 }
98 } else {
99 lhs.insert(key, rhs_value);
100 }
101 }
102
103 true
105}
106
107#[derive(Debug)]
109pub enum Error {
110 NoPczts,
111 DataMismatch,
112}