#![deny(missing_docs)]
use core::iter;
use core::marker::PhantomData;
use alloc::vec::Vec;
use crate::binary::read::{ReadArray, ReadArrayCow, ReadScope, ReadUnchecked};
use crate::binary::{I16Be, I32Be, I64Be, U16Be, U24Be, U32Be, I8, U8};
use crate::error::WriteError;
pub struct WriteBuffer {
data: Vec<u8>,
}
struct WriteSlice<'a> {
offset: usize,
data: &'a mut [u8],
}
pub struct WriteCounter {
count: usize,
}
struct NullWriter;
pub struct Placeholder<T, HostType>
where
T: WriteBinary<HostType>,
{
offset: usize,
length: usize,
marker: PhantomData<T>,
host: PhantomData<HostType>,
}
pub trait WriteBinary<HostType = Self> {
type Output;
fn write<C: WriteContext>(ctxt: &mut C, val: HostType) -> Result<Self::Output, WriteError>;
}
pub trait WriteBinaryDep<HostType = Self> {
type Args;
type Output;
fn write_dep<C: WriteContext>(
ctxt: &mut C,
val: HostType,
args: Self::Args,
) -> Result<Self::Output, WriteError>;
}
pub trait WriteContext {
fn write_array<'a, T>(&mut self, array: &ReadArray<'a, T>) -> Result<(), WriteError>
where
Self: Sized,
T: ReadUnchecked<'a> + WriteBinary<<T as ReadUnchecked<'a>>::HostType>,
{
<&ReadArray<'_, _>>::write(self, array)
}
fn write_vec<'a, T>(
&mut self,
vec: Vec<<T as ReadUnchecked<'a>>::HostType>,
) -> Result<(), WriteError>
where
Self: Sized,
T: ReadUnchecked<'a> + WriteBinary<<T as ReadUnchecked<'a>>::HostType>,
{
for val in vec {
T::write(self, val)?;
}
Ok(())
}
fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError>;
fn write_zeros(&mut self, count: usize) -> Result<(), WriteError>;
fn bytes_written(&self) -> usize;
fn placeholder<'a, T, HostType>(&mut self) -> Result<Placeholder<T, HostType>, WriteError>
where
T: WriteBinary<HostType> + ReadUnchecked<'a>,
{
let offset = self.bytes_written();
self.write_zeros(T::SIZE)?;
Ok(Placeholder {
offset,
length: T::SIZE,
marker: PhantomData,
host: PhantomData,
})
}
fn reserve<'a, T, HostType>(
&mut self,
count: usize,
) -> Result<Placeholder<T, &'a HostType>, WriteError>
where
T: WriteBinary<&'a HostType>,
{
let offset = self.bytes_written();
self.write_zeros(count)?;
Ok(Placeholder {
offset,
length: count,
marker: PhantomData,
host: PhantomData,
})
}
fn placeholder_array<'a, T, HostType>(
&mut self,
count: usize,
) -> Result<Vec<Placeholder<T, HostType>>, WriteError>
where
T: WriteBinary<HostType> + ReadUnchecked<'a>,
{
(0..count)
.map(|_| self.placeholder::<T, HostType>())
.collect()
}
fn write_placeholder<T, HostType>(
&mut self,
placeholder: Placeholder<T, HostType>,
val: HostType,
) -> Result<T::Output, WriteError>
where
T: WriteBinary<HostType>;
}
pub fn buffer<HostType, T: WriteBinaryDep<HostType>>(
writeable: HostType,
args: T::Args,
) -> Result<(T::Output, WriteBuffer), WriteError> {
let mut buffer = WriteBuffer::new();
let output = T::write_dep(&mut buffer, writeable, args)?;
Ok((output, buffer))
}
impl<T, HostType> WriteBinaryDep<HostType> for T
where
T: WriteBinary<HostType>,
{
type Args = ();
type Output = T::Output;
fn write_dep<C: WriteContext>(
ctxt: &mut C,
val: HostType,
(): Self::Args,
) -> Result<Self::Output, WriteError> {
T::write(ctxt, val)
}
}
impl<T> WriteBinary<T> for U8
where
T: Into<u8>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: u8 = t.into();
ctxt.write_bytes(&[val])
}
}
impl<T> WriteBinary<T> for I8
where
T: Into<i8>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: i8 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl<T> WriteBinary<T> for I16Be
where
T: Into<i16>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: i16 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl<T> WriteBinary<T> for U16Be
where
T: Into<u16>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: u16 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl<T> WriteBinary<T> for U24Be
where
T: Into<u32>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: u32 = t.into();
if val > 0xFF_FFFF {
return Err(WriteError::BadValue);
}
ctxt.write_bytes(&val.to_be_bytes()[1..4])
}
}
impl<T> WriteBinary<T> for I32Be
where
T: Into<i32>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: i32 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl<T> WriteBinary<T> for U32Be
where
T: Into<u32>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: u32 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl<T> WriteBinary<T> for I64Be
where
T: Into<i64>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
let val: i64 = t.into();
ctxt.write_bytes(&val.to_be_bytes())
}
}
impl WriteContext for WriteBuffer {
fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
self.data.extend(data.iter());
Ok(())
}
fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
let zeros = iter::repeat(0).take(count);
self.data.extend(zeros);
Ok(())
}
fn bytes_written(&self) -> usize {
self.data.len()
}
fn write_placeholder<T, HostType>(
&mut self,
placeholder: Placeholder<T, HostType>,
val: HostType,
) -> Result<T::Output, WriteError>
where
T: WriteBinary<HostType>,
{
let data = &mut self.data[placeholder.offset..];
let data = &mut data[0..placeholder.length];
let mut slice = WriteSlice { offset: 0, data };
T::write(&mut slice, val)
}
}
impl<'a> WriteContext for WriteSlice<'a> {
fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
let data_len = data.len();
let self_len = self.data.len();
if data_len <= self_len {
let subslice = &mut self.data[self.offset..][0..data_len];
subslice.copy_from_slice(data);
self.offset += data_len;
Ok(())
} else {
Err(WriteError::BadValue)
}
}
fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
for i in 0..count.min(self.data.len()) {
self.data[i] = 0;
}
Ok(())
}
fn bytes_written(&self) -> usize {
self.data.len()
}
fn write_placeholder<T, HostType>(
&mut self,
_placeholder: Placeholder<T, HostType>,
_val: HostType,
) -> Result<T::Output, WriteError>
where
T: WriteBinary<HostType>,
{
unimplemented!()
}
}
impl WriteContext for WriteCounter {
fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
self.count += data.len();
Ok(())
}
fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
self.count += count;
Ok(())
}
fn bytes_written(&self) -> usize {
self.count
}
fn write_placeholder<T, HostType>(
&mut self,
_placeholder: Placeholder<T, HostType>,
val: HostType,
) -> Result<T::Output, WriteError>
where
T: WriteBinary<HostType>,
{
let mut null = NullWriter;
T::write(&mut null, val)
}
}
impl WriteContext for NullWriter {
fn write_bytes(&mut self, _data: &[u8]) -> Result<(), WriteError> {
Ok(())
}
fn write_zeros(&mut self, _count: usize) -> Result<(), WriteError> {
Ok(())
}
fn bytes_written(&self) -> usize {
0
}
fn write_placeholder<T, HostType>(
&mut self,
_placeholder: Placeholder<T, HostType>,
_val: HostType,
) -> Result<T::Output, WriteError>
where
T: WriteBinary<HostType>,
{
unimplemented!()
}
}
impl<'a, T> WriteBinary for &ReadArray<'a, T>
where
T: ReadUnchecked<'a> + WriteBinary<<T as ReadUnchecked<'a>>::HostType>,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, array: Self) -> Result<(), WriteError> {
for val in array.into_iter() {
T::write(ctxt, val)?;
}
Ok(())
}
}
impl<'a, T> WriteBinary<&Self> for ReadArrayCow<'a, T>
where
T: ReadUnchecked<'a> + WriteBinary<<T as ReadUnchecked<'a>>::HostType>,
T::HostType: Copy,
{
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, array: &Self) -> Result<(), WriteError> {
for val in array.iter() {
T::write(ctxt, val)?;
}
Ok(())
}
}
impl<'a> WriteBinary for ReadScope<'a> {
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, scope: Self) -> Result<(), WriteError> {
ctxt.write_bytes(scope.data())
}
}
impl WriteBuffer {
pub fn new() -> Self {
WriteBuffer { data: Vec::new() }
}
pub fn bytes(&self) -> &[u8] {
&self.data
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn into_inner(self) -> Vec<u8> {
self.data
}
}
impl WriteCounter {
pub fn new() -> Self {
WriteCounter { count: 0 }
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tag;
struct TestTable {
tag: u32,
}
struct BigStruct {
tag: u32,
}
impl WriteBinary<Self> for TestTable {
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, val: Self) -> Result<(), WriteError> {
U32Be::write(ctxt, val.tag)
}
}
impl WriteBinary<&Self> for BigStruct {
type Output = ();
fn write<C: WriteContext>(ctxt: &mut C, val: &Self) -> Result<(), WriteError> {
U32Be::write(ctxt, val.tag)
}
}
#[test]
fn test_basic() {
let mut ctxt = WriteBuffer::new();
let table = TestTable { tag: tag::GLYF };
let big = BigStruct { tag: tag::BLOC };
TestTable::write(&mut ctxt, table).unwrap();
BigStruct::write(&mut ctxt, &big).unwrap();
assert_eq!(ctxt.bytes(), b"glyfbloc")
}
#[test]
fn test_write_u24be() {
let mut ctxt = WriteBuffer::new();
U24Be::write(&mut ctxt, 0x10203u32).unwrap();
assert_eq!(ctxt.bytes(), &[1, 2, 3]);
match U24Be::write(&mut ctxt, core::u32::MAX) {
Err(WriteError::BadValue) => {}
_ => panic!("Expected WriteError::BadValue"),
}
}
#[test]
fn test_write_placeholder() {
let mut ctxt = WriteBuffer::new();
U8::write(&mut ctxt, 1).unwrap();
let placeholder = ctxt.placeholder::<U16Be, u16>().unwrap();
U8::write(&mut ctxt, 3).unwrap();
ctxt.write_placeholder(placeholder, 2).unwrap();
assert_eq!(ctxt.bytes(), &[1, 0, 2, 3]);
}
#[test]
fn test_write_placeholder_overflow() {
let mut ctxt = WriteBuffer::new();
let placeholder = ctxt.reserve::<BigStruct, _>(1).unwrap();
let value = BigStruct { tag: 1234 };
assert!(ctxt.write_placeholder(placeholder, &value).is_err());
}
}