paged 0.1.1

Read and create read-only paged database files
Documentation
use std::io;

use crate::{heap, reader, EncodeSized, HeapSection};

pub trait Decode<C>: Sized {
	fn decode<R: io::Read>(input: &mut R, context: &mut C) -> io::Result<Self>;
}

macro_rules! decode_int {
	($($ty:ty),*) => {
		$(
			impl<C> Decode<C> for $ty {
				fn decode<R: io::Read>(
					input: &mut R,
					_context: &mut C
				) -> io::Result<Self> {
					let mut result = [0u8; std::mem::size_of::<$ty>()];
					input.read_exact(&mut result)?;
					Ok(Self::from_be_bytes(result))
				}
			}

			impl<C> DecodeFromHeap<C> for $ty {
				fn decode_from_heap<R: io::Seek + io::Read>(
					input: &mut reader::Cursor<R>,
					context: &mut C,
					_heap: HeapSection
				) -> io::Result<Self> {
					Self::decode(input, context)
				}
			}
		)*
	};
}

decode_int!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);

pub trait DecodeFromHeap<C = ()>: Sized {
	fn decode_from_heap<R: io::Seek + io::Read>(
		input: &mut reader::Cursor<R>,
		context: &mut C,
		heap: HeapSection,
	) -> io::Result<Self>;
}

impl<C> DecodeFromHeap<C> for String {
	fn decode_from_heap<R: io::Seek + io::Read>(
		input: &mut reader::Cursor<R>,
		context: &mut C,
		heap: HeapSection,
	) -> io::Result<Self> {
		let entry = heap::Entry::decode(input, context)?;
		let mut bytes = Vec::new();
		bytes.resize(entry.len as usize, 0u8);
		input.read_from_heap(heap, entry.offset, bytes.as_mut_slice())?;
		String::from_utf8(bytes).map_err(|_| io::ErrorKind::InvalidData.into())
	}
}

fn pad(input: &mut impl io::Read, len: u32) -> io::Result<()> {
	let mut buffer = [0u8; 1];
	for _ in 0..len {
		input.read_exact(&mut buffer)?;
	}

	Ok(())
}

impl<C, T: EncodeSized + Decode<C>> Decode<C> for Option<T> {
	fn decode<R: io::Read>(input: &mut R, context: &mut C) -> io::Result<Self> {
		let discriminant = u8::decode(input, context)?;
		match discriminant {
			0 => {
				pad(input, T::ENCODED_SIZE)?;
				Ok(None)
			}
			1 => T::decode(input, context).map(Some),
			_ => Err(io::ErrorKind::InvalidData.into()),
		}
	}
}

impl<C, T: EncodeSized + DecodeFromHeap<C>> DecodeFromHeap<C> for Option<T> {
	fn decode_from_heap<R: io::Seek + io::Read>(
		input: &mut reader::Cursor<R>,
		context: &mut C,
		heap: HeapSection,
	) -> io::Result<Self> {
		let discriminant = u8::decode(input, context)?;
		match discriminant {
			0 => {
				input.pad(T::ENCODED_SIZE)?;
				Ok(None)
			}
			1 => T::decode_from_heap(input, context, heap).map(Some),
			_ => Err(io::ErrorKind::InvalidData.into()),
		}
	}
}

impl<C, T: Decode<C>> DecodeFromHeap<C> for Vec<T> {
	fn decode_from_heap<R: io::Seek + io::Read>(
		input: &mut reader::Cursor<R>,
		context: &mut C,
		heap: HeapSection,
	) -> io::Result<Self> {
		let entry = heap::Entry::decode(input, context)?;
		let mut result = Vec::with_capacity(entry.len as usize);

		for _ in 0..entry.len {
			result.push(input.decode_from_heap(context, heap, entry.offset)?)
		}

		Ok(result)
	}
}

impl<C, T1: Decode<C>, T2: Decode<C>> Decode<C> for (T1, T2) {
	fn decode<R: io::Read>(input: &mut R, context: &mut C) -> io::Result<Self> {
		let t1 = T1::decode(input, context)?;
		let t2 = T2::decode(input, context)?;
		Ok((t1, t2))
	}
}

impl<C, T1: DecodeFromHeap<C>, T2: DecodeFromHeap<C>> DecodeFromHeap<C> for (T1, T2) {
	fn decode_from_heap<R: io::Seek + io::Read>(
		input: &mut reader::Cursor<R>,
		context: &mut C,
		heap: HeapSection,
	) -> io::Result<Self> {
		let t1 = T1::decode_from_heap(input, context, heap)?;
		let t2 = T2::decode_from_heap(input, context, heap)?;
		Ok((t1, t2))
	}
}