crabka_protocol/primitives/
string_bytes_borrowed.rs1use crate::ProtocolError;
2use crate::primitives::fixed::{get_i16, get_i32};
3use crate::primitives::varint::get_uvarint;
4
5pub fn get_string_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de str, ProtocolError> {
8 let len = get_i16(buf)?;
9 if len < 0 {
10 return Err(ProtocolError::InvalidValue("non-nullable STRING was null"));
11 }
12 #[allow(clippy::cast_sign_loss)]
13 let n = len as usize;
14 if buf.len() < n {
15 return Err(ProtocolError::UnexpectedEof {
16 needed: n - buf.len(),
17 });
18 }
19 let (head, tail) = buf.split_at(n);
20 *buf = tail;
21 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
22}
23
24pub fn get_nullable_string_borrowed<'de>(
26 buf: &mut &'de [u8],
27) -> Result<Option<&'de str>, ProtocolError> {
28 let len = get_i16(buf)?;
29 if len < 0 {
30 return Ok(None);
31 }
32 #[allow(clippy::cast_sign_loss)]
33 let n = len as usize;
34 if buf.len() < n {
35 return Err(ProtocolError::UnexpectedEof {
36 needed: n - buf.len(),
37 });
38 }
39 let (head, tail) = buf.split_at(n);
40 *buf = tail;
41 Ok(Some(
42 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
43 ))
44}
45
46pub fn get_compact_string_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de str, ProtocolError> {
49 let raw = get_uvarint(buf)?;
50 if raw == 0 {
51 return Err(ProtocolError::InvalidValue(
52 "non-nullable COMPACT_STRING was null",
53 ));
54 }
55 let n = (raw - 1) as usize;
56 if buf.len() < n {
57 return Err(ProtocolError::UnexpectedEof {
58 needed: n - buf.len(),
59 });
60 }
61 let (head, tail) = buf.split_at(n);
62 *buf = tail;
63 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)
64}
65
66pub fn get_compact_nullable_string_borrowed<'de>(
67 buf: &mut &'de [u8],
68) -> Result<Option<&'de str>, ProtocolError> {
69 let raw = get_uvarint(buf)?;
70 if raw == 0 {
71 return Ok(None);
72 }
73 let n = (raw - 1) as usize;
74 if buf.len() < n {
75 return Err(ProtocolError::UnexpectedEof {
76 needed: n - buf.len(),
77 });
78 }
79 let (head, tail) = buf.split_at(n);
80 *buf = tail;
81 Ok(Some(
82 std::str::from_utf8(head).map_err(ProtocolError::InvalidUtf8)?,
83 ))
84}
85
86pub fn get_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
89 let len = get_i32(buf)?;
90 if len < 0 {
91 return Err(ProtocolError::InvalidValue("non-nullable BYTES was null"));
92 }
93 #[allow(clippy::cast_sign_loss)]
94 let n = len as usize;
95 if buf.len() < n {
96 return Err(ProtocolError::UnexpectedEof {
97 needed: n - buf.len(),
98 });
99 }
100 let (head, tail) = buf.split_at(n);
101 *buf = tail;
102 Ok(head)
103}
104
105pub fn get_nullable_bytes_borrowed<'de>(
107 buf: &mut &'de [u8],
108) -> Result<Option<&'de [u8]>, ProtocolError> {
109 let len = get_i32(buf)?;
110 if len < 0 {
111 return Ok(None);
112 }
113 #[allow(clippy::cast_sign_loss)]
114 let n = len as usize;
115 if buf.len() < n {
116 return Err(ProtocolError::UnexpectedEof {
117 needed: n - buf.len(),
118 });
119 }
120 let (head, tail) = buf.split_at(n);
121 *buf = tail;
122 Ok(Some(head))
123}
124
125pub fn get_compact_bytes_borrowed<'de>(buf: &mut &'de [u8]) -> Result<&'de [u8], ProtocolError> {
127 let raw = get_uvarint(buf)?;
128 if raw == 0 {
129 return Err(ProtocolError::InvalidValue(
130 "non-nullable COMPACT_BYTES was null",
131 ));
132 }
133 let n = (raw - 1) as usize;
134 if buf.len() < n {
135 return Err(ProtocolError::UnexpectedEof {
136 needed: n - buf.len(),
137 });
138 }
139 let (head, tail) = buf.split_at(n);
140 *buf = tail;
141 Ok(head)
142}
143
144pub fn get_compact_nullable_bytes_borrowed<'de>(
146 buf: &mut &'de [u8],
147) -> Result<Option<&'de [u8]>, ProtocolError> {
148 let raw = get_uvarint(buf)?;
149 if raw == 0 {
150 return Ok(None);
151 }
152 let n = (raw - 1) as usize;
153 if buf.len() < n {
154 return Err(ProtocolError::UnexpectedEof {
155 needed: n - buf.len(),
156 });
157 }
158 let (head, tail) = buf.split_at(n);
159 *buf = tail;
160 Ok(Some(head))
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166 use assert2::assert;
167
168 #[test]
169 fn borrowed_decode_zero_copy() {
170 let bytes = [0x06u8, b'k', b'a', b'f', b'k', b'a'];
171 let mut cur: &[u8] = &bytes;
172 let s = get_compact_string_borrowed(&mut cur).unwrap();
173 assert!(s == "kafka");
174 let bytes_ptr = bytes.as_ptr() as usize;
176 let s_ptr = s.as_ptr() as usize;
177 assert!(s_ptr >= bytes_ptr && s_ptr < bytes_ptr + bytes.len());
178 }
179
180 #[test]
181 fn get_string_borrowed_roundtrip() {
182 let bytes = [0x00u8, 0x05, b'k', b'a', b'f', b'k', b'a'];
184 let mut cur: &[u8] = &bytes;
185 let s = get_string_borrowed(&mut cur).unwrap();
186 assert!(s == "kafka");
187 assert!(cur.is_empty());
188 assert!(s.as_ptr() as usize >= bytes.as_ptr() as usize);
190 }
191
192 #[test]
193 fn get_string_borrowed_null_is_error() {
194 let bytes = [0xFFu8, 0xFF];
196 let mut cur: &[u8] = &bytes;
197 assert!(matches!(
198 get_string_borrowed(&mut cur),
199 Err(ProtocolError::InvalidValue(_))
200 ));
201 }
202
203 #[test]
204 fn get_nullable_string_borrowed_null() {
205 let bytes = [0xFFu8, 0xFF];
206 let mut cur: &[u8] = &bytes;
207 assert!(get_nullable_string_borrowed(&mut cur).unwrap() == None);
208 assert!(cur.is_empty());
209 }
210
211 #[test]
212 fn get_nullable_string_borrowed_some() {
213 let bytes = [0x00u8, 0x03, b'f', b'o', b'o'];
214 let mut cur: &[u8] = &bytes;
215 assert!(get_nullable_string_borrowed(&mut cur).unwrap() == Some("foo"));
216 assert!(cur.is_empty());
217 }
218
219 #[test]
220 fn get_bytes_borrowed_roundtrip() {
221 let bytes = [0x00u8, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03];
223 let mut cur: &[u8] = &bytes;
224 let b = get_bytes_borrowed(&mut cur).unwrap();
225 assert!(b == &[1u8, 2, 3]);
226 assert!(cur.is_empty());
227 }
228
229 #[test]
230 fn get_bytes_borrowed_null_is_error() {
231 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF]; let mut cur: &[u8] = &bytes;
233 assert!(matches!(
234 get_bytes_borrowed(&mut cur),
235 Err(ProtocolError::InvalidValue(_))
236 ));
237 }
238
239 #[test]
240 fn get_nullable_bytes_borrowed_null() {
241 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF];
242 let mut cur: &[u8] = &bytes;
243 assert!(get_nullable_bytes_borrowed(&mut cur).unwrap() == None);
244 }
245
246 #[test]
247 fn get_compact_bytes_borrowed_roundtrip() {
248 let bytes = [0x04u8, 0xAA, 0xBB, 0xCC];
250 let mut cur: &[u8] = &bytes;
251 let b = get_compact_bytes_borrowed(&mut cur).unwrap();
252 assert!(b == &[0xAAu8, 0xBB, 0xCC]);
253 assert!(cur.is_empty());
254 }
255
256 #[test]
257 fn get_compact_bytes_borrowed_null_is_error() {
258 let bytes = [0x00u8]; let mut cur: &[u8] = &bytes;
260 assert!(matches!(
261 get_compact_bytes_borrowed(&mut cur),
262 Err(ProtocolError::InvalidValue(_))
263 ));
264 }
265
266 #[test]
267 fn get_compact_nullable_bytes_borrowed_null() {
268 let bytes = [0x00u8];
269 let mut cur: &[u8] = &bytes;
270 assert!(get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == None);
271 }
272
273 #[test]
274 fn get_compact_nullable_bytes_borrowed_some() {
275 let bytes = [0x03u8, 0x01, 0x02];
277 let mut cur: &[u8] = &bytes;
278 assert!(
279 get_compact_nullable_bytes_borrowed(&mut cur).unwrap() == Some(&[0x01u8, 0x02][..])
280 );
281 assert!(cur.is_empty());
282 }
283}