use core::cmp::min;
use std::collections::HashMap;
use std::hash::Hash;
use crate::codec::Compact1CodecOpinion;
use crate::decoder::{DecError, Decoder, MeasureBuf};
use crate::encoder::{EncError, Encoder, ImprovidentBufMut};
pub struct HashMapOpinion<KO, VO> {
max_len: u32,
inner_k: KO,
inner_v: VO,
}
impl<KO, VO> HashMapOpinion<KO, VO> {
pub fn new(max_len: u32, inner_k: KO, inner_v: VO) -> Self {
Self {
inner_k,
inner_v,
max_len,
}
}
}
impl<K: Eq + Hash, KO: Compact1CodecOpinion<K>, V, VO: Compact1CodecOpinion<V>>
Compact1CodecOpinion<HashMap<K, V>> for HashMapOpinion<KO, VO>
{
fn encode<B: ImprovidentBufMut>(
&self,
encoder: &mut Encoder<B>,
what: &HashMap<K, V>,
) -> Result<(), EncError>
where
Self: Sized,
{
let items = what.len();
if items > min(self.max_len, crate::vu29::VU29_MAX_4BYTE) as usize {
return Err(EncError::ContainerTooLong);
}
crate::vu29::encode_vu29(encoder.buf.deref_mut(), items as u32)?;
for (key, value) in what {
self.inner_k.encode(encoder, key)?;
self.inner_v.encode(encoder, value)?;
}
Ok(())
}
fn decode<B: MeasureBuf>(&self, decoder: &mut Decoder<B>) -> Result<HashMap<K, V>, DecError> {
let num_items = crate::vu29::decode_vu29(&mut decoder.buf)?;
if num_items > self.max_len {
return Err(DecError::ContainerTooLong);
}
let mut out = HashMap::with_capacity(num_items as usize);
for _ in 0..num_items {
let k = self.inner_k.decode(decoder)?;
let v = self.inner_v.decode(decoder)?;
if out.insert(k, v).is_some() {
return Err(DecError::DuplicateMapKeys);
}
}
Ok(out)
}
}