use core::any::{Any, TypeId};
use core::hash::Hash;
use hashbrown::HashMap;
#[cfg(not(feature = "std"))]
use alloc::boxed::Box;
#[cfg(feature = "std")]
use std::boxed::Box;
use crate::prelude::*;
const DEFAULT_INITIAL_CAPACITY: usize = 128;
const DEFAULT_NUM_TYPES: usize = 4;
pub trait DedupeEncodeable: Hash + Eq + Pack + Clone + Send + Sync + 'static {}
impl<T: DedupeEncodeable> Encode for T {
#[inline(always)]
fn encode_ext(
&self,
writer: &mut impl Write,
dedupe_encoder: Option<&mut crate::dedupe::DedupeEncoder>,
) -> Result<usize> {
if let Some(encoder) = dedupe_encoder {
encoder.encode(self, writer)
} else {
self.pack(writer)
}
}
}
pub trait DedupeDecodeable: Pack + Clone + Hash + Eq + Send + Sync + 'static {}
impl<T: DedupeDecodeable> Decode for T {
#[inline(always)]
fn decode_ext(
reader: &mut impl Read,
dedupe_decoder: Option<&mut crate::dedupe::DedupeDecoder>,
) -> Result<Self> {
if let Some(decoder) = dedupe_decoder {
decoder.decode(reader)
} else {
T::unpack(reader)
}
}
}
pub struct DedupeEncoder {
type_stores: HashMap<TypeId, Box<dyn Any + Send + Sync>>,
next_id: usize,
initial_capacity: usize,
}
impl Default for DedupeEncoder {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl DedupeEncoder {
#[inline(always)]
pub fn new() -> Self {
Self {
type_stores: HashMap::with_capacity(DEFAULT_NUM_TYPES),
next_id: 1, initial_capacity: DEFAULT_INITIAL_CAPACITY,
}
}
#[inline(always)]
pub fn with_capacity(initial_capacity: usize, num_types: usize) -> Self {
Self {
type_stores: HashMap::with_capacity(num_types),
next_id: 1,
initial_capacity,
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.type_stores.clear();
self.next_id = 1;
}
#[inline(always)]
pub const fn len(&self) -> usize {
self.next_id - 1
}
#[inline(always)]
pub const fn is_empty(&self) -> bool {
self.next_id == 1
}
#[inline]
pub fn encode<T: Hash + Eq + Pack + Clone + Send + Sync + 'static>(
&mut self,
val: &T,
writer: &mut impl Write,
) -> Result<usize> {
let type_id = TypeId::of::<T>();
let store = self
.type_stores
.entry(type_id)
.or_insert_with(|| Box::new(HashMap::<T, usize>::with_capacity(self.initial_capacity)));
let typed_store = store
.downcast_mut::<HashMap<T, usize>>()
.expect("Type mismatch in type store");
if let Some(&existing_id) = typed_store.get(val) {
return Lencode::encode_varint(existing_id, writer);
}
let new_id = self.next_id;
self.next_id += 1;
typed_store.insert(val.clone(), new_id);
let mut total_bytes = 0;
total_bytes += Lencode::encode_varint(0usize, writer)?; total_bytes += val.pack(writer)?;
Ok(total_bytes)
}
}
#[derive(Default)]
pub struct DedupeDecoder {
values: Vec<Box<dyn Any + Send + Sync>>,
}
impl DedupeDecoder {
#[inline(always)]
pub fn new() -> Self {
Self {
values: Vec::with_capacity(DEFAULT_INITIAL_CAPACITY),
}
}
#[inline(always)]
pub fn with_capacity(capacity: usize) -> Self {
Self {
values: Vec::with_capacity(capacity),
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.values.clear();
}
#[inline(always)]
pub fn len(&self) -> usize {
self.values.len()
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
#[inline]
pub fn decode<T: Pack + Clone + Hash + Eq + Send + Sync + 'static>(
&mut self,
reader: &mut impl Read,
) -> Result<T> {
let id = Lencode::decode_varint::<usize>(reader)?;
if id == 0 {
let value = T::unpack(reader)?;
self.values.push(Box::new(value.clone()));
Ok(value)
} else {
let index = id - 1; if let Some(boxed_value) = self.values.get(index)
&& let Some(typed_value) = boxed_value.downcast_ref::<T>()
{
return Ok(typed_value.clone());
}
Err(crate::io::Error::InvalidData)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::io::Cursor;
#[test]
fn test_dedupe_encode_decode_roundtrip() {
let mut encoder = DedupeEncoder::new();
let mut decoder = DedupeDecoder::new();
let mut buffer = Vec::new();
let values = [42u32, 123u32, 42u32, 456u32, 123u32, 789u32, 42u32];
for &value in &values {
encoder.encode(&value, &mut buffer).unwrap();
}
let mut cursor = Cursor::new(&buffer);
let mut decoded_values = Vec::new();
for _ in &values {
let decoded: u32 = decoder.decode(&mut cursor).unwrap();
decoded_values.push(decoded);
}
assert_eq!(values.to_vec(), decoded_values);
}
#[test]
fn test_dedupe_clear() {
let mut encoder = DedupeEncoder::new();
let mut decoder = DedupeDecoder::new();
let mut buffer = Vec::new();
encoder.encode(&42u32, &mut buffer).unwrap();
encoder.encode(&123u32, &mut buffer).unwrap();
encoder.clear();
decoder.clear();
buffer.clear();
encoder.encode(&42u32, &mut buffer).unwrap(); encoder.encode(&42u32, &mut buffer).unwrap();
let mut cursor = Cursor::new(&buffer);
let decoded1: u32 = decoder.decode(&mut cursor).unwrap();
let decoded2: u32 = decoder.decode(&mut cursor).unwrap();
assert_eq!(decoded1, 42u32);
assert_eq!(decoded2, 42u32);
}
#[test]
fn test_dedupe_invalid_id() {
let mut decoder = DedupeDecoder::new();
let mut buffer = Vec::new();
Lencode::encode_varint(5usize, &mut buffer).unwrap();
let mut cursor = Cursor::new(&buffer);
let result: Result<u32> = decoder.decode(&mut cursor);
assert!(result.is_err());
matches!(result, Err(crate::io::Error::InvalidData));
}
}