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> {
18 let Ok(n) = usize::try_from(get_i16(buf)?) else {
19 return Err(ProtocolError::InvalidValue("non-nullable STRING was null"));
20 };
21 if buf.len() < n {
22 return Err(ProtocolError::UnexpectedEof {
23 needed: n - buf.len(),
24 });
25 }
26 let (head, tail) = buf.split_at(n);
27 *buf = tail;
28 str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
29}
30
31pub fn get_nullable_string_borrowed<'de>(
37 buf: &mut &'de [u8],
38) -> Result<Option<&'de str>, ProtocolError> {
39 let Ok(n) = usize::try_from(get_i16(buf)?) else {
41 return Ok(None);
42 };
43 if buf.len() < n {
44 return Err(ProtocolError::UnexpectedEof {
45 needed: n - buf.len(),
46 });
47 }
48 let (head, tail) = buf.split_at(n);
49 *buf = tail;
50 Ok(Some(
51 str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
52 ))
53}
54
55pub fn get_compact_string_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de str, ProtocolError> {
63 let raw = get_uvarint(buf)?;
64 if raw == 0 {
65 return Err(ProtocolError::InvalidValue(
66 "non-nullable COMPACT_STRING was null",
67 ));
68 }
69 let n = (raw - 1) as usize;
70 if buf.len() < n {
71 return Err(ProtocolError::UnexpectedEof {
72 needed: n - buf.len(),
73 });
74 }
75 let (head, tail) = buf.split_at(n);
76 *buf = tail;
77 str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
78}
79
80pub fn get_compact_nullable_string_borrowed<'de>(
83 buf: &mut &'de [u8],
84) -> Result<Option<&'de str>, ProtocolError> {
85 let raw = get_uvarint(buf)?;
86 if raw == 0 {
87 return Ok(None);
88 }
89 let n = (raw - 1) as usize;
90 if buf.len() < n {
91 return Err(ProtocolError::UnexpectedEof {
92 needed: n - buf.len(),
93 });
94 }
95 let (head, tail) = buf.split_at(n);
96 *buf = tail;
97 Ok(Some(
98 str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
99 ))
100}
101
102pub fn get_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
111 let Ok(n) = usize::try_from(get_i32(buf)?) else {
112 return Err(ProtocolError::InvalidValue("non-nullable BYTES was null"));
113 };
114 if buf.len() < n {
115 return Err(ProtocolError::UnexpectedEof {
116 needed: n - buf.len(),
117 });
118 }
119 let (head, tail) = buf.split_at(n);
120 *buf = tail;
121 Ok(head)
122}
123
124pub fn get_nullable_bytes_borrowed<'de>(
130 buf: &mut &'de [u8],
131) -> Result<Option<&'de [u8]>, ProtocolError> {
132 let Ok(n) = usize::try_from(get_i32(buf)?) else {
134 return Ok(None);
135 };
136 if buf.len() < n {
137 return Err(ProtocolError::UnexpectedEof {
138 needed: n - buf.len(),
139 });
140 }
141 let (head, tail) = buf.split_at(n);
142 *buf = tail;
143 Ok(Some(head))
144}
145
146pub fn get_compact_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
152 let raw = get_uvarint(buf)?;
153 if raw == 0 {
154 return Err(ProtocolError::InvalidValue(
155 "non-nullable COMPACT_BYTES was null",
156 ));
157 }
158 let n = (raw - 1) as usize;
159 if buf.len() < n {
160 return Err(ProtocolError::UnexpectedEof {
161 needed: n - buf.len(),
162 });
163 }
164 let (head, tail) = buf.split_at(n);
165 *buf = tail;
166 Ok(head)
167}
168
169pub fn get_compact_nullable_bytes_borrowed<'de>(
175 buf: &mut &'de [u8],
176) -> Result<Option<&'de [u8]>, ProtocolError> {
177 let raw = get_uvarint(buf)?;
178 if raw == 0 {
179 return Ok(None);
180 }
181 let n = (raw - 1) as usize;
182 if buf.len() < n {
183 return Err(ProtocolError::UnexpectedEof {
184 needed: n - buf.len(),
185 });
186 }
187 let (head, tail) = buf.split_at(n);
188 *buf = tail;
189 Ok(Some(head))
190}
191
192#[cfg(test)]
193mod tests {
194 use assert2::check;
195
196 use super::*;
197
198 #[test]
199 fn borrowed_decode_zero_copy() {
200 let bytes = [0x06u8, b'k', b'a', b'f', b'k', b'a'];
201 let mut cur: &[u8] = &bytes;
202 let s = get_compact_string_borrowed(&mut cur).unwrap();
203 assert2::assert!(s == "kafka");
204 let bytes_ptr = bytes.as_ptr() as usize;
206 let s_ptr = s.as_ptr() as usize;
207 assert2::assert!(s_ptr >= bytes_ptr && s_ptr < bytes_ptr + bytes.len());
208 }
209
210 #[test]
211 fn get_string_borrowed_roundtrip() {
212 let bytes = [0x00u8, 0x05, b'k', b'a', b'f', b'k', b'a'];
214 let mut cur: &[u8] = &bytes;
215 let s = get_string_borrowed(&mut cur).unwrap();
216 check!(s == "kafka");
217 check!(cur.is_empty());
218 check!(s.as_ptr() as usize >= bytes.as_ptr() as usize);
220 }
221
222 #[test]
223 fn get_string_borrowed_null_is_error() {
224 let bytes = [0xFFu8, 0xFF];
226 let mut cur: &[u8] = &bytes;
227 assert2::assert!(matches!(
228 get_string_borrowed(&mut cur),
229 Err(ProtocolError::InvalidValue(_))
230 ));
231 }
232
233 #[test]
234 fn get_nullable_string_borrowed_null() {
235 let bytes = [0xFFu8, 0xFF];
236 let mut cur: &[u8] = &bytes;
237 assert2::assert!(get_nullable_string_borrowed(&mut cur).unwrap() == None);
238 assert2::assert!(cur.is_empty());
239 }
240
241 #[test]
242 fn get_nullable_string_borrowed_some() {
243 let bytes = [0x00u8, 0x03, b'f', b'o', b'o'];
244 let mut cur: &[u8] = &bytes;
245 assert2::assert!(get_nullable_string_borrowed(&mut cur).unwrap() == Some("foo"));
246 assert2::assert!(cur.is_empty());
247 }
248
249 #[test]
250 fn get_bytes_borrowed_roundtrip() {
251 let bytes = [0x00u8, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03];
253 let mut cur: &[u8] = &bytes;
254 let b = get_bytes_borrowed(&mut cur).unwrap();
255 assert2::assert!(b == &[1u8, 2, 3]);
256 assert2::assert!(cur.is_empty());
257 }
258
259 #[test]
260 fn get_bytes_borrowed_null_is_error() {
261 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF]; let mut cur: &[u8] = &bytes;
263 assert2::assert!(matches!(
264 get_bytes_borrowed(&mut cur),
265 Err(ProtocolError::InvalidValue(_))
266 ));
267 }
268
269 #[test]
270 fn get_nullable_bytes_borrowed_null() {
271 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF];
272 let mut cur: &[u8] = &bytes;
273 assert2::assert!(get_nullable_bytes_borrowed(&mut cur).unwrap() == None);
274 }
275
276 #[test]
277 fn get_compact_bytes_borrowed_roundtrip() {
278 let bytes = [0x04u8, 0xAA, 0xBB, 0xCC];
280 let mut cur: &[u8] = &bytes;
281 let b = get_compact_bytes_borrowed(&mut cur).unwrap();
282 assert2::assert!(b == &[0xAAu8, 0xBB, 0xCC]);
283 assert2::assert!(cur.is_empty());
284 }
285
286 #[test]
287 fn get_compact_bytes_borrowed_null_is_error() {
288 let bytes = [0x00u8]; let mut cur: &[u8] = &bytes;
290 assert2::assert!(matches!(
291 get_compact_bytes_borrowed(&mut cur),
292 Err(ProtocolError::InvalidValue(_))
293 ));
294 }
295
296 #[test]
297 fn get_compact_nullable_bytes_borrowed_null() {
298 let bytes = [0x00u8];
299 let mut cur: &[u8] = &bytes;
300 assert2::assert!(get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == None);
301 }
302
303 #[test]
304 fn get_compact_nullable_bytes_borrowed_some() {
305 let bytes = [0x03u8, 0x01, 0x02];
307 let mut cur: &[u8] = &bytes;
308 assert2::assert!(
309 get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == Some(&[0x01u8, 0x02][..])
310 );
311 assert2::assert!(cur.is_empty());
312 }
313}