Skip to main content

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