1use std::collections::BTreeMap;
2
3use fedimint_core::Amount;
4use serde::{Deserialize, Serialize};
5
6use crate::encoding::{Decodable, DecodeError, Encodable};
7use crate::module::registry::ModuleDecoderRegistry;
8
9#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize)]
10pub struct InvalidAmountTierError(pub Amount);
11
12impl std::fmt::Display for InvalidAmountTierError {
13 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
14 write!(f, "Amount tier unknown to mint: {}", self.0)
15 }
16}
17
18#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
19#[serde(transparent)]
20pub struct Tiered<T>(BTreeMap<Amount, T>);
21
22impl<T> Default for Tiered<T> {
23 fn default() -> Self {
24 Self(BTreeMap::default())
25 }
26}
27
28impl<T> Tiered<T> {
29 pub fn max_tier(&self) -> &Amount {
31 self.0.keys().max().expect("has tiers")
32 }
33
34 pub fn structural_eq<O>(&self, other: &Tiered<O>) -> bool {
35 self.0.keys().eq(other.0.keys())
36 }
37
38 pub fn tier(&self, amount: &Amount) -> Result<&T, InvalidAmountTierError> {
40 self.0.get(amount).ok_or(InvalidAmountTierError(*amount))
41 }
42
43 pub fn count_tiers(&self) -> usize {
44 self.0.len()
45 }
46
47 pub fn tiers(&self) -> impl DoubleEndedIterator<Item = &Amount> {
48 self.0.keys()
49 }
50
51 pub fn values(&self) -> impl DoubleEndedIterator<Item = &T> {
52 self.0.values()
53 }
54
55 pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Amount, &T)> {
56 self.0.iter().map(|(amt, key)| (*amt, key))
57 }
58
59 pub fn get(&self, amt: Amount) -> Option<&T> {
60 self.0.get(&amt)
61 }
62
63 pub fn get_mut(&mut self, amt: Amount) -> Option<&mut T> {
64 self.0.get_mut(&amt)
65 }
66
67 pub fn insert(&mut self, amt: Amount, v: T) -> Option<T> {
68 self.0.insert(amt, v)
69 }
70
71 pub fn get_mut_or_default(&mut self, amt: Amount) -> &mut T
72 where
73 T: Default,
74 {
75 self.0.entry(amt).or_default()
76 }
77
78 pub fn entry(&mut self, amt: Amount) -> std::collections::btree_map::Entry<'_, Amount, T>
79 where
80 T: Default,
81 {
82 self.0.entry(amt)
83 }
84
85 pub fn as_map(&self) -> &BTreeMap<Amount, T> {
86 &self.0
87 }
88}
89
90impl Tiered<()> {
91 pub fn gen_denominations(denomination_base: u16, max: Amount) -> Self {
93 let mut amounts = vec![];
94
95 let mut denomination = Amount::from_msats(1);
96 while denomination <= max {
97 amounts.push((denomination, ()));
98 denomination = denomination * denomination_base.into();
99 }
100
101 amounts.into_iter().collect()
102 }
103}
104
105impl<T> FromIterator<(Amount, T)> for Tiered<T> {
106 fn from_iter<I: IntoIterator<Item = (Amount, T)>>(iter: I) -> Self {
107 Self(iter.into_iter().collect())
108 }
109}
110
111impl<T> IntoIterator for Tiered<T> {
112 type Item = (Amount, T);
113 type IntoIter = std::collections::btree_map::IntoIter<Amount, T>;
114
115 fn into_iter(self) -> Self::IntoIter {
116 self.0.into_iter()
117 }
118}
119
120impl<C> Encodable for Tiered<C>
121where
122 C: Encodable,
123{
124 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<(), std::io::Error> {
125 self.0.consensus_encode(writer)?;
126 Ok(())
127 }
128}
129
130impl<C> Decodable for Tiered<C>
131where
132 C: Decodable,
133{
134 fn consensus_decode_partial<D: std::io::Read>(
135 d: &mut D,
136 modules: &ModuleDecoderRegistry,
137 ) -> Result<Self, DecodeError> {
138 Ok(Self(BTreeMap::consensus_decode_partial(d, modules)?))
139 }
140}
141
142#[cfg(test)]
143mod tests;