incremental_writer/json/
mod.rs1use serde::{Serialize, Deserialize};
2use std::io::{Write, Seek, SeekFrom};
3
4#[cfg(unix)]
5use std::os::unix::fs::FileExt;
6#[cfg(windows)]
7use std::os::windows::fs::FileExt;
8
9type Result<T> = std::result::Result<T, std::io::Error>;
10
11pub struct IncrementalJsonWriter<T: FileExt + Write + Seek> {
12 buffer: T,
13}
14impl<T: FileExt + Write + Seek> IncrementalJsonWriter<T> {
15 pub fn new(buffer: T) -> Self {
16 IncrementalJsonWriter::<T> {
17 buffer
18 }
19 }
20
21 pub fn write_json<U: Serialize>(&mut self, element: &U) -> Result<usize> {
22 self.write(serde_json::to_string_pretty(&element)?.as_bytes())
23 }
24
25 #[cfg(unix)]
26 fn write_at_offset(&mut self, bytes: &[u8], offset: u64) -> Result<usize> {
27 let bytes_written = self.buffer.write_at(bytes, offset)?;
28 self.buffer.seek(SeekFrom::Current((bytes_written - 2) as i64)).map(|_| bytes_written)
29 }
30 #[cfg(windows)]
31 fn write_at_offset(&mut self, bytes: &[u8], offset: u64) -> Result<usize> {
32 self.buffer.seek_write(bytes, offset)
33 }
34}
35
36impl<T: FileExt + Write + Seek> Write for IncrementalJsonWriter<T> {
37 fn write(&mut self, element: &[u8]) -> Result<usize> {
38 let mut current = self.buffer.seek(SeekFrom::Current(0))?;
39 let mut bytes = vec![];
40
41 if current == 0 {
42 self.buffer.write(b"[\n\n]")?;
43 current = self.buffer.seek(SeekFrom::Current(0))?;
44 } else {
45 bytes.extend(b",\n");
46 }
47
48 bytes.extend(element);
49 bytes.push(b'\n');
50 bytes.push(b']');
51
52 let written = self.write_at_offset(&bytes, current - 2)?;
53
54 let new_position = self.buffer.seek(SeekFrom::Current(0))?;
55 println!("Was: {}, now: {}, total: {}", current, new_position, current + bytes.len() as u64);
56 Ok(written)
57 }
58 fn flush(&mut self) -> Result<()> {
59 self.buffer.flush()
60 }
61}
62
63#[test]
64fn writer_writes_square_brackets_to_buffer() {
65 use std::io::{Read};
66
67 let expect_one = String::from("[\n{\n \"name\": \"Test\",\n \"detail\": 0\n},\
68 \n{\n \"name\": \"Test\",\n \"detail\": 1\n}\n]");
69
70 let expect_two = String::from("[\n{\n \"name\": \"Test\",\n \"detail\": 0\n},\
71 \n{\n \"name\": \"Test\",\n \"detail\": 1\n},\
72 \n{\n \"name\": \"Test\",\n \"detail\": 2\n},\
73 \n{\n \"name\": \"Test\",\n \"detail\": 3\n}\n]");
74
75 let path = "unittest.json";
76 let rows: Vec<Record> = vec![0, 1, 2, 3]
77 .iter()
78 .map(|num| Record { name: String::from("Test"), detail: *num})
79 .collect();
80
81 let writer = std::fs::File::create(path).unwrap();
82 let mut json_writer = IncrementalJsonWriter::new(writer);
83
84 let mut reader = std::fs::File::open(path).unwrap();
85
86 for row in rows.iter().take(2) {
87 json_writer.write_json(&row).unwrap();
88 }
89
90 let mut buffer = String::new();
91 reader.read_to_string(&mut buffer).unwrap();
92 assert_eq!(expect_one, buffer);
93
94 for row in rows.iter().skip(2).take(2) {
95 json_writer.write_json(&row).unwrap();
96 }
97 let mut buffer = String::new();
98 reader.seek(SeekFrom::Start(0)).unwrap();
99 reader.read_to_string(&mut buffer).unwrap();
100 assert_eq!(expect_two, buffer);
101}
102
103#[derive(Serialize, Deserialize, Debug)]
104struct Record {
105 name: String,
106 detail: u32
107}