1use super::{
7 buffer::{self, cmp_table_header_name, BufferError, BufferExt, Res},
8 slice::{FDBBucketHeaderSlice, FDBColumnHeaderSlice, FDBFieldDataSlice, FDBTableHeaderSlice},
9 BaseHandle, Handle,
10};
11use assembly_fdb_core::{
12 file::{
13 FDBBucketHeader, FDBColumnHeader, FDBFieldData, FDBHeader, FDBRowHeader,
14 FDBRowHeaderListEntry, FDBTableDataHeader, FDBTableDefHeader, FDBTableHeader,
15 },
16 value::{file::FDBFieldValue, UnknownValueType, ValueType},
17};
18use displaydoc::Display;
19use latin1str::Latin1Str;
20use std::{convert::TryFrom, error::Error, fmt, ops::Deref, result::Result as StdResult};
21
22pub type Result<'a, T> = std::result::Result<Handle<'a, T>, BufferError>;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct BaseError<P: Deref>
28where
29 P::Target: AsRef<[u8]>,
30{
31 mem: P,
32 kind: BaseErrorKind,
33}
34
35impl<P: Deref + fmt::Debug> Error for BaseError<P>
36where
37 P::Target: AsRef<[u8]>,
38{
39 fn source(&self) -> Option<&(dyn Error + 'static)> {
40 match &self.kind {
41 BaseErrorKind::Unimplemented => None,
42 BaseErrorKind::Buffer(e) => Some(e),
43 }
44 }
45}
46
47impl<P: Deref> fmt::Display for BaseError<P>
48where
49 P::Target: AsRef<[u8]>,
50{
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 self.kind.fmt(f)
53 }
54}
55
56impl<P: Deref> BaseError<P>
57where
58 P::Target: AsRef<[u8]>,
59{
60 pub fn unimplemented(mem: P) -> Self {
62 Self {
63 mem,
64 kind: BaseErrorKind::Unimplemented,
65 }
66 }
67}
68
69#[derive(Debug, Display, Clone, PartialEq, Eq)]
70pub enum BaseErrorKind {
72 Unimplemented,
74 Buffer(BufferError),
76}
77
78impl From<BufferError> for BaseErrorKind {
79 fn from(b: BufferError) -> Self {
80 Self::Buffer(b)
81 }
82}
83
84pub type BaseResult<P, T> = std::result::Result<BaseHandle<P, T>, BaseError<P>>;
86
87impl<P: Deref, T> BaseHandle<P, T>
88where
89 P::Target: AsRef<[u8]>,
90{
91 pub fn map_into<M, O, E>(self, map: M) -> BaseResult<P, O>
93 where
94 M: Fn(&[u8], T) -> std::result::Result<O, E>,
95 E: Into<BaseErrorKind>,
96 {
97 match map(self.mem.deref().as_ref(), self.raw) {
98 Ok(new_raw) => Ok(BaseHandle {
99 mem: self.mem,
100 raw: new_raw,
101 }),
102 Err(e) => Err(BaseError {
103 mem: self.mem,
104 kind: e.into(),
105 }),
106 }
107 }
108}
109
110impl<P: Deref> BaseHandle<P, ()>
111where
112 P::Target: AsRef<[u8]>,
113{
114 pub fn into_tables(self) -> BaseResult<P, FDBHeader> {
116 self.map_into(buffer::header)
117 }
118}
119
120impl<P: Deref> BaseHandle<P, FDBHeader>
121where
122 P::Target: AsRef<[u8]>,
123{
124 pub fn into_table_at(self, index: usize) -> BaseResult<P, Option<FDBTableHeader>> {
126 self.map_into(|buf, header| -> Res<Option<FDBTableHeader>> {
127 let slice = buffer::table_headers(buf, &header)?;
128 Ok(slice.get(index).copied())
129 })
130 }
131
132 pub fn into_table_by_name(self, name: &Latin1Str) -> BaseResult<P, Option<FDBTableHeader>> {
134 self.map_into(|buf, header| -> Res<Option<FDBTableHeader>> {
135 let slice = buffer::table_headers(buf, &header)?;
136 match slice.binary_search_by(|t| cmp_table_header_name(buf, name.as_bytes(), *t)) {
137 Ok(index) => Ok(Some(*slice.get(index).unwrap())),
138 Err(_) => Ok(None),
139 }
140 })
141 }
142}
143
144impl<P: Deref> BaseHandle<P, FDBTableHeader>
145where
146 P::Target: AsRef<[u8]>,
147{
148 pub fn into_definition(self) -> BaseResult<P, FDBTableDefHeader> {
150 self.map_into(buffer::table_definition)
151 }
152
153 pub fn into_data(self) -> BaseResult<P, FDBTableDataHeader> {
155 self.map_into(buffer::table_data)
156 }
157}
158
159impl<P: Deref> BaseHandle<P, FDBTableDataHeader>
160where
161 P::Target: AsRef<[u8]>,
162{
163 pub fn get_bucket_for_hash(self, id: u32) -> BaseResult<P, FDBBucketHeader> {
165 self.map_into::<_, _, BufferError>(|buf, raw| {
166 let bucket_count = raw.buckets.count as usize;
167 let buckets_addr = raw.buckets.base_offset as usize;
168 let slice: &[FDBBucketHeader] = buffer::get_slice_at(buf, buckets_addr, bucket_count)?;
169 Ok(slice[id as usize % bucket_count])
170 })
171 }
172}
173
174pub type Database<'a> = Handle<'a, ()>;
176
177impl<'a> Database<'a> {
178 pub fn new_ref(mem: &'a [u8]) -> Self {
180 Self { mem, raw: () }
181 }
182
183 pub fn tables(&self) -> Result<'a, FDBHeader> {
185 let header = buffer::header(self.mem, ())?;
186 Ok(self.wrap(header))
187 }
188}
189
190impl<'a> Handle<'a, FDBHeader> {
191 pub fn table_count(&self) -> u32 {
193 self.raw.tables.count
194 }
195
196 pub fn table_header_list(&self) -> Result<'a, FDBTableHeaderSlice<'a>> {
198 let len = self.table_count() as usize * 8;
199 let buf = self
200 .mem
201 .get_len_at(self.raw.tables.base_offset as usize, len)?;
202 Ok(self.wrap(FDBTableHeaderSlice(buf)))
203 }
204}
205
206impl<'a> IntoIterator for &Handle<'a, FDBTableHeaderSlice<'a>> {
207 type Item = Handle<'a, FDBTableHeader>;
208 type IntoIter = Handle<'a, FDBTableHeaderSlice<'a>>;
209
210 fn into_iter(self) -> Self::IntoIter {
211 *self
212 }
213}
214
215impl<'a> DoubleEndedIterator for Handle<'a, FDBTableHeaderSlice<'a>> {
224 fn next_back(&mut self) -> Option<Self::Item> {
225 self.raw
226 .next_back()
227 .map(|raw| Handle { mem: self.mem, raw })
228 }
229}
230
231impl<'a> Handle<'a, FDBTableHeader> {
232 pub fn table_def_header(&self) -> Result<'a, FDBTableDefHeader> {
234 let raw = self.mem.table_def_header(self.raw.table_def_header_addr)?;
235 Ok(self.wrap(raw))
236 }
237
238 pub fn table_data_header(&self) -> Result<'a, FDBTableDataHeader> {
240 let raw = self
241 .mem
242 .table_data_header(self.raw.table_data_header_addr)?;
243 Ok(self.wrap(raw))
244 }
245}
246
247impl<'a> Handle<'a, FDBTableDefHeader> {
248 pub fn column_count(&self) -> u32 {
250 self.raw.column_count
251 }
252
253 pub fn table_name(&self) -> Result<'a, &'a Latin1Str> {
255 let raw = self.mem.string(self.raw.table_name_addr)?;
256 Ok(self.wrap(raw))
257 }
258
259 pub fn column_header_list(&self) -> Result<'a, FDBColumnHeaderSlice<'a>> {
261 let len = self.column_count() as usize * 8;
262 let buf = self
263 .mem
264 .get_len_at(self.raw.column_header_list_addr as usize, len)?;
265 Ok(self.wrap(FDBColumnHeaderSlice(buf)))
266 }
267}
268
269#[cfg(feature = "serde-derives")]
270impl<'a> serde::Serialize for Handle<'a, FDBTableDefHeader> {
271 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
272 where
273 S: serde::Serializer,
274 {
275 use serde::ser::SerializeStruct;
276 let mut tbl = serializer.serialize_struct("Table", 2)?;
277 tbl.serialize_field("name", self.table_name().unwrap().raw().decode().as_ref())?;
278 tbl.serialize_field("columns", &self.column_header_list().unwrap())?;
279 tbl.end()
280 }
281}
282
283impl<'a> IntoIterator for &Handle<'a, FDBColumnHeaderSlice<'a>> {
284 type Item = Handle<'a, FDBColumnHeader>;
285 type IntoIter = Handle<'a, FDBColumnHeaderSlice<'a>>;
286
287 fn into_iter(self) -> Self::IntoIter {
288 *self
289 }
290}
291
292#[cfg(feature = "serde-derives")]
301impl<'a> serde::Serialize for Handle<'a, FDBColumnHeaderSlice<'a>> {
302 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
303 where
304 S: serde::Serializer,
305 {
306 use serde::ser::SerializeSeq;
307 let len = self.raw().len();
308 let mut seq = serializer.serialize_seq(Some(len))?;
309 for element in self.into_iter() {
310 seq.serialize_element(&element)?;
311 }
312 seq.end()
313 }
314}
315
316impl<'a> DoubleEndedIterator for Handle<'a, FDBColumnHeaderSlice<'a>> {
317 fn next_back(&mut self) -> Option<Self::Item> {
318 self.raw
319 .next_back()
320 .map(|raw| Handle { mem: self.mem, raw })
321 }
322}
323
324impl<'a> Handle<'a, FDBColumnHeader> {
325 pub fn column_name(&self) -> Result<'a, &'a Latin1Str> {
327 let raw = self.mem.string(self.raw.column_name_addr)?;
328 Ok(self.wrap(raw))
329 }
330
331 pub fn column_data_type(&self) -> StdResult<ValueType, UnknownValueType> {
333 ValueType::try_from(self.raw.column_data_type)
334 }
335}
336
337#[cfg(feature = "serde-derives")]
338impl<'a> serde::Serialize for Handle<'a, FDBColumnHeader> {
339 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
340 where
341 S: serde::Serializer,
342 {
343 use serde::ser::SerializeStruct;
344 let mut col = serializer.serialize_struct("Column", 2)?;
345 col.serialize_field("name", self.column_name().unwrap().raw().decode().as_ref())?;
346 col.serialize_field("data_type", &self.column_data_type().unwrap())?;
347 col.end()
348 }
349}
350
351impl<'a> Handle<'a, FDBTableDataHeader> {
352 pub fn bucket_count(&self) -> u32 {
354 self.raw.buckets.count
355 }
356
357 pub fn bucket_header_list(&self) -> Result<'a, FDBBucketHeaderSlice<'a>> {
359 let len = self.bucket_count() as usize * 4;
360 let buf = self
361 .mem
362 .get_len_at(self.raw.buckets.base_offset as usize, len)?;
363 Ok(self.wrap(FDBBucketHeaderSlice(buf)))
364 }
365}
366
367impl<'a> IntoIterator for &Handle<'a, FDBBucketHeaderSlice<'a>> {
368 type Item = Handle<'a, FDBBucketHeader>;
369 type IntoIter = Handle<'a, FDBBucketHeaderSlice<'a>>;
370
371 fn into_iter(self) -> Self::IntoIter {
372 *self
373 }
374}
375
376impl<'a> DoubleEndedIterator for Handle<'a, FDBBucketHeaderSlice<'a>> {
389 fn next_back(&mut self) -> Option<Self::Item> {
390 self.raw
391 .next_back()
392 .map(|raw| Handle { mem: self.mem, raw })
393 }
394}
395
396impl<'a> Handle<'a, FDBBucketHeader> {
397 pub fn first(&self) -> Option<Result<'a, FDBRowHeaderListEntry>> {
399 let addr = self.raw.row_header_list_head_addr;
400 if addr == 0xFFFFFFFF {
401 None
402 } else {
403 Some(self.mem.row_header_list_entry(addr).map(|e| self.wrap(e)))
404 }
405 }
406
407 pub fn row_header_iter(&self) -> Handle<'a, FDBRowHeaderRef> {
409 self.wrap(FDBRowHeaderRef(self.raw.row_header_list_head_addr))
410 }
411}
412
413#[derive(Debug, Copy, Clone)]
414#[allow(clippy::upper_case_acronyms)]
416pub struct FDBRowHeaderRef(u32);
417
418impl<'a> Iterator for Handle<'a, FDBRowHeaderRef> {
419 type Item = Result<'a, FDBRowHeader>;
420
421 fn next(&mut self) -> Option<Self::Item> {
422 let addr = self.raw.0;
423 if addr == 0xFFFFFFFF {
424 None
425 } else {
426 match self.mem.row_header_list_entry(addr) {
427 Ok(e) => {
428 self.raw.0 = e.row_header_list_next_addr;
429 match self.mem.row_header(e.row_header_addr) {
430 Ok(rh) => Some(Ok(self.wrap(rh))),
431 Err(e) => {
432 self.raw.0 = 0xFFFFFFFF;
433 Some(Err(e))
434 }
435 }
436 }
437 Err(e) => {
438 self.raw.0 = 0xFFFFFFFF;
439 Some(Err(e))
440 }
441 }
442 }
443 }
444}
445
446impl<'a> Handle<'a, FDBRowHeaderListEntry> {
447 pub fn next(&self) -> Option<Result<'a, FDBRowHeaderListEntry>> {
449 let addr = self.raw.row_header_list_next_addr;
450 if addr == 0xFFFFFFFF {
451 None
452 } else {
453 Some(self.mem.row_header_list_entry(addr).map(|e| self.wrap(e)))
454 }
455 }
456
457 pub fn row_header(&self) -> Result<'a, FDBRowHeader> {
459 let e = self.mem.row_header(self.raw.row_header_addr)?;
460 Ok(self.wrap(e))
461 }
462}
463
464impl<'a> Handle<'a, FDBRowHeader> {
465 pub fn field_count(&self) -> u32 {
467 self.raw.fields.count
468 }
469
470 pub fn field_data_list(&self) -> Result<'a, FDBFieldDataSlice<'a>> {
472 let len = self.field_count() as usize * 8;
473 let buf = self
474 .mem
475 .get_len_at(self.raw.fields.base_offset as usize, len)?;
476 Ok(self.wrap(FDBFieldDataSlice(buf)))
477 }
478}
479
480impl<'a> IntoIterator for &Handle<'a, FDBFieldDataSlice<'a>> {
481 type Item = Handle<'a, FDBFieldData>;
482 type IntoIter = Handle<'a, FDBFieldDataSlice<'a>>;
483
484 fn into_iter(self) -> Self::IntoIter {
485 *self
486 }
487}
488
489impl<'a> DoubleEndedIterator for Handle<'a, FDBFieldDataSlice<'a>> {
498 fn next_back(&mut self) -> Option<Self::Item> {
499 self.raw
500 .next_back()
501 .map(|raw| Handle { mem: self.mem, raw })
502 }
503}
504
505impl<'a> Handle<'a, FDBFieldData> {
506 pub fn try_get_value(&self) -> Result<'a, FDBFieldValue> {
508 Ok(self.map(|_, r| FDBFieldValue::try_from(r).unwrap()))
510 }
511}