Skip to main content

typhoon/bytes/
static.rs

1#[cfg(test)]
2#[path = "../../tests/bytes/static.rs"]
3mod tests;
4
5use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
6use std::hash::{Hash, Hasher};
7use std::sync::Arc;
8
9use crate::bytes::common::ByteBuffer;
10
11/// Immutable owned byte buffer with Arc-based sharing.
12/// Send + Sync - can be safely shared across threads.
13/// Used for cryptographic keys and other immutable data.
14#[derive(Clone)]
15pub struct StaticByteBuffer {
16    data: Arc<[u8]>,
17}
18
19impl StaticByteBuffer {
20    /// Create an owned buffer from a slice.
21    #[inline]
22    pub fn from_slice(data: &[u8]) -> Self {
23        Self {
24            data: Arc::from(data),
25        }
26    }
27
28    /// Create an owned buffer from a fixed-size array.
29    #[inline]
30    pub fn from_array<const N: usize>(arr: &[u8; N]) -> Self {
31        Self::from_slice(arr.as_slice())
32    }
33
34    /// Create an empty owned buffer of given size (zeroed).
35    #[inline]
36    pub fn empty(size: usize) -> Self {
37        Self {
38            data: Arc::from(vec![0u8; size]),
39        }
40    }
41}
42
43// SAFETY: Arc<[u8]> is thread-safe for sharing immutable data.
44unsafe impl Send for StaticByteBuffer {}
45unsafe impl Sync for StaticByteBuffer {}
46
47impl ByteBuffer for StaticByteBuffer {
48    #[inline]
49    fn len(&self) -> usize {
50        self.data.len()
51    }
52
53    #[inline]
54    fn get(&self, at: usize) -> &u8 {
55        assert!(at < self.len(), "index out of bounds: {} >= {}", at, self.len());
56        &self.data[at]
57    }
58
59    #[inline]
60    fn slice(&self) -> &[u8] {
61        &self.data
62    }
63
64    #[inline]
65    fn slice_start(&self, start: usize) -> &[u8] {
66        assert!(start <= self.len(), "start out of bounds");
67        &self.data[start..]
68    }
69
70    #[inline]
71    fn slice_end(&self, end: usize) -> &[u8] {
72        assert!(end <= self.len(), "end out of bounds");
73        &self.data[..end]
74    }
75
76    #[inline]
77    fn slice_both(&self, start: usize, end: usize) -> &[u8] {
78        assert!(start <= end && end <= self.len(), "invalid slice bounds");
79        &self.data[start..end]
80    }
81
82    #[inline]
83    fn split(&self, divide: usize) -> (&[u8], &[u8]) {
84        assert!(divide <= self.len(), "divide point out of bounds");
85        (&self.data[..divide], &self.data[divide..])
86    }
87}
88
89impl AsRef<[u8]> for StaticByteBuffer {
90    #[inline]
91    fn as_ref(&self) -> &[u8] {
92        &self.data
93    }
94}
95
96impl From<Vec<u8>> for StaticByteBuffer {
97    #[inline]
98    fn from(value: Vec<u8>) -> Self {
99        Self {
100            data: Arc::from(value),
101        }
102    }
103}
104
105impl From<&[u8]> for StaticByteBuffer {
106    #[inline]
107    fn from(value: &[u8]) -> Self {
108        Self::from_slice(value)
109    }
110}
111
112impl<const N: usize> From<&[u8; N]> for StaticByteBuffer {
113    #[inline]
114    fn from(value: &[u8; N]) -> Self {
115        Self::from_array(value)
116    }
117}
118
119impl<const N: usize> From<[u8; N]> for StaticByteBuffer {
120    #[inline]
121    fn from(value: [u8; N]) -> Self {
122        Self::from_array(&value)
123    }
124}
125
126impl From<StaticByteBuffer> for Vec<u8> {
127    #[inline]
128    fn from(val: StaticByteBuffer) -> Self {
129        val.data.to_vec()
130    }
131}
132
133impl From<&StaticByteBuffer> for Vec<u8> {
134    #[inline]
135    fn from(val: &StaticByteBuffer) -> Self {
136        val.data.to_vec()
137    }
138}
139
140impl<const N: usize> From<&StaticByteBuffer> for [u8; N] {
141    #[inline]
142    fn from(val: &StaticByteBuffer) -> Self {
143        match <[u8; N]>::try_from(&val.data[..]) {
144            Ok(res) => res,
145            Err(err) => panic!("error converting StaticByteBuffer to array [u8; {}], actual length {}: {}", N, val.len(), err),
146        }
147    }
148}
149
150impl PartialEq for StaticByteBuffer {
151    #[inline]
152    fn eq(&self, other: &Self) -> bool {
153        self.data == other.data
154    }
155}
156
157impl Eq for StaticByteBuffer {}
158
159impl Hash for StaticByteBuffer {
160    #[inline]
161    fn hash<H: Hasher>(&self, state: &mut H) {
162        self.data.hash(state);
163    }
164}
165
166impl Display for StaticByteBuffer {
167    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
168        for byte in self.data.iter() {
169            write!(f, "{byte:02x}")?;
170        }
171        Ok(())
172    }
173}
174
175impl Debug for StaticByteBuffer {
176    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
177        f.debug_struct("StaticByteBuffer").field("length", &self.len()).field("data", &self.data.as_ref()).finish()
178    }
179}