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