use rawdb::likely;
use crate::{Error, Result, ValueStrategy};
use super::Page;
pub trait CompressionStrategy<T>: ValueStrategy<T> {
fn compress(values: &[T]) -> Result<Vec<u8>>;
fn decompress(bytes: &[u8], expected_len: usize) -> Result<Vec<T>>;
#[inline]
fn decompress_into(bytes: &[u8], expected_len: usize, dst: &mut Vec<T>) -> Result<()> {
*dst = Self::decompress(bytes, expected_len)?;
Ok(())
}
#[inline]
fn decompress_append(bytes: &[u8], expected_len: usize, dst: &mut Vec<T>) -> Result<()> {
let tmp = Self::decompress(bytes, expected_len)?;
dst.extend(tmp);
Ok(())
}
#[inline]
fn decode_page(data: &[u8], page: &Page) -> Result<Vec<T>> {
let n = page.values_count() as usize;
if page.is_raw() {
Self::bytes_to_values(data, n)
} else {
let vec = Self::decompress(data, n)?;
if likely(vec.len() == n) {
return Ok(vec);
}
Err(Error::DecompressionMismatch {
expected_len: n,
actual_len: vec.len(),
})
}
}
#[inline]
fn decode_page_into(data: &[u8], page: &Page, dst: &mut Vec<T>) -> Result<()> {
let n = page.values_count() as usize;
if page.is_raw() {
Self::bytes_to_values_into(data, n, dst)
} else {
Self::decompress_into(data, n, dst)
}
}
#[inline]
fn values_to_bytes(values: &[T]) -> Vec<u8> {
let byte_len = size_of_val(values);
let mut bytes = Vec::with_capacity(byte_len);
if Self::IS_NATIVE_LAYOUT {
unsafe {
std::ptr::copy_nonoverlapping(
values.as_ptr() as *const u8,
bytes.as_mut_ptr(),
byte_len,
);
bytes.set_len(byte_len);
}
} else {
for v in values {
Self::write_to_vec(v, &mut bytes);
}
}
bytes
}
#[inline]
fn bytes_to_values(bytes: &[u8], expected_len: usize) -> Result<Vec<T>> {
let mut vec = Vec::with_capacity(expected_len);
Self::bytes_to_values_into(bytes, expected_len, &mut vec)?;
Ok(vec)
}
#[inline]
fn bytes_to_values_into(bytes: &[u8], expected_len: usize, dst: &mut Vec<T>) -> Result<()> {
let expected_bytes = expected_len * size_of::<T>();
dst.clear();
dst.reserve(expected_len);
if Self::IS_NATIVE_LAYOUT {
if likely(bytes.len() >= expected_bytes) {
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
dst.as_mut_ptr() as *mut u8,
expected_bytes,
);
dst.set_len(expected_len);
}
return Ok(());
}
} else {
for chunk in bytes.chunks_exact(size_of::<T>()) {
dst.push(Self::read(chunk)?);
}
if likely(dst.len() == expected_len) {
return Ok(());
}
}
Err(Error::DecompressionMismatch {
expected_len,
actual_len: if Self::IS_NATIVE_LAYOUT {
bytes.len() / size_of::<T>()
} else {
dst.len()
},
})
}
}