concordium_base/common/
version.rs

1use super::*;
2use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize};
3
4/// Version 0 as a constant for ease of use.
5pub const VERSION_0: Version = Version { value: 0 };
6
7/// Version of the serialization of a data structure. Binary coded as a variable
8/// integer represented by bytes, where MSB=1 indicates more bytes follow, and
9/// the 7 lower bits in a byte is Big Endian data bits for the value. A version
10/// number is bounded by u32 max.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, SerdeSerialize, SerdeDeserialize)]
12#[serde(transparent)]
13pub struct Version {
14    pub value: u32,
15}
16
17impl From<u32> for Version {
18    fn from(value: u32) -> Version {
19        Version { value }
20    }
21}
22
23impl From<Version> for u32 {
24    fn from(val: Version) -> u32 {
25        val.value
26    }
27}
28
29impl std::fmt::Display for Version {
30    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
31        write!(f, "{}", self.value)
32    }
33}
34
35impl Serial for Version {
36    fn serial<B: Buffer>(&self, out: &mut B) {
37        if self.value == 0 {
38            out.write_u8(0).expect("Writing to buffer is safe");
39            return;
40        }
41
42        // Create 7-bit encoding with all MSB set to 1
43        let mut buf: [u8; 5] = [0; 5];
44        let mut v = self.value;
45        let mut len = 0;
46        while v > 0 {
47            buf[len] = (1 << 7) | (v & 0b0111_1111) as u8;
48            v >>= 7;
49            len += 1;
50        }
51
52        // Convert to BigEndian, ensure last byte has MSB=0, write to buffer
53        let buf = &mut buf[..len];
54        buf[0] &= 0b0111_1111;
55        buf.reverse();
56        out.write_all(buf).expect("Writing to buffer is safe");
57    }
58}
59
60impl Deserial for Version {
61    fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
62        let mut acc: u64 = 0;
63        for _ in 0..5 {
64            let byte = u64::from(source.read_u8()?);
65            if byte >= 0b1000_0000 {
66                acc = (acc << 7) | (byte & 0b0111_1111);
67            } else {
68                acc = (acc << 7) | byte;
69                break;
70            }
71        }
72        let value: u32 = acc.try_into()?;
73        Ok(Version::from(value))
74    }
75}
76
77/// [`Versioned<T>`](Versioned) represents `T` as a versioned data-structure.
78/// The version is a integer number up to the implementation,
79/// which is serialized using variable integer encoding.
80/// The caller is responsible for ensuring the data structure `T`
81/// is compatible with the version number.
82#[derive(Clone, Copy, Debug, Eq, PartialEq, SerdeSerialize, SerdeDeserialize)]
83pub struct Versioned<T> {
84    #[serde(rename = "v")]
85    pub version: Version,
86    #[serde(rename = "value")]
87    pub value: T,
88}
89
90impl<T> Versioned<T> {
91    pub fn new(version: Version, value: T) -> Versioned<T> {
92        Versioned { version, value }
93    }
94}
95
96impl<T: Serial> Serial for Versioned<T> {
97    fn serial<B: Buffer>(&self, out: &mut B) {
98        out.put(&self.version);
99        out.put(&self.value);
100    }
101}
102
103impl<T: Deserial> Deserial for Versioned<T> {
104    fn deserial<R: ReadBytesExt>(source: &mut R) -> ParseResult<Self> {
105        let version: Version = source.get()?;
106        let value: T = source.get()?;
107        Ok(Versioned { version, value })
108    }
109}
110
111#[cfg(test)]
112mod tests {
113    use super::*;
114    use rand::{thread_rng, RngCore};
115
116    #[test]
117    fn test_version_serialization_testvector() {
118        let test = Version::from(1_700_794_014);
119        let actual: Vec<u8> = vec![0x86, 0xab, 0x80, 0x9d, 0x1e];
120        let mut buffer: Vec<u8> = Vec::new();
121        test.serial(&mut buffer);
122        assert_eq!(buffer, actual);
123    }
124
125    #[test]
126    fn test_version_serialization_minmax() {
127        let min = Version::from(0);
128        let max = Version::from(u32::MAX);
129        let min_actual: Vec<u8> = vec![0x00];
130        let max_actual: Vec<u8> = vec![0x8F, 0xFF, 0xFF, 0xFF, 0x7F];
131        let mut buffer: Vec<u8> = Vec::new();
132        min.serial(&mut buffer);
133        assert_eq!(buffer, min_actual);
134        let mut buffer: Vec<u8> = Vec::new();
135        max.serial(&mut buffer);
136        assert_eq!(buffer, max_actual);
137    }
138
139    #[test]
140    fn test_version_serialization_overflow() {
141        let data: Vec<u8> = vec![0x9F, 0xFF, 0xFF, 0xFF, 0x7F];
142        let mut cursor = std::io::Cursor::new(data);
143        let version: ParseResult<Version> = cursor.get();
144        assert!(version.is_err());
145    }
146
147    #[test]
148    fn test_version_serialization_random() {
149        let mut rng = thread_rng();
150        for _ in 0..1000 {
151            let actual = Version::from(rng.next_u32());
152            let parsed = serialize_deserialize(&actual)
153                .expect("Deserialization of a serialized value failed");
154            assert_eq!(actual, parsed);
155        }
156    }
157}