1use std::{
2 io::{Read, Write},
3 ops::Deref,
4};
5
6use crate::error::Error;
7
8mod decoder;
9mod encoder;
10
11pub use decoder::{ParcelDecoder, ParcelItem};
12pub use encoder::ParcelEncoder;
13
14const MARKER_SEP: [u8; 4] = [0x30, 0x30, 0x30, 0x31];
15const MARKER_END: [u8; 4] = [0x30, 0x30, 0x30, 0x30];
16
17#[derive(Debug, Clone)]
18pub struct Parcel {
19 pub sections: Vec<Section>,
20}
21
22impl Parcel {
23 #[must_use]
24 pub fn new(sections: Vec<Section>) -> Self {
25 Self { sections }
26 }
27
28 pub fn from_bytes(data: &[u8]) -> Result<Self, Error> {
34 let dec = ParcelDecoder::new(data);
35 dec.collect()
36 }
37
38 pub fn from_reader<R: Read>(reader: R) -> Result<Self, Error> {
44 let dec = ParcelDecoder::new(reader);
45 dec.collect()
46 }
47
48 pub fn write_to<W: Write>(&self, writer: W) -> Result<(), Error> {
54 let mut enc = ParcelEncoder::new(writer);
55
56 let mut first = true;
57
58 for section in &self.sections {
59 if first {
60 first = false;
61 } else {
62 enc.new_section()?;
63 }
64
65 for data in section.iter() {
66 enc.write_data(data)?;
67 }
68 }
69
70 enc.finish()
71 }
72}
73
74impl FromIterator<ParcelItem> for Parcel {
75 fn from_iter<T: IntoIterator<Item = ParcelItem>>(iter: T) -> Self {
76 let mut res = Self::new(vec![]);
77 let mut current = Section::new(vec![]);
78
79 for item in iter {
80 match item {
81 ParcelItem::Data(chunk) => current.chunks.push(chunk),
82 ParcelItem::Separator | ParcelItem::End => {
83 res.sections.push(current);
84 current = Section::new(vec![]);
85 }
86 }
87 }
88
89 if !current.is_empty() {
90 res.sections.push(current);
91 }
92
93 res
94 }
95}
96
97#[derive(Debug, Clone)]
98pub struct Section {
99 pub chunks: Vec<Vec<u8>>,
100}
101
102impl Section {
103 pub fn new(chunks: Vec<Vec<u8>>) -> Self {
104 Self { chunks }
105 }
106}
107
108impl Deref for Section {
109 type Target = Vec<Vec<u8>>;
110
111 fn deref(&self) -> &Self::Target {
112 &self.chunks
113 }
114}
115
116impl PartialEq<[&str]> for Section {
117 fn eq(&self, other: &[&str]) -> bool {
118 if self.chunks.len() != other.len() {
119 return false;
120 }
121
122 for (a, b) in self.chunks.iter().zip(other) {
123 if a != b.as_bytes() {
124 return false;
125 }
126 }
127
128 true
129 }
130}