pub(crate) const MAX_FIX_PART_DATA_SIZE: usize = 7;
pub(crate) fn round_to_nearest_word(num_bytes: usize) -> usize {
let remainder = num_bytes & 0x07;
if remainder == 0 {
num_bytes
} else {
num_bytes + (8 - remainder)
}
}
pub(crate) fn pack_offset_and_size(offset: usize, size: u64) -> i64 {
((offset as i64) << 32) | (size as i64)
}
pub(crate) fn pack_inline_bytes(bytes: &[u8]) -> i64 {
debug_assert!(bytes.len() <= MAX_FIX_PART_DATA_SIZE);
let first_byte = (bytes.len() as u64) | 0x80;
let mut seven_bytes = 0_u64;
for (i, b) in bytes.iter().enumerate() {
seven_bytes |= (*b as u64) << (i * 8);
}
((first_byte << 56) | seven_bytes) as i64
}
const NON_COMPACT_DECIMAL_LEN: usize = 16;
pub(crate) fn append_non_compact_decimal(
buffer: &mut Vec<u8>,
cursor: &mut usize,
unscaled: &[u8],
) -> i64 {
debug_assert!(unscaled.len() <= NON_COMPACT_DECIMAL_LEN);
let at = *cursor;
let end = at + NON_COMPACT_DECIMAL_LEN;
ensure_len(buffer, end);
buffer[at..end].fill(0);
buffer[at..at + unscaled.len()].copy_from_slice(unscaled);
*cursor = end;
pack_offset_and_size(at, unscaled.len() as u64)
}
const NON_COMPACT_TIMESTAMP_LEN: usize = 8;
pub(crate) fn append_non_compact_timestamp(
buffer: &mut Vec<u8>,
cursor: &mut usize,
millis: i64,
nano_of_millisecond: i32,
) -> i64 {
let at = *cursor;
ensure_len(buffer, at + NON_COMPACT_TIMESTAMP_LEN);
buffer[at..at + NON_COMPACT_TIMESTAMP_LEN].copy_from_slice(&millis.to_le_bytes());
*cursor = at + NON_COMPACT_TIMESTAMP_LEN;
pack_offset_and_size(at, nano_of_millisecond as u64)
}
pub(crate) fn pack_or_append_bytes(buffer: &mut Vec<u8>, cursor: &mut usize, bytes: &[u8]) -> i64 {
if bytes.len() <= MAX_FIX_PART_DATA_SIZE {
pack_inline_bytes(bytes)
} else {
append_var_len(buffer, cursor, bytes)
}
}
pub(crate) fn ensure_len(buffer: &mut Vec<u8>, len: usize) {
if buffer.len() < len {
buffer.resize(len, 0);
}
}
pub(crate) fn append_var_len(buffer: &mut Vec<u8>, cursor: &mut usize, bytes: &[u8]) -> i64 {
let len = bytes.len();
let rounded = round_to_nearest_word(len);
let at = *cursor;
ensure_len(buffer, at + rounded);
buffer[at + len..at + rounded].fill(0);
buffer[at..at + len].copy_from_slice(bytes);
*cursor = at + rounded;
pack_offset_and_size(at, len as u64)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rounds_up_to_whole_words() {
assert_eq!(round_to_nearest_word(0), 0);
assert_eq!(round_to_nearest_word(1), 8);
assert_eq!(round_to_nearest_word(8), 8);
assert_eq!(round_to_nearest_word(9), 16);
}
#[test]
fn packs_an_offset_and_size_into_the_two_halves() {
let packed = pack_offset_and_size(32, 11);
assert_eq!((packed >> 32) as usize, 32);
assert_eq!((packed & 0xFFFF_FFFF) as usize, 11);
}
#[test]
fn inlines_bytes_with_the_length_marker_on_top() {
let packed = pack_inline_bytes(b"abc");
let slot = packed.to_le_bytes();
assert_eq!(&slot[..3], b"abc");
assert_eq!(slot[7], 0x83);
}
#[test]
fn a_non_compact_decimal_always_takes_sixteen_bytes() {
let mut buffer = vec![0xFF; 8];
let mut cursor = 8;
let slot = append_non_compact_decimal(&mut buffer, &mut cursor, &[1, 2, 3]);
assert_eq!((slot >> 32) as usize, 8);
assert_eq!((slot & 0xFFFF_FFFF) as usize, 3);
assert_eq!(cursor, 24);
assert_eq!(&buffer[8..11], &[1, 2, 3]);
assert_eq!(&buffer[11..24], &[0u8; 13]);
}
#[test]
fn append_zeroes_the_padding_of_a_partial_word() {
let mut buffer = vec![0xFF; 8];
let mut cursor = 8;
let slot = append_var_len(&mut buffer, &mut cursor, b"abcdefghij");
assert_eq!((slot >> 32) as usize, 8);
assert_eq!((slot & 0xFFFF_FFFF) as usize, 10);
assert_eq!(&buffer[8..18], b"abcdefghij");
assert_eq!(&buffer[18..24], &[0u8; 6]);
assert_eq!(cursor, 24);
}
#[test]
fn ensure_len_only_grows() {
let mut buffer = vec![1, 2, 3];
ensure_len(&mut buffer, 2);
assert_eq!(buffer, vec![1, 2, 3]);
ensure_len(&mut buffer, 5);
assert_eq!(buffer, vec![1, 2, 3, 0, 0]);
}
}