pancake_db_core/encoding/
encoder.rs

1use std::marker::PhantomData;
2
3use pancake_db_idl::dml::FieldValue;
4use pancake_db_idl::dml::field_value::Value;
5
6use crate::errors::{CoreResult, CoreError};
7use crate::primitives::{Atom, Primitive};
8use super::{NULL_BYTE, ESCAPE_BYTE, COUNT_BYTE};
9
10pub trait Encoder: Send + Sync {
11  fn encode(&self, values: &[FieldValue]) -> CoreResult<Vec<u8>>;
12  fn encode_count(&self, count: u32) -> Vec<u8>;
13}
14
15#[derive(Clone, Debug)]
16pub struct EncoderImpl<P: Primitive> {
17  nested_list_depth: u8,
18  _phantom: PhantomData<P>,
19}
20
21fn escape_bytes(bytes: &[u8]) -> Vec<u8> {
22  let mut res = Vec::new();
23  for &b in bytes {
24    if b >= NULL_BYTE {
25      res.push(ESCAPE_BYTE);
26      // we must avoid using the count byte at all so that we can easily read the end
27      // of the file without decoding the whole thing, so instead of pushing the byte
28      // we escaped, we push its complement
29      res.push(!b);
30    } else {
31      res.push(b);
32    }
33  }
34  res
35}
36
37impl<P: Primitive> Encoder for EncoderImpl<P> {
38  fn encode(&self, fvs: &[FieldValue]) -> CoreResult<Vec<u8>> {
39    let mut res = Vec::new();
40
41    for fv in fvs {
42      let maybe_err: CoreResult<()> = match &fv.value {
43        Some(value) => {
44          let bytes = self.value_bytes(value, 0)?;
45          res.extend(bytes);
46          Ok(())
47        },
48        None => {
49          res.push(NULL_BYTE);
50          Ok(())
51        }
52      };
53      maybe_err?;
54    }
55    Ok(res)
56  }
57
58  fn encode_count(&self, count: u32) -> Vec<u8> {
59    let mut res = vec![COUNT_BYTE];
60    res.extend(&escape_bytes(&count.to_be_bytes()));
61    res
62  }
63}
64
65impl<P: Primitive> EncoderImpl<P> {
66  pub fn new(escape_depth: u8) -> Self {
67    Self {
68      nested_list_depth: escape_depth,
69      _phantom: PhantomData,
70    }
71  }
72
73  fn value_bytes(&self, v: &Value, traverse_depth: u8) -> CoreResult<Vec<u8>> {
74    if traverse_depth == self.nested_list_depth {
75      let atoms = P::try_from_value(v)?.to_atoms();
76      if P::IS_ATOMIC {
77        Ok(escape_bytes(&atoms[0].to_bytes()))
78      } else {
79        let mut res = Vec::with_capacity(2 + P::A::BYTE_SIZE * atoms.len());
80        res.extend((atoms.len() as u16).to_be_bytes());
81        for atom in &atoms {
82          res.extend(atom.to_bytes());
83        }
84        Ok(escape_bytes(&res))
85      }
86    } else {
87      match v {
88        Value::ListVal(l) => {
89          let mut res = Vec::new();
90          res.extend(escape_bytes(&(l.vals.len() as u16).to_be_bytes()));
91          for val in &l.vals {
92            let bytes = self.value_bytes(val.value.as_ref().unwrap(), traverse_depth + 1)?;
93            res.extend(bytes);
94          }
95          Ok(res)
96        },
97        _ => Err(CoreError::invalid("expected a list to traverse but found atomic type"))
98      }
99    }
100  }
101}