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}