1#![allow(missing_docs)]
4#![allow(clippy::missing_errors_doc)]
5#![allow(clippy::missing_panics_doc)]
6
7use std::io::{Read, Write};
8
9pub use dory_derive::{DoryDeserialize, DorySerialize, Valid};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Compress {
14 Yes,
15 No,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum Validate {
20 Yes,
21 No,
22}
23
24#[derive(Debug, thiserror::Error)]
25pub enum SerializationError {
26 #[error("IO error: {0}")]
27 IoError(#[from] std::io::Error),
28
29 #[error("Invalid data: {0}")]
30 InvalidData(String),
31
32 #[error("Unexpected data")]
33 UnexpectedData,
34}
35
36pub trait Valid {
39 fn check(&self) -> Result<(), SerializationError>;
41
42 fn batch_check<'a>(batch: impl Iterator<Item = &'a Self>) -> Result<(), SerializationError>
44 where
45 Self: 'a,
46 {
47 for item in batch {
48 item.check()?;
49 }
50 Ok(())
51 }
52}
53
54pub trait DorySerialize {
56 fn serialize_with_mode<W: Write>(
58 &self,
59 writer: W,
60 compress: Compress,
61 ) -> Result<(), SerializationError>;
62
63 fn serialized_size(&self, compress: Compress) -> usize;
65
66 fn serialize_compressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
68 self.serialize_with_mode(writer, Compress::Yes)
69 }
70
71 fn compressed_size(&self) -> usize {
73 self.serialized_size(Compress::Yes)
74 }
75
76 fn serialize_uncompressed<W: Write>(&self, writer: W) -> Result<(), SerializationError> {
78 self.serialize_with_mode(writer, Compress::No)
79 }
80
81 fn uncompressed_size(&self) -> usize {
83 self.serialized_size(Compress::No)
84 }
85}
86
87pub trait DoryDeserialize {
89 fn deserialize_with_mode<R: Read>(
91 reader: R,
92 compress: Compress,
93 validate: Validate,
94 ) -> Result<Self, SerializationError>
95 where
96 Self: Sized;
97
98 fn deserialize_compressed<R: Read>(reader: R) -> Result<Self, SerializationError>
100 where
101 Self: Sized,
102 {
103 Self::deserialize_with_mode(reader, Compress::Yes, Validate::Yes)
104 }
105
106 fn deserialize_compressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError>
111 where
112 Self: Sized,
113 {
114 Self::deserialize_with_mode(reader, Compress::Yes, Validate::No)
115 }
116
117 fn deserialize_uncompressed<R: Read>(reader: R) -> Result<Self, SerializationError>
119 where
120 Self: Sized,
121 {
122 Self::deserialize_with_mode(reader, Compress::No, Validate::Yes)
123 }
124
125 fn deserialize_uncompressed_unchecked<R: Read>(reader: R) -> Result<Self, SerializationError>
130 where
131 Self: Sized,
132 {
133 Self::deserialize_with_mode(reader, Compress::No, Validate::No)
134 }
135}
136
137mod primitive_impls {
138 use super::*;
139
140 macro_rules! impl_primitive_serialization {
141 ($t:ty, $size:expr) => {
142 impl Valid for $t {
143 fn check(&self) -> Result<(), SerializationError> {
144 Ok(())
146 }
147 }
148
149 impl DorySerialize for $t {
150 fn serialize_with_mode<W: Write>(
151 &self,
152 mut writer: W,
153 _compress: Compress,
154 ) -> Result<(), SerializationError> {
155 writer.write_all(&self.to_le_bytes())?;
156 Ok(())
157 }
158
159 fn serialized_size(&self, _compress: Compress) -> usize {
160 $size
161 }
162 }
163
164 impl DoryDeserialize for $t {
165 fn deserialize_with_mode<R: Read>(
166 mut reader: R,
167 _compress: Compress,
168 _validate: Validate,
169 ) -> Result<Self, SerializationError> {
170 let mut bytes = [0u8; $size];
171 reader.read_exact(&mut bytes)?;
172 Ok(<$t>::from_le_bytes(bytes))
173 }
174 }
175 };
176 }
177
178 impl_primitive_serialization!(u8, 1);
179 impl_primitive_serialization!(u16, 2);
180 impl_primitive_serialization!(u32, 4);
181 impl_primitive_serialization!(u64, 8);
182 impl_primitive_serialization!(usize, std::mem::size_of::<usize>());
183 impl_primitive_serialization!(i8, 1);
184 impl_primitive_serialization!(i16, 2);
185 impl_primitive_serialization!(i32, 4);
186 impl_primitive_serialization!(i64, 8);
187
188 impl Valid for bool {
189 fn check(&self) -> Result<(), SerializationError> {
190 Ok(())
191 }
192 }
193
194 impl DorySerialize for bool {
195 fn serialize_with_mode<W: Write>(
196 &self,
197 mut writer: W,
198 _compress: Compress,
199 ) -> Result<(), SerializationError> {
200 writer.write_all(&[*self as u8])?;
201 Ok(())
202 }
203
204 fn serialized_size(&self, _compress: Compress) -> usize {
205 1
206 }
207 }
208
209 impl DoryDeserialize for bool {
210 fn deserialize_with_mode<R: Read>(
211 mut reader: R,
212 _compress: Compress,
213 _validate: Validate,
214 ) -> Result<Self, SerializationError> {
215 let mut byte = [0u8; 1];
216 reader.read_exact(&mut byte)?;
217 match byte[0] {
218 0 => Ok(false),
219 1 => Ok(true),
220 _ => Err(SerializationError::InvalidData(
221 "Invalid bool value".to_string(),
222 )),
223 }
224 }
225 }
226
227 impl<T: Valid> Valid for Vec<T> {
228 fn check(&self) -> Result<(), SerializationError> {
229 for item in self {
230 item.check()?;
231 }
232 Ok(())
233 }
234 }
235
236 impl<T: DorySerialize> DorySerialize for Vec<T> {
237 fn serialize_with_mode<W: Write>(
238 &self,
239 mut writer: W,
240 compress: Compress,
241 ) -> Result<(), SerializationError> {
242 (self.len() as u64).serialize_with_mode(&mut writer, compress)?;
243 for item in self {
244 item.serialize_with_mode(&mut writer, compress)?;
245 }
246 Ok(())
247 }
248
249 fn serialized_size(&self, compress: Compress) -> usize {
250 let len_size = 8;
251 let items_size: usize = self.iter().map(|item| item.serialized_size(compress)).sum();
252 len_size + items_size
253 }
254 }
255
256 impl<T: DoryDeserialize> DoryDeserialize for Vec<T> {
257 fn deserialize_with_mode<R: Read>(
258 mut reader: R,
259 compress: Compress,
260 validate: Validate,
261 ) -> Result<Self, SerializationError> {
262 let len = u64::deserialize_with_mode(&mut reader, compress, validate)? as usize;
263 let mut vec = Vec::with_capacity(len);
264 for _ in 0..len {
265 vec.push(T::deserialize_with_mode(&mut reader, compress, validate)?);
266 }
267 Ok(vec)
268 }
269 }
270}