krabka_protocol/primitives/
string_bytes_borrowed.rs1use crate::{
2 ProtocolError,
3 primitives::{
4 fixed::{get_i16, get_i32},
5 varint::get_uvarint,
6 },
7};
8
9pub fn get_string_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de str, ProtocolError> {
20 let len = get_i16(buf)?;
21 if len < 0 {
22 return Err(ProtocolError::InvalidValue("non-nullable STRING was null"));
23 }
24 let n = usize::try_from(len).expect("non-negative string length must fit in usize");
25 if buf.len() < n {
26 return Err(ProtocolError::UnexpectedEof {
27 needed: n - buf.len(),
28 });
29 }
30 let (head, tail) = buf.split_at(n);
31 *buf = tail;
32 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
33}
34
35pub fn get_nullable_string_borrowed<'de>(
43 buf: &mut &'de [u8],
44) -> Result<Option<&'de str>, ProtocolError> {
45 let len = get_i16(buf)?;
46 if len < 0 {
47 return Ok(None);
48 }
49 let n = usize::try_from(len).expect("non-negative string length must fit in usize");
50 if buf.len() < n {
51 return Err(ProtocolError::UnexpectedEof {
52 needed: n - buf.len(),
53 });
54 }
55 let (head, tail) = buf.split_at(n);
56 *buf = tail;
57 Ok(Some(
58 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
59 ))
60}
61
62pub fn get_compact_string_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de str, ProtocolError> {
70 let raw = get_uvarint(buf)?;
71 if raw == 0 {
72 return Err(ProtocolError::InvalidValue(
73 "non-nullable COMPACT_STRING was null",
74 ));
75 }
76 let n = (raw - 1) as usize;
77 if buf.len() < n {
78 return Err(ProtocolError::UnexpectedEof {
79 needed: n - buf.len(),
80 });
81 }
82 let (head, tail) = buf.split_at(n);
83 *buf = tail;
84 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
85}
86
87pub fn get_compact_nullable_string_borrowed<'de>(
90 buf: &mut &'de [u8],
91) -> Result<Option<&'de str>, ProtocolError> {
92 let raw = get_uvarint(buf)?;
93 if raw == 0 {
94 return Ok(None);
95 }
96 let n = (raw - 1) as usize;
97 if buf.len() < n {
98 return Err(ProtocolError::UnexpectedEof {
99 needed: n - buf.len(),
100 });
101 }
102 let (head, tail) = buf.split_at(n);
103 *buf = tail;
104 Ok(Some(
105 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
106 ))
107}
108
109pub fn get_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
120 let len = get_i32(buf)?;
121 if len < 0 {
122 return Err(ProtocolError::InvalidValue("non-nullable BYTES was null"));
123 }
124 let n = usize::try_from(len).expect("non-negative bytes length must fit in usize");
125 if buf.len() < n {
126 return Err(ProtocolError::UnexpectedEof {
127 needed: n - buf.len(),
128 });
129 }
130 let (head, tail) = buf.split_at(n);
131 *buf = tail;
132 Ok(head)
133}
134
135pub fn get_nullable_bytes_borrowed<'de>(
143 buf: &mut &'de [u8],
144) -> Result<Option<&'de [u8]>, ProtocolError> {
145 let len = get_i32(buf)?;
146 if len < 0 {
147 return Ok(None);
148 }
149 let n = usize::try_from(len).expect("non-negative bytes length must fit in usize");
150 if buf.len() < n {
151 return Err(ProtocolError::UnexpectedEof {
152 needed: n - buf.len(),
153 });
154 }
155 let (head, tail) = buf.split_at(n);
156 *buf = tail;
157 Ok(Some(head))
158}
159
160pub fn get_compact_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
166 let raw = get_uvarint(buf)?;
167 if raw == 0 {
168 return Err(ProtocolError::InvalidValue(
169 "non-nullable COMPACT_BYTES was null",
170 ));
171 }
172 let n = (raw - 1) as usize;
173 if buf.len() < n {
174 return Err(ProtocolError::UnexpectedEof {
175 needed: n - buf.len(),
176 });
177 }
178 let (head, tail) = buf.split_at(n);
179 *buf = tail;
180 Ok(head)
181}
182
183pub fn get_compact_nullable_bytes_borrowed<'de>(
189 buf: &mut &'de [u8],
190) -> Result<Option<&'de [u8]>, ProtocolError> {
191 let raw = get_uvarint(buf)?;
192 if raw == 0 {
193 return Ok(None);
194 }
195 let n = (raw - 1) as usize;
196 if buf.len() < n {
197 return Err(ProtocolError::UnexpectedEof {
198 needed: n - buf.len(),
199 });
200 }
201 let (head, tail) = buf.split_at(n);
202 *buf = tail;
203 Ok(Some(head))
204}
205
206#[cfg(test)]
207mod tests {
208 use assert2::check;
209
210 use super::*;
211
212 #[test]
213 fn borrowed_decode_zero_copy() {
214 let bytes = [0x06u8, b'k', b'a', b'f', b'k', b'a'];
215 let mut cur: &[u8] = &bytes;
216 let s = get_compact_string_borrowed(&mut cur).unwrap();
217 assert2::assert!(s == "kafka");
218 let bytes_ptr = bytes.as_ptr() as usize;
220 let s_ptr = s.as_ptr() as usize;
221 assert2::assert!(s_ptr >= bytes_ptr && s_ptr < bytes_ptr + bytes.len());
222 }
223
224 #[test]
225 fn get_string_borrowed_roundtrip() {
226 let bytes = [0x00u8, 0x05, b'k', b'a', b'f', b'k', b'a'];
228 let mut cur: &[u8] = &bytes;
229 let s = get_string_borrowed(&mut cur).unwrap();
230 check!(s == "kafka");
231 check!(cur.is_empty());
232 check!(s.as_ptr() as usize >= bytes.as_ptr() as usize);
234 }
235
236 #[test]
237 fn get_string_borrowed_null_is_error() {
238 let bytes = [0xFFu8, 0xFF];
240 let mut cur: &[u8] = &bytes;
241 assert2::assert!(matches!(
242 get_string_borrowed(&mut cur),
243 Err(ProtocolError::InvalidValue(_))
244 ));
245 }
246
247 #[test]
248 fn get_nullable_string_borrowed_null() {
249 let bytes = [0xFFu8, 0xFF];
250 let mut cur: &[u8] = &bytes;
251 assert2::assert!(get_nullable_string_borrowed(&mut cur).unwrap() == None);
252 assert2::assert!(cur.is_empty());
253 }
254
255 #[test]
256 fn get_nullable_string_borrowed_some() {
257 let bytes = [0x00u8, 0x03, b'f', b'o', b'o'];
258 let mut cur: &[u8] = &bytes;
259 assert2::assert!(get_nullable_string_borrowed(&mut cur).unwrap() == Some("foo"));
260 assert2::assert!(cur.is_empty());
261 }
262
263 #[test]
264 fn get_bytes_borrowed_roundtrip() {
265 let bytes = [0x00u8, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03];
267 let mut cur: &[u8] = &bytes;
268 let b = get_bytes_borrowed(&mut cur).unwrap();
269 assert2::assert!(b == &[1u8, 2, 3]);
270 assert2::assert!(cur.is_empty());
271 }
272
273 #[test]
274 fn get_bytes_borrowed_null_is_error() {
275 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF]; let mut cur: &[u8] = &bytes;
277 assert2::assert!(matches!(
278 get_bytes_borrowed(&mut cur),
279 Err(ProtocolError::InvalidValue(_))
280 ));
281 }
282
283 #[test]
284 fn get_nullable_bytes_borrowed_null() {
285 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF];
286 let mut cur: &[u8] = &bytes;
287 assert2::assert!(get_nullable_bytes_borrowed(&mut cur).unwrap() == None);
288 }
289
290 #[test]
291 fn get_compact_bytes_borrowed_roundtrip() {
292 let bytes = [0x04u8, 0xAA, 0xBB, 0xCC];
294 let mut cur: &[u8] = &bytes;
295 let b = get_compact_bytes_borrowed(&mut cur).unwrap();
296 assert2::assert!(b == &[0xAAu8, 0xBB, 0xCC]);
297 assert2::assert!(cur.is_empty());
298 }
299
300 #[test]
301 fn get_compact_bytes_borrowed_null_is_error() {
302 let bytes = [0x00u8]; let mut cur: &[u8] = &bytes;
304 assert2::assert!(matches!(
305 get_compact_bytes_borrowed(&mut cur),
306 Err(ProtocolError::InvalidValue(_))
307 ));
308 }
309
310 #[test]
311 fn get_compact_nullable_bytes_borrowed_null() {
312 let bytes = [0x00u8];
313 let mut cur: &[u8] = &bytes;
314 assert2::assert!(get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == None);
315 }
316
317 #[test]
318 fn get_compact_nullable_bytes_borrowed_some() {
319 let bytes = [0x03u8, 0x01, 0x02];
321 let mut cur: &[u8] = &bytes;
322 assert2::assert!(
323 get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == Some(&[0x01u8, 0x02][..])
324 );
325 assert2::assert!(cur.is_empty());
326 }
327}