Skip to main content

amaru_protocols/protocol_messages/
version_data.rs

1// Copyright 2025 PRAGMA
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt::Display;
16
17use amaru_kernel::{NetworkMagic, cbor};
18
19use crate::protocol_messages::version_number::VersionNumber;
20
21#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
22pub struct VersionData {
23    network_magic: NetworkMagic,
24    initiator_only_diffusion_mode: bool,
25    /// range [0, 1]
26    peer_sharing: u8,
27    query: bool,
28}
29
30pub const PEER_SHARING_DISABLED: u8 = 0;
31pub const PEER_SHARING_ENABLED: u8 = 1;
32
33impl VersionData {
34    pub fn new(
35        network_magic: NetworkMagic,
36        initiator_only_diffusion_mode: bool,
37        peer_sharing: u8,
38        query: bool,
39    ) -> Self {
40        VersionData { network_magic, initiator_only_diffusion_mode, peer_sharing, query }
41    }
42}
43
44impl Display for VersionData {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(
47            f,
48            "{{ network_magic: {}, initiator_only_diffusion_mode: {}, peer_sharing: {}, query: {} }}",
49            self.network_magic, self.initiator_only_diffusion_mode, self.peer_sharing, self.query
50        )
51    }
52}
53
54impl<T: AsRef<VersionNumber>> cbor::Encode<T> for VersionData {
55    fn encode<W: cbor::encode::Write>(
56        &self,
57        e: &mut cbor::Encoder<W>,
58        ctx: &mut T,
59    ) -> Result<(), cbor::encode::Error<W::Error>> {
60        if ctx.as_ref().has_query_and_peer_sharing() {
61            e.array(4)?
62                .encode(self.network_magic)?
63                .bool(self.initiator_only_diffusion_mode)?
64                .u8(self.peer_sharing)?
65                .bool(self.query)?;
66        } else {
67            e.array(2)?.encode(self.network_magic)?.bool(self.initiator_only_diffusion_mode)?;
68        }
69        Ok(())
70    }
71}
72
73impl<'b, T: AsRef<VersionNumber>> cbor::Decode<'b, T> for VersionData {
74    fn decode(d: &mut cbor::Decoder<'b>, ctx: &mut T) -> Result<Self, cbor::decode::Error> {
75        if ctx.as_ref().has_query_and_peer_sharing() {
76            let len = d.array()?;
77            cbor::check_tagged_array_length(0, len, 4)?;
78            let network_magic = d.decode()?;
79            let initiator_only_diffusion_mode = d.bool()?;
80            let peer_sharing = d.u8()?;
81            let query = d.bool()?;
82            Ok(Self { network_magic, initiator_only_diffusion_mode, peer_sharing, query })
83        } else {
84            let len = d.array()?;
85            cbor::check_tagged_array_length(0, len, 2)?;
86            let network_magic = d.decode()?;
87            let initiator_only_diffusion_mode = d.bool()?;
88            Ok(Self { network_magic, initiator_only_diffusion_mode, peer_sharing: 0, query: false })
89        }
90    }
91}
92
93#[cfg(test)]
94pub(crate) mod tests {
95    use amaru_kernel::any_network_magic;
96    use proptest::{prelude::any, prop_compose, strategy::Strategy};
97
98    use super::*;
99
100    prop_compose! {
101        pub fn any_version_data()(network_magic in any_network_magic(),
102            initiator_only_diffusion_mode in any::<bool>(),
103            peer_sharing in any::<bool>().prop_map(|b| if b { 1 } else { 0 }),
104            query in any::<bool>()) -> VersionData {
105            VersionData::new(network_magic, initiator_only_diffusion_mode, peer_sharing, query)
106        }
107    }
108}