1use crate::WireError;
19use bytes::{Bytes, BytesMut};
20
21pub trait WireEncode {
27 fn encode(&self, buf: &mut BytesMut);
29
30 fn encoded_size(&self) -> usize;
32
33 #[must_use]
35 fn to_bytes(&self) -> Bytes {
36 let mut buf = BytesMut::with_capacity(self.encoded_size());
37 self.encode(&mut buf);
38 buf.freeze()
39 }
40}
41
42pub trait WireDecode: Sized {
47 fn decode(buf: &[u8]) -> Result<(Self, usize), WireError>;
53
54 fn decode_from(buf: &[u8]) -> Result<Self, WireError> {
59 Self::decode(buf).map(|(val, _)| val)
60 }
61}
62
63#[inline]
68pub fn read_u8(buf: &[u8], offset: usize) -> Result<u8, WireError> {
69 buf.get(offset)
70 .copied()
71 .ok_or_else(|| WireError::UnexpectedEof {
72 offset,
73 need: 1,
74 have: buf.len().saturating_sub(offset),
75 })
76}
77
78#[allow(clippy::missing_panics_doc)]
83#[inline]
84pub fn read_u16_le(buf: &[u8], offset: usize) -> Result<u16, WireError> {
85 let end = offset
86 .checked_add(2)
87 .ok_or_else(|| WireError::UnexpectedEof {
88 offset,
89 need: 2,
90 have: buf.len().saturating_sub(offset),
91 })?;
92 let slice = buf
93 .get(offset..end)
94 .ok_or_else(|| WireError::UnexpectedEof {
95 offset,
96 need: 2,
97 have: buf.len().saturating_sub(offset),
98 })?;
99 Ok(u16::from_le_bytes(
100 slice.try_into().expect("slice is exactly 2 bytes"),
101 ))
102}
103
104#[allow(clippy::missing_panics_doc)]
109#[inline]
110pub fn read_u32_le(buf: &[u8], offset: usize) -> Result<u32, WireError> {
111 let end = offset
112 .checked_add(4)
113 .ok_or_else(|| WireError::UnexpectedEof {
114 offset,
115 need: 4,
116 have: buf.len().saturating_sub(offset),
117 })?;
118 let slice = buf
119 .get(offset..end)
120 .ok_or_else(|| WireError::UnexpectedEof {
121 offset,
122 need: 4,
123 have: buf.len().saturating_sub(offset),
124 })?;
125 Ok(u32::from_le_bytes(
126 slice.try_into().expect("slice is exactly 4 bytes"),
127 ))
128}
129
130#[allow(clippy::missing_panics_doc)]
135#[inline]
136pub fn read_u64_le(buf: &[u8], offset: usize) -> Result<u64, WireError> {
137 let end = offset
138 .checked_add(8)
139 .ok_or_else(|| WireError::UnexpectedEof {
140 offset,
141 need: 8,
142 have: buf.len().saturating_sub(offset),
143 })?;
144 let slice = buf
145 .get(offset..end)
146 .ok_or_else(|| WireError::UnexpectedEof {
147 offset,
148 need: 8,
149 have: buf.len().saturating_sub(offset),
150 })?;
151 Ok(u64::from_le_bytes(
152 slice.try_into().expect("slice is exactly 8 bytes"),
153 ))
154}
155
156#[inline]
161pub fn read_str(buf: &[u8], offset: usize, len: usize) -> Result<String, WireError> {
162 let end = offset
163 .checked_add(len)
164 .ok_or_else(|| WireError::UnexpectedEof {
165 offset,
166 need: len,
167 have: buf.len().saturating_sub(offset),
168 })?;
169 let slice = buf
170 .get(offset..end)
171 .ok_or_else(|| WireError::UnexpectedEof {
172 offset,
173 need: len,
174 have: buf.len().saturating_sub(offset),
175 })?;
176 std::str::from_utf8(slice)
177 .map(str::to_string)
178 .map_err(|_| WireError::InvalidUtf8 { offset })
179}
180
181#[allow(clippy::missing_panics_doc)]
186#[inline]
187pub fn read_u128_le(buf: &[u8], offset: usize) -> Result<u128, WireError> {
188 let end = offset
189 .checked_add(16)
190 .ok_or_else(|| WireError::UnexpectedEof {
191 offset,
192 need: 16,
193 have: buf.len().saturating_sub(offset),
194 })?;
195 let slice = buf
196 .get(offset..end)
197 .ok_or_else(|| WireError::UnexpectedEof {
198 offset,
199 need: 16,
200 have: buf.len().saturating_sub(offset),
201 })?;
202 Ok(u128::from_le_bytes(
203 slice.try_into().expect("slice is exactly 16 bytes"),
204 ))
205}
206
207#[allow(clippy::missing_panics_doc)]
212#[inline]
213pub fn read_f32_le(buf: &[u8], offset: usize) -> Result<f32, WireError> {
214 let end = offset
215 .checked_add(4)
216 .ok_or_else(|| WireError::UnexpectedEof {
217 offset,
218 need: 4,
219 have: buf.len().saturating_sub(offset),
220 })?;
221 let slice = buf
222 .get(offset..end)
223 .ok_or_else(|| WireError::UnexpectedEof {
224 offset,
225 need: 4,
226 have: buf.len().saturating_sub(offset),
227 })?;
228 Ok(f32::from_le_bytes(
229 slice.try_into().expect("slice is exactly 4 bytes"),
230 ))
231}
232
233#[inline]
238pub fn read_bytes(buf: &[u8], offset: usize, len: usize) -> Result<&[u8], WireError> {
239 let end = offset
240 .checked_add(len)
241 .ok_or_else(|| WireError::UnexpectedEof {
242 offset,
243 need: len,
244 have: buf.len().saturating_sub(offset),
245 })?;
246 buf.get(offset..end)
247 .ok_or_else(|| WireError::UnexpectedEof {
248 offset,
249 need: len,
250 have: buf.len().saturating_sub(offset),
251 })
252}
253
254#[must_use]
268#[inline]
269pub fn bounded_capacity(count: usize, remaining: usize, min_element_size: usize) -> usize {
270 count.min(remaining / min_element_size.max(1))
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[test]
278 fn bounded_capacity_limits_allocation() {
279 assert_eq!(bounded_capacity(1_000_000, 100, 10), 10);
280 assert_eq!(bounded_capacity(5, 100, 10), 5);
281 assert_eq!(bounded_capacity(10, 100, 10), 10);
282 assert_eq!(bounded_capacity(11, 100, 10), 10);
283 assert_eq!(bounded_capacity(0, 100, 10), 0);
284 assert_eq!(bounded_capacity(100, 0, 10), 0);
285 }
286
287 #[test]
288 fn bounded_capacity_zero_element_size_still_bounds_by_the_buffer() {
289 assert_eq!(bounded_capacity(1_000_000, 100, 0), 100);
290 }
291}