jubako 0.3.0

The reference implementation of the Jubako container format
Documentation
use crate::bases::*;
use crate::creator::MaybeFileReader;
use std::fmt::Debug;
use std::io::{Read, Seek, Write};

pub(crate) mod private {
    use super::{BlockCheck, ByteSize, MaybeFileReader, Offset, CRC};
    use std::fmt::Debug;
    use std::io::{Cursor, Read, Result as IoResult, Seek, Write};
    use zerocopy::byteorder::little_endian::{U16, U32, U64};
    use zerocopy::{AsBytes, ByteOrder, LittleEndian as LE};

    /// A Serializable is a object we can serialized on a [Serializer].
    pub trait Serializable {
        fn serialize(&self, stream: &mut Serializer) -> IoResult<usize>;
    }

    /// A Buffer on which we can write data.
    pub struct Serializer {
        buf: Cursor<Vec<u8>>,
        check: BlockCheck,
    }

    impl Serializer {
        pub fn new(check: BlockCheck) -> Self {
            Self {
                buf: Cursor::new(Vec::with_capacity(256)),
                check,
            }
        }

        pub fn close(self) -> (Vec<u8>, Option<[u8; 4]>) {
            match self.check {
                BlockCheck::None => (self.buf.into_inner(), None),
                BlockCheck::Crc32 => {
                    let buf = self.buf.into_inner();
                    let mut digest = CRC.digest();
                    digest.update(&buf);
                    let checksum = digest.finalize();
                    let checksum = checksum.to_be_bytes();

                    #[cfg(debug_assertions)]
                    {
                        let mut digest = CRC.digest();
                        digest.update(&buf);
                        digest.update(&checksum);
                        assert_eq!(digest.finalize(), 0);
                    }
                    (buf, Some(checksum))
                }
            }
        }

        pub fn len(&self) -> usize {
            self.buf.get_ref().len()
        }
    }

    impl Serializer {
        pub fn write_u8(&mut self, value: u8) -> IoResult<usize> {
            self.buf.write_all(value.as_bytes())?;
            Ok(1)
        }
        pub fn write_u16(&mut self, value: u16) -> IoResult<usize> {
            let d = U16::from(value);
            self.buf.write_all(d.as_bytes())?;
            Ok(2)
        }
        pub fn write_u32(&mut self, value: u32) -> IoResult<usize> {
            let d = U32::from(value);
            self.buf.write_all(d.as_bytes())?;
            Ok(4)
        }
        pub fn write_u64(&mut self, value: u64) -> IoResult<usize> {
            let d = U64::from(value);
            self.buf.write_all(d.as_bytes())?;
            Ok(8)
        }
        pub fn write_usized(&mut self, value: u64, size: ByteSize) -> IoResult<usize> {
            let d = U64::from(value);
            let size = size as usize;
            self.buf.write_all(&d.as_bytes()[..size])?;
            Ok(size)
        }
        pub fn write_isized(&mut self, value: i64, size: ByteSize) -> IoResult<usize> {
            let mut d = [0_u8; 8];
            let size = size as usize;
            LE::write_int(&mut d, value, size);
            self.buf.write_all(&d[..size])?;
            Ok(size)
        }
        pub fn write_data(&mut self, buf: &[u8]) -> IoResult<usize> {
            self.buf.write_all(buf)?;
            Ok(buf.len())
        }
    }

    /// A OutStream is a object on which we can write data.
    pub trait OutStream: Write + Seek + Send + Debug {
        fn copy(
            &mut self,
            reader: Box<dyn crate::creator::InputReader>,
        ) -> IoResult<(u64, MaybeFileReader)>;

        fn tell(&mut self) -> Offset {
            self.stream_position().unwrap().into()
        }

        fn write_serializer(&mut self, serializer: Serializer) -> IoResult<usize> {
            let (data, check) = serializer.close();
            self.write_all(&data)?;
            if let Some(check) = check {
                self.write_all(&check)?;
            }
            Ok(data.len())
        }

        fn ser_write(&mut self, obj: &dyn Serializable) -> IoResult<usize> {
            let mut serializer = Serializer::new(BlockCheck::Crc32);
            let written = obj.serialize(&mut serializer)?;
            assert_eq!(written, serializer.len());
            self.write_serializer(serializer)
        }

        fn ser_callable(
            &mut self,
            fun: &dyn Fn(&mut Serializer) -> IoResult<()>,
        ) -> IoResult<usize> {
            let mut serializer = Serializer::new(BlockCheck::Crc32);
            fun(&mut serializer)?;
            self.write_serializer(serializer)
        }
    }

    pub trait InOutStream: OutStream + Read {}
}

pub(crate) use private::{InOutStream, OutStream, Serializable, Serializer};

impl OutStream for std::fs::File {
    fn copy(
        &mut self,
        reader: Box<dyn crate::creator::InputReader>,
    ) -> IoResult<(u64, MaybeFileReader)> {
        let mut maybe_file_reader = reader.get_file_source();
        let read = match maybe_file_reader {
            crate::creator::MaybeFileReader::Yes(ref mut input_file) => {
                std::io::copy(input_file, self)?
            }
            crate::creator::MaybeFileReader::No(ref mut reader) => {
                std::io::copy(reader.as_mut(), self)?
            }
        };
        Ok((read, maybe_file_reader))
    }
}

impl<T> OutStream for std::io::Cursor<T>
where
    std::io::Cursor<T>: Write + Seek + Send + std::fmt::Debug,
{
    fn copy(
        &mut self,
        reader: Box<dyn crate::creator::InputReader>,
    ) -> IoResult<(u64, MaybeFileReader)> {
        let mut maybe_file_reader = reader.get_file_source();
        let read = match maybe_file_reader {
            crate::creator::MaybeFileReader::Yes(ref mut input_file) => {
                std::io::copy(input_file, self)?
            }
            crate::creator::MaybeFileReader::No(ref mut reader) => {
                std::io::copy(reader.as_mut(), self)?
            }
        };
        Ok((read, maybe_file_reader))
    }
}

impl<T> OutStream for std::io::BufWriter<T>
where
    T: Write + Seek + Send + Debug,
{
    fn copy(
        &mut self,
        reader: Box<dyn crate::creator::InputReader>,
    ) -> IoResult<(u64, MaybeFileReader)> {
        let mut maybe_file_reader = reader.get_file_source();
        let read = match maybe_file_reader {
            crate::creator::MaybeFileReader::Yes(ref mut input_file) => {
                std::io::copy(input_file, self)?
            }
            crate::creator::MaybeFileReader::No(ref mut reader) => {
                std::io::copy(reader.as_mut(), self)?
            }
        };
        Ok((read, maybe_file_reader))
    }
}

impl<O> OutStream for Skip<O>
where
    O: OutStream,
{
    fn copy(
        &mut self,
        reader: Box<dyn crate::creator::InputReader>,
    ) -> IoResult<(u64, MaybeFileReader)> {
        self.inner_mut().copy(reader)
    }
}

impl<O> OutStream for Box<O>
where
    O: OutStream + ?Sized,
{
    fn copy(
        &mut self,
        reader: Box<dyn crate::creator::InputReader>,
    ) -> IoResult<(u64, MaybeFileReader)> {
        self.as_mut().copy(reader)
    }
}

impl<T> InOutStream for T where T: OutStream + Read {}