assembly_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, 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
22/// Custom result type for this module
23pub type Result<'a, T> = std::result::Result<Handle<'a, T>, BufferError>;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
26/// The basic error type
27pub 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    /// Creates a new error of kind [`BaseErrorKind::Unimplemented`]
61    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)]
70/// The different kinds of [`BaseError`]s
71pub enum BaseErrorKind {
72    /// Unimplemented
73    Unimplemented,
74    /// Failed to read from the buffer
75    Buffer(BufferError),
76}
77
78impl From<BufferError> for BaseErrorKind {
79    fn from(b: BufferError) -> Self {
80        Self::Buffer(b)
81    }
82}
83
84/// The base result type
85pub 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    /// Get the tables
92    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    /// Get the tables
115    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    /// Get the tables
125    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    /// Get the tables
133    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    /// Get the tables
149    pub fn into_definition(self) -> BaseResult<P, FDBTableDefHeader> {
150        self.map_into(buffer::table_definition)
151    }
152
153    /// Get the tables
154    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    /// Get the bucket for a particular id / hash
164    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
174/// The basic database handle
175pub type Database<'a> = Handle<'a, ()>;
176
177impl<'a> Database<'a> {
178    /// Create a new database handle
179    pub fn new_ref(mem: &'a [u8]) -> Self {
180        Self { mem, raw: () }
181    }
182
183    /// Get the header for the local database
184    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    /// Get the number of tables
192    pub fn table_count(&self) -> u32 {
193        self.raw.tables.count
194    }
195
196    /// Get the table header slice
197    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
215/*impl<'a> Iterator for Handle<'a, FDBTableHeaderSlice<'a>> {
216    type Item = Handle<'a, FDBTableHeader>;
217
218    fn next(&mut self) -> Option<Self::Item> {
219        self.raw.next().map(|raw| Handle { mem: self.mem, raw })
220    }
221}*/
222
223impl<'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    /// Get the table definition header
233    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    /// Get the table data header
239    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    /// Get the number of columns
249    pub fn column_count(&self) -> u32 {
250        self.raw.column_count
251    }
252
253    /// Get the name of the table
254    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    /// Get the column header list
260    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/*impl<'a> Iterator for Handle<'a, FDBColumnHeaderSlice<'a>> {
293    type Item = Handle<'a, FDBColumnHeader>;
294
295    fn next(&mut self) -> Option<Self::Item> {
296        self.raw.next().map(|raw| Handle { mem: self.mem, raw })
297    }
298}*/
299
300#[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    /// Get the name of the column
326    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    /// Get the type of the column
332    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    /// Get the number of buckets
353    pub fn bucket_count(&self) -> u32 {
354        self.raw.buckets.count
355    }
356
357    /// Get the slice of buckets
358    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
376/*impl<'a> Iterator for Handle<'a, FDBBucketHeaderSlice<'a>> {
377    type Item = Handle<'a, FDBBucketHeader>;
378
379    fn next(&mut self) -> Option<Self::Item> {
380        self.raw.next().map(|raw| Handle { mem: self.mem, raw })
381    }
382
383    fn nth(&mut self, n: usize) -> Option<Self::Item> {
384        self.raw.nth(n).map(|raw| Handle { mem: self.mem, raw })
385    }
386}*/
387
388impl<'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    /// Get the first row header entry or `None`
398    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    /// Get an iterator over all buckets
408    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/// A newtype for a row header reference
415#[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    /// Get the next row header list entry instance
448    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    /// Get the associated row header.
458    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    /// Get the number of fields
466    pub fn field_count(&self) -> u32 {
467        self.raw.fields.count
468    }
469
470    /// Get the slice of fields
471    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
489/*impl<'a> Iterator for Handle<'a, FDBFieldDataSlice<'a>> {
490    type Item = Handle<'a, FDBFieldData>;
491
492    fn next(&mut self) -> Option<Self::Item> {
493        self.raw.next().map(|raw| Handle { mem: self.mem, raw })
494    }
495}*/
496
497impl<'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    /// Get the value from this handle
507    pub fn try_get_value(&self) -> Result<'a, FDBFieldValue> {
508        // FIXME: propagate error
509        Ok(self.map(|_, r| FDBFieldValue::try_from(r).unwrap()))
510    }
511}