1use rkyv::util::AlignedVec;
14use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
15use std::path::Path;
16
17use crate::machine::{AsyncFileIO, blocking::BlockingIO};
18
19#[cfg(feature = "parallel")]
20use rayon::prelude::*;
21
22const SMALL_FILE_THRESHOLD: usize = 1024; const PARALLEL_THRESHOLD: usize = 10_000; fn deserialize_checked<T>(bytes: &[u8]) -> Result<T, std::io::Error>
27where
28 T: Archive,
29 T::Archived: for<'a> rkyv::bytecheck::CheckBytes<rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>>
30 + RkyvDeserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
31{
32 let archived = rkyv::access::<T::Archived, rkyv::rancor::Error>(bytes)
33 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?;
34 let mut deserializer = rkyv::de::Pool::new();
35 archived
36 .deserialize(rkyv::rancor::Strategy::wrap(&mut deserializer))
37 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
38}
39
40pub struct OptimizedRkyv {
42 io: BlockingIO,
43}
44
45impl Default for OptimizedRkyv {
46 fn default() -> Self {
47 Self::new()
48 }
49}
50
51impl OptimizedRkyv {
52 pub fn new() -> Self {
54 Self {
55 io: BlockingIO::new(),
56 }
57 }
58
59 pub fn serialize_to_file<T>(&self, value: &T, path: &Path) -> Result<(), std::io::Error>
64 where
65 T: for<'a> RkyvSerialize<
66 rkyv::rancor::Strategy<
67 rkyv::ser::Serializer<
68 AlignedVec,
69 rkyv::ser::allocator::ArenaHandle<'a>,
70 rkyv::ser::sharing::Share,
71 >,
72 rkyv::rancor::Error,
73 >,
74 >,
75 {
76 let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(value)
77 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
78
79 if bytes.len() < SMALL_FILE_THRESHOLD {
81 if let Some(parent) = path.parent() {
82 if !parent.as_os_str().is_empty() && !parent.exists() {
83 std::fs::create_dir_all(parent)?;
84 }
85 }
86 std::fs::write(path, &bytes)
87 } else {
88 self.io.write_sync(path, &bytes)
90 }
91 }
92
93 pub fn deserialize_from_file<T>(&self, path: &Path) -> Result<T, std::io::Error>
95 where
96 T: Archive,
97 T::Archived: for<'a> rkyv::bytecheck::CheckBytes<
98 rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>,
99 > + RkyvDeserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
100 {
101 let metadata = std::fs::metadata(path)?;
103 let file_size = metadata.len() as usize;
104
105 let bytes = if file_size < SMALL_FILE_THRESHOLD {
106 std::fs::read(path)?
108 } else {
109 self.io.read_sync(path)?
111 };
112
113 deserialize_checked::<T>(&bytes)
114 }
115
116 pub fn serialize_batch_smart<T>(&self, items: &[T]) -> Result<Vec<AlignedVec>, std::io::Error>
121 where
122 T: for<'a> RkyvSerialize<
123 rkyv::rancor::Strategy<
124 rkyv::ser::Serializer<
125 AlignedVec,
126 rkyv::ser::allocator::ArenaHandle<'a>,
127 rkyv::ser::sharing::Share,
128 >,
129 rkyv::rancor::Error,
130 >,
131 > + Sync,
132 {
133 if items.is_empty() {
134 return Ok(Vec::new());
135 }
136
137 if items.len() < PARALLEL_THRESHOLD {
139 let mut results = Vec::with_capacity(items.len());
140 for item in items {
141 results.push(
142 rkyv::to_bytes::<rkyv::rancor::Error>(item).map_err(|e| {
143 std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
144 })?,
145 );
146 }
147 return Ok(results);
148 }
149
150 #[cfg(feature = "parallel")]
152 {
153 items
154 .par_iter()
155 .map(|item| {
156 rkyv::to_bytes::<rkyv::rancor::Error>(item)
157 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
158 })
159 .collect()
160 }
161
162 #[cfg(not(feature = "parallel"))]
163 {
164 let mut results = Vec::with_capacity(items.len());
166 for item in items {
167 results.push(
168 rkyv::to_bytes::<rkyv::rancor::Error>(item).map_err(|e| {
169 std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
170 })?,
171 );
172 }
173 Ok(results)
174 }
175 }
176
177 pub fn serialize_batch_to_files<T>(
179 &self,
180 items: &[(T, &Path)],
181 ) -> Result<Vec<std::io::Result<()>>, std::io::Error>
182 where
183 T: for<'a> RkyvSerialize<
184 rkyv::rancor::Strategy<
185 rkyv::ser::Serializer<
186 AlignedVec,
187 rkyv::ser::allocator::ArenaHandle<'a>,
188 rkyv::ser::sharing::Share,
189 >,
190 rkyv::rancor::Error,
191 >,
192 >,
193 {
194 let serialized: Vec<_> = items
196 .iter()
197 .map(|(item, _)| {
198 rkyv::to_bytes::<rkyv::rancor::Error>(item)
199 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))
200 })
201 .collect::<Result<Vec<_>, _>>()?;
202
203 let files: Vec<_> = items
205 .iter()
206 .zip(serialized.iter())
207 .map(|((_, path), bytes)| (*path, bytes.as_ref()))
208 .collect();
209
210 self.io.write_batch_sync(&files)
211 }
212
213 pub fn deserialize_batch_from_files<T>(
215 &self,
216 paths: &[&Path],
217 ) -> Result<Vec<Result<T, std::io::Error>>, std::io::Error>
218 where
219 T: Archive,
220 T::Archived: for<'a> rkyv::bytecheck::CheckBytes<
221 rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>,
222 > + RkyvDeserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
223 {
224 let read_results = self.io.read_batch_sync(paths)?;
225 Ok(read_results
226 .into_iter()
227 .map(|result| result.and_then(|bytes| deserialize_checked::<T>(&bytes)))
228 .collect())
229 }
230
231 pub fn backend_name(&self) -> &'static str {
233 self.io.backend_name()
234 }
235}
236
237#[cfg(feature = "arena")]
241pub struct ArenaRkyv {
242 arena: crate::machine::arena::DxArena,
243 capacity: usize,
244}
245
246#[cfg(feature = "arena")]
247impl ArenaRkyv {
248 pub fn new() -> Self {
250 let capacity = 1024 * 1024; Self {
252 arena: crate::machine::arena::DxArena::new(capacity),
253 capacity,
254 }
255 }
256
257 pub fn with_capacity(capacity: usize) -> Self {
259 Self {
260 arena: crate::machine::arena::DxArena::new(capacity),
261 capacity,
262 }
263 }
264
265 pub fn serialize_batch<T>(&mut self, items: &[T]) -> Result<Vec<AlignedVec>, std::io::Error>
267 where
268 T: for<'a> RkyvSerialize<
269 rkyv::rancor::Strategy<
270 rkyv::ser::Serializer<
271 AlignedVec,
272 rkyv::ser::allocator::ArenaHandle<'a>,
273 rkyv::ser::sharing::Share,
274 >,
275 rkyv::rancor::Error,
276 >,
277 >,
278 {
279 let mut results = Vec::with_capacity(items.len());
280 for item in items {
281 results.push(
282 rkyv::to_bytes::<rkyv::rancor::Error>(item)
283 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?,
284 );
285 }
286 Ok(results)
287 }
288
289 pub fn reset(&mut self) {
291 self.arena = crate::machine::arena::DxArena::new(self.capacity);
292 }
293}
294
295#[cfg(feature = "arena")]
296impl Default for ArenaRkyv {
297 fn default() -> Self {
298 Self::new()
299 }
300}
301
302#[cfg(feature = "compression")]
308pub struct CompressedRkyv {
309 level: crate::machine::compress::CompressionLevel,
310}
311
312#[cfg(feature = "compression")]
313impl CompressedRkyv {
314 pub fn new(level: crate::machine::compress::CompressionLevel) -> Self {
316 Self { level }
317 }
318
319 pub fn serialize_compressed<T>(&mut self, value: &T) -> Result<Vec<u8>, std::io::Error>
324 where
325 T: for<'a> RkyvSerialize<
326 rkyv::rancor::Strategy<
327 rkyv::ser::Serializer<
328 AlignedVec,
329 rkyv::ser::allocator::ArenaHandle<'a>,
330 rkyv::ser::sharing::Share,
331 >,
332 rkyv::rancor::Error,
333 >,
334 >,
335 {
336 let bytes = rkyv::to_bytes::<rkyv::rancor::Error>(value)
337 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
338
339 let compressed = crate::machine::compress::DxCompressed::compress_level(&bytes, self.level);
340 Ok(compressed.to_wire())
341 }
342
343 pub fn deserialize_compressed<T>(&mut self, compressed: &[u8]) -> Result<T, std::io::Error>
345 where
346 T: Archive,
347 T::Archived: for<'a> rkyv::bytecheck::CheckBytes<
348 rkyv::api::high::HighValidator<'a, rkyv::rancor::Error>,
349 > + RkyvDeserialize<T, rkyv::rancor::Strategy<rkyv::de::Pool, rkyv::rancor::Error>>,
350 {
351 let mut dx_compressed = crate::machine::compress::DxCompressed::from_wire(compressed)
353 .map_err(|e| {
354 std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{:?}", e))
355 })?;
356 let bytes = dx_compressed.decompress().map_err(|e| {
357 std::io::Error::new(std::io::ErrorKind::InvalidData, format!("{:?}", e))
358 })?;
359
360 deserialize_checked::<T>(bytes)
361 }
362}
363
364#[cfg(feature = "mmap")]
368pub struct MmapRkyv {
369 _phantom: std::marker::PhantomData<()>,
370}
371
372#[cfg(feature = "mmap")]
373impl MmapRkyv {
374 pub fn new() -> Self {
376 Self {
377 _phantom: std::marker::PhantomData,
378 }
379 }
380
381 pub fn open<T>(&self, path: &Path) -> Result<crate::machine::mmap::DxMmap, std::io::Error>
385 where
386 T: Archive,
387 {
388 crate::machine::mmap::DxMmap::open(path)
389 }
390}
391
392#[cfg(feature = "mmap")]
393impl Default for MmapRkyv {
394 fn default() -> Self {
395 Self::new()
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::*;
402 use rkyv::{Archive, Deserialize, Serialize};
403 use tempfile::TempDir;
404
405 #[derive(Archive, Serialize, Deserialize, Debug, PartialEq)]
406 struct TestData {
407 id: u64,
408 name: String,
409 }
410
411 #[test]
412 fn test_optimized_file_io() {
413 let dir = TempDir::new().unwrap();
414 let path = dir.path().join("test.rkyv");
415 let opt = OptimizedRkyv::new();
416
417 let data = TestData {
418 id: 42,
419 name: "test".to_string(),
420 };
421
422 opt.serialize_to_file(&data, &path).unwrap();
423 let loaded: TestData = opt.deserialize_from_file(&path).unwrap();
424
425 assert_eq!(data, loaded);
426 }
427
428 #[test]
429 fn test_backend_name() {
430 let opt = OptimizedRkyv::new();
431 let backend = opt.backend_name();
432
433 assert_eq!(backend, "blocking");
434 }
435
436 #[cfg(feature = "compression")]
437 #[test]
438 fn test_compressed_rkyv() {
439 use crate::machine::compress::CompressionLevel;
440
441 let mut comp = CompressedRkyv::new(CompressionLevel::Fast);
442 let data = TestData {
443 id: 42,
444 name: "test".to_string(),
445 };
446
447 let compressed = comp.serialize_compressed(&data).unwrap();
448 let decompressed: TestData = comp.deserialize_compressed(&compressed).unwrap();
449
450 assert_eq!(data, decompressed);
451 }
452
453 #[cfg(feature = "arena")]
454 #[test]
455 fn test_arena_rkyv() {
456 let mut arena = ArenaRkyv::new();
457 let items = vec![
458 TestData {
459 id: 1,
460 name: "one".to_string(),
461 },
462 TestData {
463 id: 2,
464 name: "two".to_string(),
465 },
466 TestData {
467 id: 3,
468 name: "three".to_string(),
469 },
470 ];
471
472 let serialized = arena.serialize_batch(&items).unwrap();
473 assert_eq!(serialized.len(), 3);
474 }
475}