use crate::{
Pointer, PointerType, Position, Read, ReadType, StaticSize, VecReader, Write, WriteType, Writer,
};
use num::ToPrimitive;
use std::{convert::TryInto, mem::size_of};
impl<'a> ReadType<'a> for () {
type ReadType = ();
}
impl WriteType for () {
type WriteType = ();
}
impl StaticSize for () {
const STATIC_SIZE: PointerType = 0;
}
impl<'a> Read<'a> for () {
type Output = Self;
fn read(_bytes: &'a [u8], _position: Position<Self>) -> Self::Output {}
}
impl Write for () {
type Output = Self;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
writer.position()
}
}
impl<'a> ReadType<'a> for bool {
type ReadType = bool;
}
impl WriteType for bool {
type WriteType = bool;
}
impl StaticSize for bool {
const STATIC_SIZE: PointerType = 1;
}
impl<'a> Read<'a> for bool {
type Output = Self;
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
let position = position.cast();
<u8>::read(bytes, position) != 0
}
}
impl Write for bool {
type Output = Self;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
let value = *self as u8;
writer.write_raw::<bool>(&value.to_le_bytes())
}
}
macro_rules! impl_read_write_for_number_type {
($ty:ty) => {
impl<'a> ReadType<'a> for $ty {
type ReadType = $ty;
}
impl WriteType for $ty {
type WriteType = $ty;
}
impl StaticSize for $ty {
const STATIC_SIZE: PointerType = size_of::<$ty>() as PointerType;
}
impl<'a> Read<'a> for $ty {
type Output = Self;
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
let position = position.to_usize().unwrap();
let bytes = &bytes[position..position + size_of::<$ty>()];
let bytes = bytes.try_into().unwrap();
<$ty>::from_le_bytes(bytes)
}
}
impl Write for $ty {
type Output = $ty;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
writer.write_raw::<$ty>(&self.to_le_bytes())
}
}
};
}
impl_read_write_for_number_type!(u8);
impl_read_write_for_number_type!(u16);
impl_read_write_for_number_type!(u32);
impl_read_write_for_number_type!(u64);
impl_read_write_for_number_type!(i8);
impl_read_write_for_number_type!(i16);
impl_read_write_for_number_type!(i32);
impl_read_write_for_number_type!(i64);
impl_read_write_for_number_type!(f32);
impl_read_write_for_number_type!(f64);
impl<'a> ReadType<'a> for char {
type ReadType = char;
}
impl WriteType for char {
type WriteType = char;
}
impl StaticSize for char {
const STATIC_SIZE: PointerType = 4;
}
impl<'a> Read<'a> for char {
type Output = Self;
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
<u32>::read(bytes, position.cast()).try_into().unwrap()
}
}
impl Write for char {
type Output = Self;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
writer.write(&(*self as u32)).cast()
}
}
impl<'a, T> ReadType<'a> for Option<T>
where
T: ReadType<'a>,
T::ReadType: StaticSize,
{
type ReadType = Option<T::ReadType>;
}
impl<T> WriteType for Option<T>
where
T: WriteType,
{
type WriteType = Option<T::WriteType>;
}
impl<'a, T> StaticSize for Option<T>
where
T: StaticSize,
{
const STATIC_SIZE: PointerType = 1 + T::STATIC_SIZE;
}
impl<'a, T> Read<'a> for Option<T>
where
T: StaticSize + Read<'a>,
{
type Output = Option<T::Output>;
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
let is_some = bool::read(bytes, position.offset(0));
if is_some {
Some(T::read(bytes, position.offset(1)))
} else {
None
}
}
}
impl<T> Write for Option<T>
where
T: StaticSize + Write,
T::Output: Sized,
{
type Output = Option<T::Output>;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
let position = writer.position();
match self {
None => {
writer.write(&0u8);
for _ in 0..T::STATIC_SIZE {
writer.write(&0u8);
}
}
Some(value) => {
writer.write(&1u8);
writer.write(value);
}
}
position
}
}
impl<'a, T1, T2> ReadType<'a> for (T1, T2)
where
T1: ReadType<'a>,
T1::ReadType: StaticSize,
T2: ReadType<'a>,
T2::ReadType: StaticSize,
{
type ReadType = (T1::ReadType, T2::ReadType);
}
impl<T1, T2> WriteType for (T1, T2)
where
T1: WriteType,
T2: WriteType,
{
type WriteType = (T1::WriteType, T2::WriteType);
}
impl<'a, T1, T2> StaticSize for (T1, T2)
where
T1: Read<'a> + StaticSize,
T2: Read<'a> + StaticSize,
{
const STATIC_SIZE: PointerType = T1::STATIC_SIZE + T2::STATIC_SIZE;
}
impl<'a, T1, T2> Read<'a> for (T1, T2)
where
T1: Read<'a> + StaticSize,
T2: Read<'a> + StaticSize,
{
type Output = (T1::Output, T2::Output);
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
(
T1::read(bytes, position.offset(0)),
T2::read(bytes, position.offset(T1::STATIC_SIZE)),
)
}
}
impl<T1, T2> Write for (T1, T2)
where
T1: Write + StaticSize,
T2: Write + StaticSize,
T1::Output: Sized,
T2::Output: Sized,
{
type Output = (T1::Output, T2::Output);
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
let position = writer.position();
self.0.write(writer);
self.1.write(writer);
position
}
}
impl<'a, T> ReadType<'a> for Vec<T>
where
T: 'a + ReadType<'a>,
T::ReadType: StaticSize,
{
type ReadType = Pointer<VecReader<'a, T::ReadType>>;
}
impl<T> WriteType for Vec<T>
where
T: WriteType,
{
type WriteType = Position<[T::WriteType]>;
}
impl<T> Write for Vec<T>
where
T: Write,
T::Output: Sized,
{
type Output = [T::Output];
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
writer.write(self.as_slice())
}
}
impl<T> Write for [T]
where
T: Write,
T::Output: Sized,
{
type Output = [T::Output];
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
let position = writer.position();
let len = self.len() as PointerType;
writer.write(&len);
for value in self.iter() {
writer.write(value);
}
position
}
}
impl<'a> ReadType<'a> for String {
type ReadType = Pointer<&'a str>;
}
impl WriteType for String {
type WriteType = Position<str>;
}
impl<'a> StaticSize for &'a str {
const STATIC_SIZE: PointerType = size_of::<PointerType>() as PointerType;
}
impl<'a> Read<'a> for &'a str {
type Output = Self;
fn read(bytes: &'a [u8], position: Position<Self>) -> Self::Output {
let len = PointerType::read(bytes, position.cast());
let len = len.to_usize().unwrap();
let position = position.offset::<str>(PointerType::STATIC_SIZE);
let position = *position as usize;
std::str::from_utf8(&bytes[position..position + len]).unwrap()
}
}
impl Write for str {
type Output = str;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
let position = writer.position();
let len: PointerType = self.len().try_into().unwrap();
writer.write(&len);
writer.write_raw::<str>(self.as_bytes());
position
}
}
impl Write for String {
type Output = str;
fn write(&self, writer: &mut Writer) -> Position<Self::Output> {
writer.write(self.as_str())
}
}
impl<'a, K, V> ReadType<'a> for std::collections::HashMap<K, V>
where
K: 'a + ReadType<'a>,
K::ReadType: StaticSize,
V: 'a + ReadType<'a>,
V::ReadType: StaticSize,
{
type ReadType = Pointer<VecReader<'a, (K::ReadType, V::ReadType)>>;
}
impl<K, V> WriteType for std::collections::HashMap<K, V>
where
K: WriteType,
V: WriteType,
{
type WriteType = Position<[(K::WriteType, V::WriteType)]>;
}