use crate::{FromStream, ToStream, from_stream, numbers::EndianSettings, to_stream};
use std::{
collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList, VecDeque},
hash::Hash,
io::{Read, Result, Write},
};
pub enum Size {
Usize,
U8,
U16,
U32,
U64,
U128,
}
pub trait SizeSettings: EndianSettings {
const SIZE: Size;
fn size_to_stream<W: Write>(size: usize, stream: &mut W) -> Result<()> {
use Size::*;
match Self::SIZE {
U8 => to_stream::<Self, _, _>(&(size as u8), stream),
U16 => to_stream::<Self, _, _>(&(size as u16), stream),
U32 => to_stream::<Self, _, _>(&(size as u32), stream),
U64 => to_stream::<Self, _, _>(&(size as u64), stream),
U128 => to_stream::<Self, _, _>(&(size as u128), stream),
Usize => to_stream::<Self, _, _>(&size, stream),
}
}
fn size_from_stream<R: Read>(stream: &mut R) -> Result<usize> {
use Size::*;
Ok(match Self::SIZE {
U8 => from_stream::<Self, u8, _>(stream)? as usize,
U16 => from_stream::<Self, u16, _>(stream)? as usize,
U32 => from_stream::<Self, u32, _>(stream)? as usize,
U64 => from_stream::<Self, u64, _>(stream)? as usize,
U128 => from_stream::<Self, u128, _>(stream)? as usize,
Usize => from_stream::<Self, usize, _>(stream)?,
})
}
}
macro_rules! impl_list_collection {
($t: ident) => {
impl<T: ToStream<S>, S: SizeSettings> ToStream<S> for $t<T> {
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
S::size_to_stream(self.len(), stream)?;
for element in self {
element.to_stream(stream)?
}
Ok(())
}
}
impl<T: FromStream<S>, S: SizeSettings> FromStream<S> for $t<T> {
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
let size = S::size_from_stream(stream)?;
(0..size)
.map(|_| from_stream(stream))
.collect::<Result<_>>()
}
}
};
($t: ident, $($rest: ident),+) => {
impl_list_collection!($t);
impl_list_collection!($($rest),+);
};
}
impl_list_collection!(Vec, VecDeque, LinkedList);
macro_rules! impl_set_collection {
($t: ident, $bound: tt $(+ $others: tt )*) => {
impl<T: ToStream<S> + $bound $(+ $others)*, S: SizeSettings> ToStream<S> for $t<T> {
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
S::size_to_stream(self.len(), stream)?;
for element in self {
element.to_stream(stream)?
}
Ok(())
}
}
impl<T: FromStream<S> + $bound $(+ $others)*, S: SizeSettings> FromStream<S> for $t<T> {
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
let size = S::size_from_stream(stream)?;
(0..size)
.map(|_| from_stream(stream))
.collect::<Result<_>>()
}
}
};
}
impl_set_collection!(HashSet, Eq + Hash);
impl_set_collection!(BTreeSet, Ord);
impl_set_collection!(BinaryHeap, Ord);
macro_rules! impl_map_collection {
($t: ident, $bound: tt $(+ $others: tt )*) => {
impl<K: ToStream<S> + $bound $(+ $others)*, V: ToStream<S>, S: SizeSettings> ToStream<S> for $t<K, V> {
fn to_stream<W: Write>(&self, stream: &mut W) -> Result<()> {
S::size_to_stream(self.len(), stream)?;
for (key, value) in self {
key.to_stream(stream)?;
value.to_stream(stream)?;
}
Ok(())
}
}
impl<K: FromStream<S> + $bound $(+ $others)*, V: FromStream<S>, S: SizeSettings> FromStream<S> for $t<K, V> {
fn from_stream<R: Read>(stream: &mut R) -> Result<Self> {
let size = S::size_from_stream(stream)?;
(0..size)
.map(|_| Ok((from_stream(stream)?, from_stream(stream)?)))
.collect::<Result<_>>()
}
}
};
}
impl_map_collection!(HashMap, Eq + Hash);
impl_map_collection!(BTreeMap, Ord);