Skip to main content

commonware_utils/sequence/
vec_u64.rs

1//! A `u64` encoded with the same framing as a `Vec<u8>` of its big-endian bytes.
2
3use bytes::{Buf, BufMut};
4use commonware_codec::{EncodeSize, Error as CodecError, FixedSize, Read, Write};
5
6/// A `u64` encoded with the same framing as a `Vec<u8>` of its big-endian bytes.
7///
8/// The encoding is a varint length of 8 followed by the 8 big-endian bytes, byte-identical to the
9/// codec encoding of a `Vec<u8>` holding those bytes. This lets a typed `u64` share an on-disk
10/// format with a value historically stored as a `Vec<u8>`.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
12#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
13pub struct VecU64(u64);
14
15impl VecU64 {
16    pub const fn new(value: u64) -> Self {
17        Self(value)
18    }
19}
20
21impl From<u64> for VecU64 {
22    fn from(value: u64) -> Self {
23        Self(value)
24    }
25}
26
27impl From<VecU64> for u64 {
28    fn from(value: VecU64) -> Self {
29        value.0
30    }
31}
32
33impl From<&VecU64> for u64 {
34    fn from(value: &VecU64) -> Self {
35        value.0
36    }
37}
38
39impl Write for VecU64 {
40    fn write(&self, buf: &mut impl BufMut) {
41        let bytes = self.0.to_be_bytes();
42        bytes.len().write(buf);
43        buf.put_slice(&bytes);
44    }
45}
46
47impl EncodeSize for VecU64 {
48    fn encode_size(&self) -> usize {
49        let bytes = self.0.to_be_bytes();
50        bytes.len().encode_size() + bytes.len()
51    }
52}
53
54impl Read for VecU64 {
55    type Cfg = ();
56
57    fn read_cfg(buf: &mut impl Buf, _: &Self::Cfg) -> Result<Self, CodecError> {
58        let len = usize::read_cfg(buf, &(u64::SIZE..=u64::SIZE).into())?;
59        if buf.remaining() < len {
60            return Err(CodecError::EndOfBuffer);
61        }
62        let mut bytes = [0u8; u64::SIZE];
63        buf.copy_to_slice(&mut bytes);
64        Ok(Self(u64::from_be_bytes(bytes)))
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::*;
71    use commonware_codec::{DecodeExt, DecodeRangeExt, Encode};
72
73    #[test]
74    fn test_vec_u64_matches_vec_encoding() {
75        for value in [0u64, 1, 8, 42, 255, 256, u64::MAX - 1, u64::MAX] {
76            let vec = value.to_be_bytes().to_vec();
77            let vec_u64 = VecU64(value);
78
79            // `VecU64` encodes byte-identically to a `Vec<u8>` of the big-endian bytes.
80            assert_eq!(vec_u64.encode(), vec.encode());
81
82            // A `Vec<u8>` reader decodes the bytes written by `VecU64`.
83            assert_eq!(Vec::<u8>::decode_range(vec_u64.encode(), ..).unwrap(), vec);
84
85            // A `VecU64` reader decodes the bytes written as a `Vec<u8>`.
86            assert_eq!(VecU64::decode(vec.encode()).unwrap(), vec_u64);
87        }
88    }
89
90    #[cfg(feature = "arbitrary")]
91    mod conformance {
92        use super::*;
93        use commonware_codec::conformance::CodecConformance;
94
95        commonware_conformance::conformance_tests! {
96            CodecConformance<VecU64>,
97        }
98    }
99}