Skip to main content

fwob_v1/
core_api.rs

1use std::{fs::File, ops::Range, path::Path};
2
3use fwob_core::{
4    FileInfo, FormatVersion, Key, Maintenance, OwnedFrame, Reader as CoreReader, ReaderBackend,
5    ReaderOptions, Result as CoreResult, Schema, VerificationReport, Writer as CoreWriter,
6    WriterBackend, WriterFactory,
7};
8
9use crate::{Reader, Writer, WriterOptions};
10
11pub struct ReaderAdapter {
12    reader: Reader<File>,
13    string_table: Vec<String>,
14}
15
16impl ReaderAdapter {
17    pub fn open(
18        path: impl AsRef<Path>,
19        key_field_index: usize,
20    ) -> crate::Result<(Self, CompatibleWriterFactory)> {
21        let mut reader = Reader::open(path, key_field_index)?;
22        let string_table = reader.read_string_table()?;
23        let factory = CompatibleWriterFactory {
24            schema: reader.schema().clone(),
25            string_table_preserved_length: reader.header().string_table_preserved_length,
26        };
27        Ok((
28            Self {
29                reader,
30                string_table,
31            },
32            factory,
33        ))
34    }
35}
36
37impl FileInfo for ReaderAdapter {
38    fn format_version(&self) -> FormatVersion {
39        FormatVersion::V1
40    }
41
42    fn schema(&self) -> &Schema {
43        self.reader.schema()
44    }
45
46    fn title(&self) -> &str {
47        &self.reader.header().title
48    }
49
50    fn frame_count(&self) -> u64 {
51        self.reader.frame_count()
52    }
53
54    fn string_table(&self) -> &[String] {
55        &self.string_table
56    }
57}
58
59impl ReaderBackend for ReaderAdapter {
60    fn read_frame(&mut self, index: u64) -> CoreResult<Option<OwnedFrame>> {
61        self.reader
62            .read_frame_at(index)
63            .map_err(fwob_core::FwobError::backend)
64    }
65
66    fn read_key(&mut self, index: u64) -> CoreResult<Option<Key>> {
67        self.reader
68            .read_key_at(index)
69            .map_err(fwob_core::FwobError::backend)
70    }
71
72    fn lower_bound(&mut self, key: Key) -> CoreResult<u64> {
73        self.reader
74            .lower_bound(key)
75            .map_err(fwob_core::FwobError::backend)
76    }
77
78    fn upper_bound(&mut self, key: Key) -> CoreResult<u64> {
79        self.reader
80            .upper_bound(key)
81            .map_err(fwob_core::FwobError::backend)
82    }
83
84    fn equal_range(&mut self, key: Key) -> CoreResult<Range<u64>> {
85        let (start, end) = self
86            .reader
87            .equal_range(key)
88            .map_err(fwob_core::FwobError::backend)?;
89        Ok(start..end)
90    }
91}
92
93pub struct CompatibleWriterFactory {
94    schema: Schema,
95    string_table_preserved_length: u32,
96}
97
98impl WriterFactory for CompatibleWriterFactory {
99    fn create(
100        &mut self,
101        path: &Path,
102        title: &str,
103        string_table: &[String],
104    ) -> CoreResult<CoreWriter> {
105        let required = string_table
106            .iter()
107            .map(|value| value.len().saturating_add(5))
108            .sum::<usize>();
109        let mut options = WriterOptions::new(title);
110        options.string_table_preserved_length = self
111            .string_table_preserved_length
112            .max(u32::try_from(required).unwrap_or(u32::MAX));
113        create_writer(path, self.schema.clone(), options, string_table)
114            .map_err(fwob_core::FwobError::backend)
115    }
116}
117
118pub struct WriterAdapter {
119    writer: Writer<File>,
120    string_table: Vec<String>,
121}
122
123impl WriterAdapter {
124    pub fn create(
125        path: impl AsRef<Path>,
126        schema: Schema,
127        options: WriterOptions,
128        string_table: &[String],
129    ) -> crate::Result<Self> {
130        let mut writer = Writer::create(path, schema, options)?;
131        for value in string_table {
132            writer.append_string(value)?;
133        }
134        Ok(Self {
135            writer,
136            string_table: string_table.to_vec(),
137        })
138    }
139
140    pub fn open_append(path: impl AsRef<Path>, key_field_index: usize) -> crate::Result<Self> {
141        let mut reader = Reader::open(path.as_ref(), key_field_index)?;
142        let string_table = reader.read_string_table()?;
143        drop(reader);
144        Ok(Self {
145            writer: Writer::open_append(path, key_field_index)?,
146            string_table,
147        })
148    }
149}
150
151impl FileInfo for WriterAdapter {
152    fn format_version(&self) -> FormatVersion {
153        FormatVersion::V1
154    }
155
156    fn schema(&self) -> &Schema {
157        self.writer.schema()
158    }
159
160    fn title(&self) -> &str {
161        &self.writer.header().title
162    }
163
164    fn frame_count(&self) -> u64 {
165        self.writer.frame_count()
166    }
167
168    fn string_table(&self) -> &[String] {
169        &self.string_table
170    }
171}
172
173impl WriterBackend for WriterAdapter {
174    fn append_frame(&mut self, frame: &[u8]) -> CoreResult<()> {
175        self.writer
176            .append_frame(frame)
177            .map_err(fwob_core::FwobError::backend)
178    }
179
180    fn append_presorted_frames(&mut self, frames: &[u8]) -> CoreResult<()> {
181        self.writer
182            .append_presorted_raw_frames(frames)
183            .map_err(fwob_core::FwobError::backend)
184    }
185
186    fn append_frames_transactional(&mut self, frames: &[u8]) -> CoreResult<()> {
187        self.writer
188            .append_raw_frames_transactional(frames)
189            .map_err(fwob_core::FwobError::backend)
190    }
191
192    fn finish(self: Box<Self>) -> CoreResult<()> {
193        Ok(())
194    }
195}
196
197pub fn open_reader(path: impl AsRef<Path>, key_field_index: usize) -> crate::Result<CoreReader> {
198    let (reader, factory) = ReaderAdapter::open(path, key_field_index)?;
199    Ok(CoreReader::from_parts(reader, factory))
200}
201
202pub fn create_writer(
203    path: impl AsRef<Path>,
204    schema: Schema,
205    options: WriterOptions,
206    string_table: &[String],
207) -> crate::Result<CoreWriter> {
208    Ok(CoreWriter::from_backend(WriterAdapter::create(
209        path,
210        schema,
211        options,
212        string_table,
213    )?))
214}
215
216pub fn open_writer(path: impl AsRef<Path>, key_field_index: usize) -> crate::Result<CoreWriter> {
217    Ok(CoreWriter::from_backend(WriterAdapter::open_append(
218        path,
219        key_field_index,
220    )?))
221}
222
223#[derive(Debug, Default, Clone, Copy)]
224pub struct MaintenanceService;
225
226impl Maintenance for MaintenanceService {
227    fn format_version(&self) -> FormatVersion {
228        FormatVersion::V1
229    }
230
231    fn light_verify(&self, path: &Path, options: ReaderOptions) -> CoreResult<VerificationReport> {
232        let (reader, _) = ReaderAdapter::open(path, options.v1_key_field_index)
233            .map_err(fwob_core::FwobError::backend)?;
234        Ok(VerificationReport {
235            format_version: FormatVersion::V1,
236            frame_count: reader.frame_count(),
237            string_count: reader.string_table().len() as u32,
238            file_length: std::fs::metadata(path)?.len(),
239        })
240    }
241
242    fn verify(&self, path: &Path, options: ReaderOptions) -> CoreResult<VerificationReport> {
243        self.light_verify(path, options)?;
244        let report = crate::verify_file(path, options.v1_key_field_index)
245            .map_err(fwob_core::FwobError::backend)?;
246        Ok(VerificationReport {
247            format_version: FormatVersion::V1,
248            frame_count: report.frame_count,
249            string_count: report.string_count,
250            file_length: report.file_length,
251        })
252    }
253
254    fn repair(&self, path: &Path, options: ReaderOptions) -> CoreResult<VerificationReport> {
255        let report = crate::repair_committed_tail(path, options.v1_key_field_index)
256            .map_err(fwob_core::FwobError::backend)?;
257        Ok(VerificationReport {
258            format_version: FormatVersion::V1,
259            frame_count: report.frame_count,
260            string_count: report.string_count,
261            file_length: report.file_length,
262        })
263    }
264}