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    type Cfg = ();
52
53    fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
54        <[u8; Self::SIZE]>::read(buf).map(Self)
55    }
56}
57
58impl FixedSize for U64 {
59    const SIZE: usize = u64::SIZE + 1;
60}
61
62impl Array for U64 {}
63
64impl From<[u8; U64::SIZE]> for U64 {
65    fn from(value: [u8; U64::SIZE]) -> Self {
66        Self(value)
67    }
68}
69
70impl AsRef<[u8]> for U64 {
71    fn as_ref(&self) -> &[u8] {
72        &self.0
73    }
74}
75
76impl Deref for U64 {
77    type Target = [u8];
78    fn deref(&self) -> &[u8] {
79        &self.0
80    }
81}
82
83impl Debug for U64 {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(
86            f,
87            "{}:{}",
88            self.0[0],
89            u64::from_be_bytes(self.0[1..].try_into().unwrap())
90        )
91    }
92}
93
94impl Display for U64 {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        Debug::fmt(self, f)
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use commonware_codec::{DecodeExt, Encode};
104
105    #[test]
106    fn test_prefixed_u64() {
107        let prefix = 69u8;
108        let value = 42u64;
109        let array = U64::new(prefix, value);
110        let decoded = U64::decode(array.as_ref()).unwrap();
111        assert_eq!(value, decoded.to_u64());
112        assert_eq!(prefix, decoded.prefix());
113        let from = U64::from(array.0);
114        assert_eq!(value, from.to_u64());
115        assert_eq!(prefix, from.prefix());
116
117        let vec = array.to_vec();
118        let from_vec = U64::decode(vec.as_ref()).unwrap();
119        assert_eq!(value, from_vec.to_u64());
120        assert_eq!(prefix, from_vec.prefix());
121    }
122
123    #[test]
124    fn test_prefixed_u64_codec() {
125        let original = U64::new(69, 42u64);
126
127        let encoded = original.encode();
128        assert_eq!(encoded.len(), U64::SIZE);
129        assert_eq!(encoded, original.as_ref());
130
131        let decoded = U64::decode(encoded).unwrap();
132        assert_eq!(original, decoded);
133    }
134}