commonware_utils/sequence/
fixed_bytes.rs1use crate::{hex, Array, Span};
2use bytes::{Buf, BufMut};
3use commonware_codec::{Error as CodecError, FixedSize, Read, ReadExt, Write};
4use core::{
5 cmp::{Ord, PartialOrd},
6 fmt::{Debug, Display},
7 hash::Hash,
8 ops::Deref,
9};
10use thiserror::Error;
11
12#[derive(Error, Debug, PartialEq)]
14pub enum Error {
15 #[error("invalid length")]
16 InvalidLength,
17}
18
19#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
21#[repr(transparent)]
22pub struct FixedBytes<const N: usize>([u8; N]);
23
24impl<const N: usize> FixedBytes<N> {
25 pub const fn new(value: [u8; N]) -> Self {
27 Self(value)
28 }
29}
30
31impl<const N: usize> Write for FixedBytes<N> {
32 fn write(&self, buf: &mut impl BufMut) {
33 self.0.write(buf);
34 }
35}
36
37impl<const N: usize> Read for FixedBytes<N> {
38 type Cfg = ();
39
40 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
41 Ok(Self(<[u8; N]>::read(buf)?))
42 }
43}
44
45impl<const N: usize> FixedSize for FixedBytes<N> {
46 const SIZE: usize = N;
47}
48
49impl<const N: usize> Span for FixedBytes<N> {}
50
51impl<const N: usize> Array for FixedBytes<N> {}
52
53impl<const N: usize> AsRef<[u8]> for FixedBytes<N> {
54 fn as_ref(&self) -> &[u8] {
55 &self.0
56 }
57}
58
59impl<const N: usize> Deref for FixedBytes<N> {
60 type Target = [u8];
61 fn deref(&self) -> &[u8] {
62 &self.0
63 }
64}
65
66impl<const N: usize> Display for FixedBytes<N> {
67 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68 write!(f, "{}", hex(&self.0))
69 }
70}
71
72impl<const N: usize> From<[u8; N]> for FixedBytes<N> {
73 fn from(value: [u8; N]) -> Self {
74 Self::new(value)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81 use crate::fixed_bytes;
82 use bytes::{Buf, BytesMut};
83 use commonware_codec::{DecodeExt, Encode};
84
85 #[test]
86 fn test_codec() {
87 let original = FixedBytes::new([1, 2, 3, 4]);
88 let encoded = original.encode();
89 assert_eq!(encoded.len(), original.len());
90 let decoded = FixedBytes::decode(encoded).unwrap();
91 assert_eq!(original, decoded);
92 }
93
94 #[test]
95 fn test_bytes_creation_and_conversion() {
96 let value = [1, 2, 3, 4];
97 let bytes = FixedBytes::new(value);
98 assert_eq!(bytes.as_ref(), &value);
99
100 let bytes_into = value.into();
101 assert_eq!(bytes, bytes_into);
102
103 let slice = [1, 2, 3, 4];
104 let bytes_from_slice = FixedBytes::decode(slice.as_ref()).unwrap();
105 assert_eq!(bytes_from_slice, bytes);
106
107 let vec = vec![1, 2, 3, 4];
108 let bytes_from_vec = FixedBytes::decode(vec.as_ref()).unwrap();
109 assert_eq!(bytes_from_vec, bytes);
110
111 let slice_too_short = [1, 2, 3];
113 assert!(matches!(
114 FixedBytes::<4>::decode(slice_too_short.as_ref()),
115 Err(CodecError::EndOfBuffer)
116 ));
117
118 let vec_too_long = vec![1, 2, 3, 4, 5];
119 assert!(matches!(
120 FixedBytes::<4>::decode(vec_too_long.as_ref()),
121 Err(CodecError::ExtraData(1))
122 ));
123 }
124
125 #[test]
126 fn test_read() {
127 let mut buf = BytesMut::from(&[1, 2, 3, 4][..]);
128 let bytes = FixedBytes::<4>::read(&mut buf).unwrap();
129 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
130 assert_eq!(buf.remaining(), 0);
131
132 let mut buf = BytesMut::from(&[1, 2, 3][..]);
133 let result = FixedBytes::<4>::read(&mut buf);
134 assert!(matches!(result, Err(CodecError::EndOfBuffer)));
135
136 let mut buf = BytesMut::from(&[1, 2, 3, 4, 5][..]);
137 let bytes = FixedBytes::<4>::read(&mut buf).unwrap();
138 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
139 assert_eq!(buf.remaining(), 1);
140 assert_eq!(buf[0], 5);
141 }
142
143 #[test]
144 fn test_display() {
145 let bytes = fixed_bytes!("0x01020304");
146 assert_eq!(format!("{bytes}"), "01020304");
147 }
148
149 #[test]
150 fn test_ord_and_eq() {
151 let a = FixedBytes::new([1, 2, 3, 4]);
152 let b = FixedBytes::new([1, 2, 3, 5]);
153 assert!(a < b);
154 assert_ne!(a, b);
155
156 let c = FixedBytes::new([1, 2, 3, 4]);
157 assert_eq!(a, c);
158 }
159}