use std::{
collections::{HashMap, HashSet},
io::{Read, Write},
};
use indexmap::{IndexMap, IndexSet};
use super::{
packed_int::PackedUint, DataFormat, DataFormatReader, DataFormatWriter, DataReadError,
DataWriteError,
};
impl<T: DataFormat + Default + Copy, const N: usize> DataFormat for [T; N] {
type Header = T::Header;
const LATEST_HEADER: Self::Header = T::LATEST_HEADER;
fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
let mut written = 0;
for item in self.iter() {
written += item.write_data(writer)?;
}
Ok(written)
}
fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
let mut data = [T::default(); N];
for item in data.iter_mut() {
*item = reader.read_data(header)?;
}
Ok(data)
}
}
impl<T: DataFormat> DataFormat for Vec<T> {
type Header = T::Header;
const LATEST_HEADER: Self::Header = T::LATEST_HEADER;
fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
let mut written = PackedUint::from(self.len()).write_data(writer)?;
for item in self.iter() {
written += writer.write_data(item)?;
}
Ok(written)
}
fn read_data<R: Read>(reader: &mut R, header: &Self::Header) -> Result<Self, DataReadError> {
let len = usize::from(PackedUint::read_data(reader, &())?);
let mut data = Vec::with_capacity(len);
for _ in 0..len {
data.push(reader.read_data(header)?);
}
Ok(data)
}
}
macro_rules! impl_set {
($set_ty:ident) => {
impl<T> DataFormat for $set_ty<T>
where
T: DataFormat + Eq + std::hash::Hash,
{
type Header = T::Header;
const LATEST_HEADER: Self::Header = T::LATEST_HEADER;
fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
let mut written = PackedUint::from(self.len()).write_data(writer)?;
for item in self.iter() {
written += writer.write_data(item)?;
}
Ok(written)
}
fn read_data<R: Read>(
reader: &mut R,
header: &Self::Header,
) -> Result<Self, DataReadError> {
let len = usize::from(PackedUint::read_data(reader, &())?);
let mut data = $set_ty::with_capacity(len);
for _ in 0..len {
data.insert(reader.read_data(header)?);
}
Ok(data)
}
}
};
}
impl_set!(HashSet);
impl_set!(IndexSet);
macro_rules! impl_map {
($map_ty:ident) => {
impl<K, V> DataFormat for $map_ty<K, V>
where
K: DataFormat + Eq + std::hash::Hash,
V: DataFormat,
{
type Header = (K::Header, V::Header);
const LATEST_HEADER: Self::Header = (K::LATEST_HEADER, V::LATEST_HEADER);
fn write_data<W: Write>(&self, writer: &mut W) -> Result<usize, DataWriteError> {
let mut written = PackedUint::from(self.len()).write_data(writer)?;
for (key, value) in self.iter() {
written += writer.write_data(key)?;
written += writer.write_data(value)?;
}
Ok(written)
}
fn read_data<R: Read>(
reader: &mut R,
(key_header, value_header): &Self::Header,
) -> Result<Self, DataReadError> {
let len = usize::from(PackedUint::read_data(reader, &())?);
let mut data = $map_ty::with_capacity(len);
for _ in 0..len {
data.insert(
reader.read_data(key_header)?,
reader.read_data(value_header)?,
);
}
Ok(data)
}
}
};
}
impl_map!(HashMap);
impl_map!(IndexMap);
#[cfg(test)]
#[rustfmt::skip]
mod test {
use crate::format::DataFormat;
macro_rules! case {
($name:ident, $ty:ty, $a:expr, $b:expr) => {
#[test]
fn $name() {
let mut data = Vec::new();
let value: $ty = $a;
value.write_data(&mut data).unwrap();
let mut reader = &data[..];
let read_value = <$ty>::read_data(&mut reader, &<$ty as DataFormat>::LATEST_HEADER).unwrap();
assert_eq!(read_value, value);
}
};
}
case!(test_vec_u8, Vec<u8>, vec![1, 2, 3], [
1, 3,
1, 2, 3
]);
case!(test_vec_u16, Vec<u16>, vec![1, 2, 3], [
1, 3,
1, 0,
2, 0,
3, 0
]);
case!(test_hashset_u8, std::collections::HashSet<u8>, [1, 2, 3].into_iter().collect(), [
1, 3,
1, 2, 3
]);
case!(test_hashset_u16, std::collections::HashSet<u16>, [1, 2, 3].into_iter().collect(), [
1, 3,
1, 0,
2, 0,
3, 0
]);
case!(test_hashmap_u8_u16, std::collections::HashMap<u8, u16>, [(1, 2), (3, 4)].into_iter().collect(), [
1, 4,
1, 0,
2, 0,
3, 0,
4, 0
]);
}