Skip to main content

typhoon/bytes/
fixed.rs

1#[cfg(test)]
2#[path = "../../tests/bytes/fixed.rs"]
3mod tests;
4
5/// Stack-allocated fixed-size byte buffer for compile-time-known sizes (e.g. cryptographic keys).
6/// Zero heap allocation; `Copy` semantics — 32-byte copies are cheaper than atomic Arc ops.
7use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
8use std::hash::{Hash, Hasher};
9
10use crate::bytes::common::ByteBuffer;
11
12/// Fixed-size byte buffer backed by a `[u8; N]` stack array.
13/// Implements [`ByteBuffer`] so it can be passed wherever a byte buffer is expected.
14/// Unlike [`StaticByteBuffer`](super::StaticByteBuffer), no heap allocation occurs.
15#[derive(Clone, Copy)]
16pub struct FixedByteBuffer<const N: usize> {
17    data: [u8; N],
18}
19
20impl<const N: usize> FixedByteBuffer<N> {
21    /// Create a zeroed buffer.
22    #[inline]
23    pub fn zeroed() -> Self {
24        Self {
25            data: [0u8; N],
26        }
27    }
28
29    /// Create from a fixed-size array.
30    #[inline]
31    pub fn from_array(arr: [u8; N]) -> Self {
32        Self {
33            data: arr,
34        }
35    }
36
37    /// Get a reference to the inner array.
38    #[inline]
39    pub fn as_array(&self) -> &[u8; N] {
40        &self.data
41    }
42}
43
44impl<const N: usize> ByteBuffer for FixedByteBuffer<N> {
45    #[inline]
46    fn len(&self) -> usize {
47        N
48    }
49
50    #[inline]
51    fn get(&self, at: usize) -> &u8 {
52        assert!(at < N, "index out of bounds: {at} >= {N}");
53        &self.data[at]
54    }
55
56    #[inline]
57    fn slice(&self) -> &[u8] {
58        &self.data
59    }
60
61    #[inline]
62    fn slice_start(&self, start: usize) -> &[u8] {
63        assert!(start <= N, "start out of bounds");
64        &self.data[start..]
65    }
66
67    #[inline]
68    fn slice_end(&self, end: usize) -> &[u8] {
69        assert!(end <= N, "end out of bounds");
70        &self.data[..end]
71    }
72
73    #[inline]
74    fn slice_both(&self, start: usize, end: usize) -> &[u8] {
75        assert!(start <= end && end <= N, "invalid slice bounds");
76        &self.data[start..end]
77    }
78
79    #[inline]
80    fn split(&self, divide: usize) -> (&[u8], &[u8]) {
81        assert!(divide <= N, "divide point out of bounds");
82        (&self.data[..divide], &self.data[divide..])
83    }
84}
85
86impl<const N: usize> AsRef<[u8]> for FixedByteBuffer<N> {
87    #[inline]
88    fn as_ref(&self) -> &[u8] {
89        &self.data
90    }
91}
92
93impl<const N: usize> From<[u8; N]> for FixedByteBuffer<N> {
94    #[inline]
95    fn from(arr: [u8; N]) -> Self {
96        Self {
97            data: arr,
98        }
99    }
100}
101
102impl<const N: usize> From<&[u8; N]> for FixedByteBuffer<N> {
103    #[inline]
104    fn from(arr: &[u8; N]) -> Self {
105        Self {
106            data: *arr,
107        }
108    }
109}
110
111impl<const N: usize> From<FixedByteBuffer<N>> for [u8; N] {
112    #[inline]
113    fn from(buf: FixedByteBuffer<N>) -> [u8; N] {
114        buf.data
115    }
116}
117
118impl<const N: usize> Default for FixedByteBuffer<N> {
119    #[inline]
120    fn default() -> Self {
121        Self::zeroed()
122    }
123}
124
125impl<const N: usize> PartialEq for FixedByteBuffer<N> {
126    #[inline]
127    fn eq(&self, other: &Self) -> bool {
128        self.data == other.data
129    }
130}
131
132impl<const N: usize> Eq for FixedByteBuffer<N> {}
133
134impl<const N: usize> Hash for FixedByteBuffer<N> {
135    #[inline]
136    fn hash<H: Hasher>(&self, state: &mut H) {
137        self.data.hash(state);
138    }
139}
140
141impl<const N: usize> Display for FixedByteBuffer<N> {
142    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
143        for byte in &self.data {
144            write!(f, "{byte:02x}")?;
145        }
146        Ok(())
147    }
148}
149
150impl<const N: usize> Debug for FixedByteBuffer<N> {
151    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
152        f.debug_struct("FixedByteBuffer").field("length", &N).field("data", &self.data).finish()
153    }
154}