amaru_protocols/protocol_messages/
version_table.rs1use std::{
16 collections::BTreeMap,
17 fmt,
18 fmt::{Debug, Display},
19};
20
21use amaru_kernel::{NetworkMagic, cbor};
22
23use crate::protocol_messages::{
24 version_data::{PEER_SHARING_DISABLED, VersionData},
25 version_number::VersionNumber,
26};
27
28#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
29pub struct VersionTable<T> {
30 pub values: BTreeMap<VersionNumber, T>,
31}
32
33impl VersionTable<VersionData> {
34 pub fn empty() -> VersionTable<VersionData> {
35 VersionTable { values: BTreeMap::new() }
36 }
37
38 pub fn query(network_magic: NetworkMagic) -> VersionTable<VersionData> {
39 VersionTable {
40 values: vec![
41 (VersionNumber::V11, VersionData::new(network_magic, false, PEER_SHARING_DISABLED, true)),
42 (VersionNumber::V12, VersionData::new(network_magic, false, PEER_SHARING_DISABLED, true)),
43 (VersionNumber::V13, VersionData::new(network_magic, false, PEER_SHARING_DISABLED, true)),
44 (VersionNumber::V14, VersionData::new(network_magic, false, PEER_SHARING_DISABLED, true)),
45 ]
46 .into_iter()
47 .collect::<BTreeMap<VersionNumber, VersionData>>(),
48 }
49 }
50
51 pub fn v11_and_above(
52 network_magic: NetworkMagic,
53 initiator_only_diffusion_mode: bool,
54 ) -> VersionTable<VersionData> {
55 let values = vec![
56 (
57 VersionNumber::V11,
58 VersionData::new(network_magic, initiator_only_diffusion_mode, PEER_SHARING_DISABLED, false),
59 ),
60 (
61 VersionNumber::V12,
62 VersionData::new(network_magic, initiator_only_diffusion_mode, PEER_SHARING_DISABLED, false),
63 ),
64 (
65 VersionNumber::V13,
66 VersionData::new(network_magic, initiator_only_diffusion_mode, PEER_SHARING_DISABLED, false),
67 ),
68 (
69 VersionNumber::V14,
70 VersionData::new(network_magic, initiator_only_diffusion_mode, PEER_SHARING_DISABLED, false),
71 ),
72 ]
73 .into_iter()
74 .collect::<BTreeMap<VersionNumber, VersionData>>();
75
76 VersionTable { values }
77 }
78}
79
80impl<T: Display + Ord> Display for VersionTable<T> {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let mut entries = self.values.iter().collect::<Vec<_>>();
83 entries.sort();
84 for (idx, (version, data)) in entries.into_iter().enumerate() {
85 if idx > 0 {
86 write!(f, ", ")?;
87 }
88 write!(f, "{}: {}", version.as_u64(), data)?;
89 }
90 Ok(())
91 }
92}
93
94impl<T> cbor::Encode<()> for VersionTable<T>
95where
96 T: fmt::Debug + Clone + cbor::Encode<VersionNumber>,
97{
98 fn encode<W: cbor::encode::Write>(
99 &self,
100 e: &mut cbor::Encoder<W>,
101 _ctx: &mut (),
102 ) -> Result<(), cbor::encode::Error<W::Error>> {
103 e.map(self.values.len() as u64)?;
104
105 for key in self.values.keys() {
106 e.encode(key)?;
107 let mut ctx = *key;
108 e.encode_with(&self.values[key], &mut ctx)?;
109 }
110
111 Ok(())
112 }
113}
114
115impl<'b, T> cbor::Decode<'b, ()> for VersionTable<T>
116where
117 T: fmt::Debug + Clone + cbor::Decode<'b, VersionNumber>,
118{
119 fn decode(d: &mut cbor::Decoder<'b>, _ctx: &mut ()) -> Result<Self, cbor::decode::Error> {
120 let len = d.map()?.ok_or(cbor::decode::Error::message("expected def-length map for versiontable"))?;
121 let mut values = BTreeMap::new();
122
123 for _ in 0..len {
124 let key = d.decode()?;
125 let mut ctx = key;
126 let value = d.decode_with(&mut ctx)?;
127 values.insert(key, value);
128 }
129 Ok(VersionTable { values })
130 }
131}
132
133#[cfg(test)]
134pub(crate) mod tests {
135 use amaru_kernel::prop_cbor_roundtrip;
136 use proptest::prop_compose;
137
138 use super::*;
139 use crate::protocol_messages::{
140 version_data::{VersionData, tests::any_version_data},
141 version_number::tests::any_version_number,
142 };
143
144 prop_cbor_roundtrip!(VersionTable<VersionData>, any_version_table());
145
146 prop_compose! {
147 pub fn any_version_table()(values in proptest::collection::btree_map(any_version_number(), any_version_data(), 0..3)) -> VersionTable<VersionData> {
148 VersionTable { values }
149 }
150 }
151}