serializer/machine/
blocking.rs1use std::fs;
8use std::io;
9use std::path::Path;
10
11use super::AsyncFileIO;
12
13#[derive(Debug, Clone, Copy, Default)]
18pub struct BlockingIO;
19
20impl BlockingIO {
21 pub fn new() -> Self {
23 Self
24 }
25}
26
27impl AsyncFileIO for BlockingIO {
28 fn read_sync(&self, path: &Path) -> io::Result<Vec<u8>> {
29 fs::read(path)
30 }
31
32 fn write_sync(&self, path: &Path, data: &[u8]) -> io::Result<()> {
33 if let Some(parent) = path.parent() {
35 if !parent.as_os_str().is_empty() && !parent.exists() {
36 fs::create_dir_all(parent)?;
37 }
38 }
39 fs::write(path, data)
40 }
41
42 fn read_batch_sync(&self, paths: &[&Path]) -> io::Result<Vec<io::Result<Vec<u8>>>> {
43 Ok(paths.iter().copied().map(fs::read).collect())
44 }
45
46 fn write_batch_sync(&self, files: &[(&Path, &[u8])]) -> io::Result<Vec<io::Result<()>>> {
47 Ok(files
48 .iter()
49 .map(|(path, data)| {
50 if let Some(parent) = path.parent() {
52 if !parent.as_os_str().is_empty() && !parent.exists() {
53 fs::create_dir_all(parent)?;
54 }
55 }
56 fs::write(path, data)
57 })
58 .collect())
59 }
60
61 fn backend_name(&self) -> &'static str {
62 "blocking"
63 }
64
65 fn is_available(&self) -> bool {
66 true }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 #[cfg(test)]
74 use tempfile::TempDir;
76
77 #[test]
78 fn test_blocking_read_write() {
79 let dir = TempDir::new().unwrap();
80 let path = dir.path().join("test.txt");
81 let io = BlockingIO::new();
82
83 let data = b"Hello, World!";
84 io.write_sync(&path, data).unwrap();
85
86 let read_data = io.read_sync(&path).unwrap();
87 assert_eq!(read_data, data);
88 }
89
90 #[test]
91 fn test_blocking_batch_operations() {
92 let dir = TempDir::new().unwrap();
93 let io = BlockingIO::new();
94
95 let files: Vec<_> = (0..3)
97 .map(|i| {
98 let path = dir.path().join(format!("file{}.txt", i));
99 let data = format!("Content {}", i);
100 (path, data)
101 })
102 .collect();
103
104 let write_refs: Vec<_> = files
105 .iter()
106 .map(|(p, d)| (p.as_path(), d.as_bytes()))
107 .collect();
108 let write_results = io.write_batch_sync(&write_refs).unwrap();
109 assert!(write_results.iter().all(|r| r.is_ok()));
110
111 let paths: Vec<_> = files.iter().map(|(p, _)| p.as_path()).collect();
113 let read_results = io.read_batch_sync(&paths).unwrap();
114
115 for (i, result) in read_results.iter().enumerate() {
116 let data = result.as_ref().unwrap();
117 assert_eq!(String::from_utf8_lossy(data), format!("Content {}", i));
118 }
119 }
120
121 #[test]
122 fn test_blocking_creates_parent_dirs() {
123 let dir = TempDir::new().unwrap();
124 let path = dir.path().join("nested").join("dir").join("test.txt");
125 let io = BlockingIO::new();
126
127 io.write_sync(&path, b"test").unwrap();
128 assert!(path.exists());
129 }
130
131 #[test]
132 fn test_blocking_backend_name() {
133 let io = BlockingIO::new();
134 assert_eq!(io.backend_name(), "blocking");
135 assert!(io.is_available());
136 }
137}