use std::{
io::{Read, Write},
ops::Deref,
};
use crate::error::Error;
mod decoder;
mod encoder;
pub use decoder::{ParcelDecoder, ParcelItem};
pub use encoder::ParcelEncoder;
const MARKER_SEP: [u8; 4] = [0x30, 0x30, 0x30, 0x31];
const MARKER_END: [u8; 4] = [0x30, 0x30, 0x30, 0x30];
#[derive(Debug, Clone)]
pub struct Parcel {
pub sections: Vec<Section>,
}
impl Parcel {
#[must_use]
pub fn new(sections: Vec<Section>) -> Self {
Self { sections }
}
pub fn from_bytes(data: &[u8]) -> Result<Self, Error> {
let dec = ParcelDecoder::new(data);
dec.collect()
}
pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
let dec = ParcelDecoder::new(reader);
dec.collect()
}
pub fn write_to<W: Write>(&self, writer: W) -> Result<(), Error> {
let mut enc = ParcelEncoder::new(writer);
let mut first = true;
for section in &self.sections {
if first {
first = false;
} else {
enc.new_section()?;
}
for data in section.iter() {
enc.write_data(data)?;
}
}
enc.finish()
}
}
impl FromIterator<ParcelItem> for Parcel {
fn from_iter<T: IntoIterator<Item = ParcelItem>>(iter: T) -> Self {
let mut res = Self::new(vec![]);
let mut current = Section::new(vec![]);
for item in iter {
match item {
ParcelItem::Data(chunk) => current.chunks.push(chunk),
ParcelItem::Separator | ParcelItem::End => {
res.sections.push(current);
current = Section::new(vec![]);
}
}
}
if !current.is_empty() {
res.sections.push(current);
}
res
}
}
#[derive(Debug, Clone)]
pub struct Section {
pub chunks: Vec<Vec<u8>>,
}
impl Section {
pub fn new(chunks: Vec<Vec<u8>>) -> Self {
Self { chunks }
}
}
impl Deref for Section {
type Target = Vec<Vec<u8>>;
fn deref(&self) -> &Self::Target {
&self.chunks
}
}
impl PartialEq<[&str]> for Section {
fn eq(&self, other: &[&str]) -> bool {
if self.chunks.len() != other.len() {
return false;
}
for (a, b) in self.chunks.iter().zip(other) {
if a != b.as_bytes() {
return false;
}
}
true
}
}