commonware_utils/sequence/
prefixed_u64.rs

1//! A `u64` array type with a prefix byte to allow for multiple key contexts.
2
3use crate::{Array, Span};
4use bytes::{Buf, BufMut};
5use commonware_codec::{Error as CodecError, FixedSize, Read, ReadExt, Write};
6use core::{
7    cmp::{Ord, PartialOrd},
8    fmt::{Debug, Display, Formatter},
9    hash::Hash,
10    ops::Deref,
11};
12use thiserror::Error;
13
14// Errors returned by `U64` functions.
15#[derive(Error, Debug, PartialEq)]
16pub enum Error {
17    #[error("invalid length")]
18    InvalidLength,
19}
20
21/// An `Array` implementation for prefixed `U64`
22#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
23#[repr(transparent)]
24pub struct U64([u8; u64::SIZE + 1]);
25
26impl U64 {
27    pub const fn new(prefix: u8, value: u64) -> Self {
28        // TODO: #![feature(const_index)]
29        // https://github.com/rust-lang/rust/issues/143775
30        let [b0, b1, b2, b3, b4, b5, b6, b7] = value.to_be_bytes();
31        Self([prefix, b0, b1, b2, b3, b4, b5, b6, b7])
32    }
33
34    pub fn prefix(&self) -> u8 {
35        self.0[0]
36    }
37
38    pub fn value(&self) -> u64 {
39        u64::from_be_bytes(self.0[1..].try_into().unwrap())
40    }
41}
42
43impl Write for U64 {
44    fn write(&self, buf: &mut impl BufMut) {
45        self.0.write(buf);
46    }
47}
48
49impl Read for U64 {
50    type Cfg = ();
51
52    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
53        <[u8; Self::SIZE]>::read(buf).map(Self)
54    }
55}
56
57impl FixedSize for U64 {
58    const SIZE: usize = u64::SIZE + 1;
59}
60
61impl Span for U64 {}
62
63impl Array for U64 {}
64
65impl From<[u8; U64::SIZE]> for U64 {
66    fn from(value: [u8; U64::SIZE]) -> Self {
67        Self(value)
68    }
69}
70
71impl AsRef<[u8]> for U64 {
72    fn as_ref(&self) -> &[u8] {
73        &self.0
74    }
75}
76
77impl Deref for U64 {
78    type Target = [u8];
79    fn deref(&self) -> &[u8] {
80        &self.0
81    }
82}
83
84impl Debug for U64 {
85    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
86        write!(
87            f,
88            "{}:{}",
89            self.0[0],
90            u64::from_be_bytes(self.0[1..].try_into().unwrap())
91        )
92    }
93}
94
95impl Display for U64 {
96    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
97        Debug::fmt(self, f)
98    }
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104    use commonware_codec::{DecodeExt, Encode};
105
106    #[test]
107    fn test_prefixed_u64() {
108        let prefix = 69u8;
109        let value = 42u64;
110        let array = U64::new(prefix, value);
111        let decoded = U64::decode(array.as_ref()).unwrap();
112        assert_eq!(value, decoded.value());
113        assert_eq!(prefix, decoded.prefix());
114        let from = U64::from(array.0);
115        assert_eq!(value, from.value());
116        assert_eq!(prefix, from.prefix());
117
118        let vec = array.to_vec();
119        let from_vec = U64::decode(vec.as_ref()).unwrap();
120        assert_eq!(value, from_vec.value());
121        assert_eq!(prefix, from_vec.prefix());
122    }
123
124    #[test]
125    fn test_prefixed_u64_codec() {
126        let original = U64::new(69, 42u64);
127
128        let encoded = original.encode();
129        assert_eq!(encoded.len(), U64::SIZE);
130        assert_eq!(encoded, original.as_ref());
131
132        let decoded = U64::decode(encoded).unwrap();
133        assert_eq!(original, decoded);
134    }
135}