commonware_utils/array/
prefixed_u64.rs

1//! A `u64` array type with a prefix byte to allow for multiple key contexts.
2
3use crate::Array;
4use bytes::{Buf, BufMut};
5use commonware_codec::{Error as CodecError, FixedSize, Read, ReadExt, Write};
6use std::{
7    cmp::{Ord, PartialOrd},
8    fmt::{Debug, Display},
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 fn new(prefix: u8, value: u64) -> Self {
28        let mut arr = [0; u64::SIZE + 1];
29        arr[0] = prefix;
30        arr[1..].copy_from_slice(&u64::to_be_bytes(value));
31
32        Self(arr)
33    }
34
35    pub fn to_u64(&self) -> u64 {
36        u64::from_be_bytes(self.0[1..].try_into().unwrap())
37    }
38
39    pub fn prefix(&self) -> u8 {
40        self.0[0]
41    }
42}
43
44impl Write for U64 {
45    fn write(&self, buf: &mut impl BufMut) {
46        self.0.write(buf);
47    }
48}
49
50impl Read for U64 {
51    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
52        <[u8; Self::SIZE]>::read(buf).map(Self)
53    }
54}
55
56impl FixedSize for U64 {
57    const SIZE: usize = u64::SIZE + 1;
58}
59
60impl Array for U64 {}
61
62impl From<[u8; U64::SIZE]> for U64 {
63    fn from(value: [u8; U64::SIZE]) -> Self {
64        Self(value)
65    }
66}
67
68impl AsRef<[u8]> for U64 {
69    fn as_ref(&self) -> &[u8] {
70        &self.0
71    }
72}
73
74impl Deref for U64 {
75    type Target = [u8];
76    fn deref(&self) -> &[u8] {
77        &self.0
78    }
79}
80
81impl Debug for U64 {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        write!(
84            f,
85            "{}:{}",
86            self.0[0],
87            u64::from_be_bytes(self.0[1..].try_into().unwrap())
88        )
89    }
90}
91
92impl Display for U64 {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        Debug::fmt(self, f)
95    }
96}
97
98#[cfg(test)]
99mod tests {
100    use super::*;
101    use commonware_codec::{DecodeExt, Encode};
102
103    #[test]
104    fn test_prefixed_u64() {
105        let prefix = 69u8;
106        let value = 42u64;
107        let array = U64::new(prefix, value);
108        let decoded = U64::decode(array.as_ref()).unwrap();
109        assert_eq!(value, decoded.to_u64());
110        assert_eq!(prefix, decoded.prefix());
111        let from = U64::from(array.0);
112        assert_eq!(value, from.to_u64());
113        assert_eq!(prefix, from.prefix());
114
115        let vec = array.to_vec();
116        let from_vec = U64::decode(vec.as_ref()).unwrap();
117        assert_eq!(value, from_vec.to_u64());
118        assert_eq!(prefix, from_vec.prefix());
119    }
120
121    #[test]
122    fn test_prefixed_u64_codec() {
123        let original = U64::new(69, 42u64);
124
125        let encoded = original.encode();
126        assert_eq!(encoded.len(), U64::SIZE);
127        assert_eq!(encoded, original.as_ref());
128
129        let decoded = U64::decode(encoded).unwrap();
130        assert_eq!(original, decoded);
131    }
132}