Skip to content

Commit 3101d37

Browse files
committed
Add a fast path for primitive slices to all arrays
1 parent c8472c7 commit 3101d37

File tree

4 files changed

+75
-1
lines changed

4 files changed

+75
-1
lines changed

gel-db-protocol/src/arrays.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ mod tests {
315315
let mut buf = &data[..];
316316
let result = Array::<u32, u32>::decode_for(&mut buf);
317317
assert!(result.is_err());
318+
319+
let mut buf = [].as_slice();
320+
let result = Array::<u32, u32>::decode_for(&mut buf);
321+
assert!(result.is_err());
318322
}
319323

320324
#[test]
@@ -334,6 +338,19 @@ mod tests {
334338
assert_eq!(collected, vec![1, 2, 3]);
335339
}
336340

341+
#[test]
342+
fn test_zt_array_u32() {
343+
// Unlikely, but helps test our primitive fast path
344+
let data = vec![0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0];
345+
346+
let mut buf = &data[..];
347+
let array = ZTArray::<u32>::decode_for(&mut buf).unwrap();
348+
349+
assert_eq!(array.len(), 2);
350+
assert!(!array.is_empty());
351+
assert_eq!(buf.len(), 0);
352+
}
353+
337354
#[test]
338355
fn test_zt_array_string() {
339356
let data = vec![
@@ -359,6 +376,12 @@ mod tests {
359376
let mut buf = &data[..];
360377
let result = ZTArray::<u8>::decode_for(&mut buf);
361378
assert!(result.is_err());
379+
380+
// Test with empty arrays
381+
let mut buf = [].as_slice();
382+
assert!(ZTArray::<u8>::decode_for(&mut buf).is_err());
383+
assert!(ZTArray::<u32>::decode_for(&mut buf).is_err());
384+
assert!(ZTArray::<ZTString>::decode_for(&mut buf).is_err());
362385
}
363386

364387
#[test]

gel-db-protocol/src/encoding.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,16 @@ where
152152
fn decode_for(buf: &mut &'a [u8]) -> Result<Self, ParseError> {
153153
let len = L::decode_usize(buf)?;
154154
let orig_buf = *buf;
155+
// Primitive types can skip the decode_for call.
156+
if T::META.is_primitive {
157+
let constant_size = T::META.constant_size.unwrap();
158+
let byte_len = constant_size.saturating_mul(len);
159+
if buf.len() < byte_len {
160+
return Err(ParseError::TooShort);
161+
}
162+
*buf = &buf[byte_len..];
163+
return Ok(Array::new(&orig_buf[..byte_len], len as _));
164+
}
155165
for _ in 0..len {
156166
T::decode_for(buf)?;
157167
}
@@ -189,6 +199,25 @@ where
189199
fn decode_for(buf: &mut &'a [u8]) -> Result<Self, ParseError> {
190200
let mut orig_buf = *buf;
191201
let mut len = 0;
202+
203+
// Primitive types can skip the decode_for call and hunt for the 0 byte.
204+
if T::META.is_primitive {
205+
let constant_size = T::META.constant_size.unwrap();
206+
loop {
207+
if buf.is_empty() {
208+
return Err(ParseError::TooShort);
209+
}
210+
if buf[0] == 0 {
211+
break;
212+
}
213+
*buf = &buf[constant_size..];
214+
len += 1;
215+
}
216+
*buf = &buf[1..];
217+
orig_buf = &orig_buf[0..orig_buf.len() - buf.len() - 1];
218+
return Ok(ZTArray::new(&orig_buf, len));
219+
}
220+
192221
loop {
193222
if buf.is_empty() {
194223
return Err(crate::prelude::ParseError::TooShort);
@@ -233,6 +262,17 @@ where
233262
{
234263
fn decode_for(buf: &mut &'a [u8]) -> Result<Self, ParseError> {
235264
let orig_buf = *buf;
265+
// Primitive types can skip the decode_for call and compute the number of elements
266+
// until the end of the buffer.
267+
if T::META.is_primitive {
268+
let constant_size = T::META.constant_size.unwrap();
269+
let len = buf.len() / constant_size;
270+
if buf.len() % constant_size != 0 {
271+
return Err(ParseError::TooShort);
272+
}
273+
*buf = &[];
274+
return Ok(RestArray::new(orig_buf, len as _));
275+
}
236276
let mut len = 0;
237277
while !buf.is_empty() {
238278
T::decode_for(buf)?;
@@ -542,10 +582,12 @@ declare_type!(u8);
542582
declare_type!(u16);
543583
declare_type!(u32);
544584
declare_type!(u64);
585+
declare_type!(u128);
545586
declare_type!(i8);
546587
declare_type!(i16);
547588
declare_type!(i32);
548589
declare_type!(i64);
590+
declare_type!(i128);
549591

550592
declare_type!(f32);
551593
declare_type!(f64);

gel-db-protocol/src/macros.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ macro_rules! declare_type {
44
// Primitive types (no lifetime, fixed size)
55
($ty:ident) =>
66
{
7-
$crate::declare_type!($crate::prelude::DataType, $ty, {
7+
$crate::declare_type!($crate::prelude::DataType, $ty, flags=[primitive], {
88
fn to_usize(value: usize) -> $ty {
99
value as $ty
1010
}

gel-db-protocol/src/structs.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub struct StructFieldMeta {
6262
pub is_enum: bool,
6363
pub is_struct: bool,
6464
pub is_array: bool,
65+
pub is_primitive: bool,
6566
}
6667

6768
impl StructFieldMeta {
@@ -73,6 +74,7 @@ impl StructFieldMeta {
7374
is_enum: false,
7475
is_struct: false,
7576
is_array: false,
77+
is_primitive: false,
7678
}
7779
}
7880

@@ -103,6 +105,13 @@ impl StructFieldMeta {
103105
..self
104106
}
105107
}
108+
109+
pub const fn set_primitive(self) -> Self {
110+
Self {
111+
is_primitive: true,
112+
..self
113+
}
114+
}
106115
}
107116

108117
#[derive(Clone, Copy, Debug)]

0 commit comments

Comments
 (0)