use std::io::{prelude::*, SeekFrom};
use byteorder::{LittleEndian, WriteBytesExt};
use fastvlq::WriteVu64Ext;
use crate::{
file::Inode, AttrMap, BoxHeader, BoxMetadata, BoxPath, Compression, DirectoryRecord,
FileRecord, LinkRecord, Record,
};
pub(crate) trait Serialize {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()>;
}
impl<T: Serialize> Serialize for Vec<T> {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_vu64(self.len() as u64)?;
for item in self.iter() {
item.write(writer)?;
}
Ok(())
}
}
impl Serialize for String {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_vu64(self.len() as u64)?;
writer.write_all(self.as_bytes())
}
}
impl Serialize for Vec<u8> {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_vu64(self.len() as u64)?;
writer.write_all(&*self)
}
}
impl Serialize for AttrMap {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
let size_index = writer.seek(SeekFrom::Current(0))?;
writer.write_u64::<LittleEndian>(std::u64::MAX)?;
writer.write_vu64(self.len() as u64)?;
for (key, value) in self.iter() {
writer.write_vu64(*key as u64)?;
value.write(writer)?;
}
let cur_index = writer.seek(SeekFrom::Current(0))?;
writer.seek(SeekFrom::Start(size_index))?;
writer.write_u64::<LittleEndian>(cur_index - size_index)?;
writer.seek(SeekFrom::Start(cur_index))?;
Ok(())
}
}
impl Serialize for BoxPath {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
self.0.write(writer)
}
}
impl Serialize for Inode {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_vu64(self.get())
}
}
impl Serialize for FileRecord {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u8(0x0)?;
writer.write_u8(self.compression.id())?;
writer.write_u64::<LittleEndian>(self.length)?;
writer.write_u64::<LittleEndian>(self.decompressed_length)?;
writer.write_u64::<LittleEndian>(self.data.get())?;
self.name.write(writer)?;
self.attrs.write(writer)
}
}
impl Serialize for DirectoryRecord {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u8(0x1)?;
self.name.write(writer)?;
self.inodes.write(writer)?;
self.attrs.write(writer)
}
}
impl Serialize for LinkRecord {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u8(0x2)?;
self.name.write(writer)?;
self.target.write(writer)?;
self.attrs.write(writer)
}
}
impl Serialize for Record {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
match self {
Record::File(file) => file.write(writer),
Record::Directory(directory) => directory.write(writer),
Record::Link(link) => link.write(writer),
}
}
}
impl Serialize for BoxHeader {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_all(&self.magic_bytes)?;
writer.write_u32::<LittleEndian>(self.version)?;
writer.write_u64::<LittleEndian>(self.alignment)?;
writer.write_u64::<LittleEndian>(self.trailer.map(|x| x.get()).unwrap_or(0))
}
}
impl Serialize for BoxMetadata {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
self.root.write(writer)?;
self.inodes.write(writer)?;
self.attr_keys.write(writer)?;
self.attrs.write(writer)?;
let mut builder = pathtrie::PathTrie::new();
for x in self.iter() {
builder.insert(x.path, x.inode.get())
}
builder.write_fst(writer)
}
}
impl Serialize for Compression {
fn write<W: Write + Seek>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_u8(self.id())
}
}