assembly_data/fdb/ro/
handle.rs

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