use std::fmt::Debug;
use std::marker::PhantomData;
use zerocopy::little_endian::U32;
use crate::posting_list::{SizedValue, UnsizedValue};
pub trait PostingValue: Clone {
type Handler: ValueHandler<Value = Self>;
}
impl PostingValue for () {
type Handler = SizedHandler<()>;
}
impl PostingValue for u32 {
type Handler = SizedHandler<u32>;
}
impl PostingValue for u64 {
type Handler = SizedHandler<u64>;
}
pub trait ValueHandler {
type Value;
type Sized: std::marker::Sized + Copy + Debug;
fn process_values(values: Vec<Self::Value>) -> (Vec<Self::Sized>, Vec<u8>);
fn get_value<N>(sized_value: Self::Sized, next_sized_value: N, var_data: &[u8]) -> Self::Value
where
N: Fn() -> Option<Self::Sized>;
}
#[derive(Default, Debug, Clone, Copy)]
pub struct SizedHandler<V: SizedValue>(PhantomData<V>);
impl<V: SizedValue> ValueHandler for SizedHandler<V> {
type Value = V;
type Sized = V;
fn process_values(values: Vec<V>) -> (Vec<V>, Vec<u8>) {
(values, Vec::new())
}
fn get_value<N>(sized_value: V, _next_sized_value: N, _var_data: &[u8]) -> V
where
N: Fn() -> Option<Self::Sized>,
{
sized_value
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct UnsizedHandler<V: UnsizedValue>(PhantomData<V>);
impl<V: UnsizedValue> ValueHandler for UnsizedHandler<V> {
type Value = V;
type Sized = U32;
fn process_values(values: Vec<Self::Value>) -> (Vec<Self::Sized>, Vec<u8>) {
let mut offsets = Vec::with_capacity(values.len());
let mut current_offset = 0u32;
for value in &values {
offsets.push(U32::from(current_offset));
let value_len = u32::try_from(value.write_len())
.expect("Value larger than 4GB, use u64 offsets instead");
current_offset = current_offset
.checked_add(value_len)
.expect("Size of all values exceeds 4GB");
}
let last_offset = offsets.last();
let ranges = offsets
.array_windows()
.map(|[a, b]| a.get() as usize..b.get() as usize)
.chain(last_offset.map(|&last| last.get() as usize..current_offset as usize));
let mut var_sized_data = vec![0; current_offset as usize];
for (value, range) in values.iter().zip(ranges) {
value.write_to(&mut var_sized_data[range]);
}
(offsets, var_sized_data)
}
fn get_value<N>(sized_value: Self::Sized, next_sized_value: N, var_data: &[u8]) -> Self::Value
where
N: Fn() -> Option<Self::Sized>,
{
let range = match next_sized_value() {
Some(next_value) => sized_value.get() as usize..next_value.get() as usize,
None => sized_value.get() as usize..var_data.len(),
};
V::from_bytes(&var_data[range])
}
}