use std::hash::Hash;
use crate::codec::SketchBytes;
use crate::codec::SketchSlice;
use crate::codec::assert::insufficient_data;
use crate::error::Error;
pub const SERIAL_VERSION: u8 = 1;
pub const PREAMBLE_LONGS_EMPTY: u8 = 1;
pub const PREAMBLE_LONGS_NONEMPTY: u8 = 4;
pub const EMPTY_FLAG_MASK: u8 = 5;
pub trait FrequentItemValue: Sized + Eq + Hash {
fn serialize_size(item: &Self) -> usize;
fn serialize_value(&self, bytes: &mut SketchBytes);
fn deserialize_value(cursor: &mut SketchSlice<'_>) -> Result<Self, Error>;
}
impl FrequentItemValue for String {
fn serialize_size(item: &Self) -> usize {
size_of::<u32>() + item.len()
}
fn serialize_value(&self, bytes: &mut SketchBytes) {
let bs = self.as_bytes();
bytes.write_u32_le(bs.len() as u32);
bytes.write(bs);
}
fn deserialize_value(cursor: &mut SketchSlice<'_>) -> Result<Self, Error> {
let len = cursor
.read_u32_le()
.map_err(insufficient_data("string item length"))? as usize;
let available_bytes = cursor.remaining().len();
if available_bytes < len {
return Err(Error::insufficient_data_of(
"string item payload",
format_args!("expected {len} bytes, got {available_bytes}"),
));
}
let value = std::str::from_utf8(&cursor.remaining()[..len])
.map(str::to_owned)
.map_err(|_| Error::deserial("invalid UTF-8 string payload"))?;
cursor.advance(len as u64);
Ok(value)
}
}
macro_rules! impl_primitive {
($name:ty, $read:ident, $write:ident) => {
impl FrequentItemValue for $name {
fn serialize_size(_item: &Self) -> usize {
size_of::<$name>()
}
fn serialize_value(&self, bytes: &mut SketchBytes) {
bytes.$write(*self);
}
fn deserialize_value(cursor: &mut SketchSlice<'_>) -> Result<Self, Error> {
cursor
.$read()
.map_err(insufficient_data(concat!(stringify!($name), " item")))
}
}
};
}
impl_primitive!(i64, read_i64_le, write_i64_le);
impl_primitive!(u64, read_u64_le, write_u64_le);