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
167 #[test]
168 fn borrowed_decode_zero_copy() {
169 let bytes = [0x06u8, b'k', b'a', b'f', b'k', b'a'];
170 let mut cur: &[u8] = &bytes;
171 let s = get_compact_string_borrowed(&mut cur).unwrap();
172 assert_eq!(s, "kafka");
173 let bytes_ptr = bytes.as_ptr() as usize;
175 let s_ptr = s.as_ptr() as usize;
176 assert!(s_ptr >= bytes_ptr && s_ptr < bytes_ptr + bytes.len());
177 }
178
179 #[test]
180 fn get_string_borrowed_roundtrip() {
181 let bytes = [0x00u8, 0x05, b'k', b'a', b'f', b'k', b'a'];
183 let mut cur: &[u8] = &bytes;
184 let s = get_string_borrowed(&mut cur).unwrap();
185 assert_eq!(s, "kafka");
186 assert!(cur.is_empty());
187 assert!(s.as_ptr() as usize >= bytes.as_ptr() as usize);
189 }
190
191 #[test]
192 fn get_string_borrowed_null_is_error() {
193 let bytes = [0xFFu8, 0xFF];
195 let mut cur: &[u8] = &bytes;
196 assert!(matches!(
197 get_string_borrowed(&mut cur),
198 Err(ProtocolError::InvalidValue(_))
199 ));
200 }
201
202 #[test]
203 fn get_nullable_string_borrowed_null() {
204 let bytes = [0xFFu8, 0xFF];
205 let mut cur: &[u8] = &bytes;
206 assert_eq!(get_nullable_string_borrowed(&mut cur).unwrap(), None);
207 assert!(cur.is_empty());
208 }
209
210 #[test]
211 fn get_nullable_string_borrowed_some() {
212 let bytes = [0x00u8, 0x03, b'f', b'o', b'o'];
213 let mut cur: &[u8] = &bytes;
214 assert_eq!(get_nullable_string_borrowed(&mut cur).unwrap(), Some("foo"));
215 assert!(cur.is_empty());
216 }
217
218 #[test]
219 fn get_bytes_borrowed_roundtrip() {
220 let bytes = [0x00u8, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03];
222 let mut cur: &[u8] = &bytes;
223 let b = get_bytes_borrowed(&mut cur).unwrap();
224 assert_eq!(b, &[1u8, 2, 3]);
225 assert!(cur.is_empty());
226 }
227
228 #[test]
229 fn get_bytes_borrowed_null_is_error() {
230 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF]; let mut cur: &[u8] = &bytes;
232 assert!(matches!(
233 get_bytes_borrowed(&mut cur),
234 Err(ProtocolError::InvalidValue(_))
235 ));
236 }
237
238 #[test]
239 fn get_nullable_bytes_borrowed_null() {
240 let bytes = [0xFFu8, 0xFF, 0xFF, 0xFF];
241 let mut cur: &[u8] = &bytes;
242 assert_eq!(get_nullable_bytes_borrowed(&mut cur).unwrap(), None);
243 }
244
245 #[test]
246 fn get_compact_bytes_borrowed_roundtrip() {
247 let bytes = [0x04u8, 0xAA, 0xBB, 0xCC];
249 let mut cur: &[u8] = &bytes;
250 let b = get_compact_bytes_borrowed(&mut cur).unwrap();
251 assert_eq!(b, &[0xAAu8, 0xBB, 0xCC]);
252 assert!(cur.is_empty());
253 }
254
255 #[test]
256 fn get_compact_bytes_borrowed_null_is_error() {
257 let bytes = [0x00u8]; let mut cur: &[u8] = &bytes;
259 assert!(matches!(
260 get_compact_bytes_borrowed(&mut cur),
261 Err(ProtocolError::InvalidValue(_))
262 ));
263 }
264
265 #[test]
266 fn get_compact_nullable_bytes_borrowed_null() {
267 let bytes = [0x00u8];
268 let mut cur: &[u8] = &bytes;
269 assert_eq!(get_compact_nullable_bytes_borrowed(&mut cur).unwrap(), None);
270 }
271
272 #[test]
273 fn get_compact_nullable_bytes_borrowed_some() {
274 let bytes = [0x03u8, 0x01, 0x02];
276 let mut cur: &[u8] = &bytes;
277 assert_eq!(
278 get_compact_nullable_bytes_borrowed(&mut cur).unwrap(),
279 Some(&[0x01u8, 0x02][..])
280 );
281 assert!(cur.is_empty());
282 }
283}