1use crate::{hex, Array};
2use bytes::{Buf, BufMut};
3use commonware_codec::{Error as CodecError, FixedSize, Read, ReadExt, Write};
4use std::{
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 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 fn read_cfg(buf: &mut impl Buf, _: &()) -> Result<Self, CodecError> {
39 Ok(Self(<[u8; N]>::read(buf)?))
40 }
41}
42
43impl<const N: usize> FixedSize for FixedBytes<N> {
44 const SIZE: usize = N;
45}
46
47impl<const N: usize> Array for FixedBytes<N> {}
48
49impl<const N: usize> AsRef<[u8]> for FixedBytes<N> {
50 fn as_ref(&self) -> &[u8] {
51 &self.0
52 }
53}
54
55impl<const N: usize> Deref for FixedBytes<N> {
56 type Target = [u8];
57 fn deref(&self) -> &[u8] {
58 &self.0
59 }
60}
61
62impl<const N: usize> Display for FixedBytes<N> {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "{}", hex(&self.0))
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use bytes::{Buf, BytesMut};
72 use commonware_codec::{DecodeExt, Encode};
73
74 #[test]
75 fn test_codec() {
76 let original = FixedBytes::new([1, 2, 3, 4]);
77 let encoded = original.encode();
78 assert_eq!(encoded.len(), original.len());
79 let decoded = FixedBytes::decode(encoded).unwrap();
80 assert_eq!(original, decoded);
81 }
82
83 #[test]
84 fn test_bytes_creation_and_conversion() {
85 let value = [1, 2, 3, 4];
86 let bytes = FixedBytes::new(value);
87 assert_eq!(bytes.as_ref(), &value);
88
89 let slice = [1, 2, 3, 4];
90 let bytes_from_slice = FixedBytes::decode(slice.as_ref()).unwrap();
91 assert_eq!(bytes_from_slice, bytes);
92
93 let vec = vec![1, 2, 3, 4];
94 let bytes_from_vec = FixedBytes::decode(vec.as_ref()).unwrap();
95 assert_eq!(bytes_from_vec, bytes);
96
97 let slice_too_short = [1, 2, 3];
99 assert!(matches!(
100 FixedBytes::<4>::decode(slice_too_short.as_ref()),
101 Err(CodecError::EndOfBuffer)
102 ));
103
104 let vec_too_long = vec![1, 2, 3, 4, 5];
105 assert!(matches!(
106 FixedBytes::<4>::decode(vec_too_long.as_ref()),
107 Err(CodecError::ExtraData(1))
108 ));
109 }
110
111 #[test]
112 fn test_read() {
113 let mut buf = BytesMut::from(&[1, 2, 3, 4][..]);
114 let bytes = FixedBytes::<4>::read(&mut buf).unwrap();
115 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
116 assert_eq!(buf.remaining(), 0);
117
118 let mut buf = BytesMut::from(&[1, 2, 3][..]);
119 let result = FixedBytes::<4>::read(&mut buf);
120 assert!(matches!(result, Err(CodecError::EndOfBuffer)));
121
122 let mut buf = BytesMut::from(&[1, 2, 3, 4, 5][..]);
123 let bytes = FixedBytes::<4>::read(&mut buf).unwrap();
124 assert_eq!(bytes.as_ref(), &[1, 2, 3, 4]);
125 assert_eq!(buf.remaining(), 1);
126 assert_eq!(buf[0], 5);
127 }
128
129 #[test]
130 fn test_display() {
131 let bytes = FixedBytes::new([0x01, 0x02, 0x03, 0x04]);
132 assert_eq!(format!("{}", bytes), "01020304");
133 }
134
135 #[test]
136 fn test_ord_and_eq() {
137 let a = FixedBytes::new([1, 2, 3, 4]);
138 let b = FixedBytes::new([1, 2, 3, 5]);
139 assert!(a < b);
140 assert_ne!(a, b);
141
142 let c = FixedBytes::new([1, 2, 3, 4]);
143 assert_eq!(a, c);
144 }
145}