From 87e1b38f02b327ae094ad9da0a98cc8bde26340d Mon Sep 17 00:00:00 2001 From: Tobie Morgan Hitchcock Date: Thu, 13 Jan 2022 17:40:20 +0000 Subject: [PATCH] Add initial key-value storage key implementation --- src/key/bytes/decode.rs | 558 ++++++++++++++++++++++++++++++++ src/key/bytes/encode.rs | 696 ++++++++++++++++++++++++++++++++++++++++ src/key/bytes/mod.rs | 64 ++++ src/key/database.rs | 51 +++ src/key/db.rs | 51 +++ src/key/dt.rs | 56 ++++ src/key/du.rs | 56 ++++ src/key/ev.rs | 61 ++++ src/key/fd.rs | 61 ++++ src/key/ft.rs | 61 ++++ src/key/index.rs | 65 ++++ src/key/ix.rs | 61 ++++ src/key/key.rs | 100 ++++++ src/key/kv.rs | 40 +++ src/key/lv.rs | 61 ++++ src/key/mod.rs | 25 ++ src/key/namespace.rs | 46 +++ src/key/ns.rs | 46 +++ src/key/nt.rs | 51 +++ src/key/nu.rs | 51 +++ src/key/point.rs | 68 ++++ src/key/sc.rs | 56 ++++ src/key/st.rs | 61 ++++ src/key/table.rs | 56 ++++ src/key/tb.rs | 56 ++++ src/key/thing.rs | 62 ++++ 26 files changed, 2620 insertions(+) create mode 100644 src/key/bytes/decode.rs create mode 100644 src/key/bytes/encode.rs create mode 100644 src/key/bytes/mod.rs create mode 100644 src/key/database.rs create mode 100644 src/key/db.rs create mode 100644 src/key/dt.rs create mode 100644 src/key/du.rs create mode 100644 src/key/ev.rs create mode 100644 src/key/fd.rs create mode 100644 src/key/ft.rs create mode 100644 src/key/index.rs create mode 100644 src/key/ix.rs create mode 100644 src/key/key.rs create mode 100644 src/key/kv.rs create mode 100644 src/key/lv.rs create mode 100644 src/key/mod.rs create mode 100644 src/key/namespace.rs create mode 100644 src/key/ns.rs create mode 100644 src/key/nt.rs create mode 100644 src/key/nu.rs create mode 100644 src/key/point.rs create mode 100644 src/key/sc.rs create mode 100644 src/key/st.rs create mode 100644 src/key/table.rs create mode 100644 src/key/tb.rs create mode 100644 src/key/thing.rs diff --git a/src/key/bytes/decode.rs b/src/key/bytes/decode.rs new file mode 100644 index 00000000..5d0f1a6d --- /dev/null +++ b/src/key/bytes/decode.rs @@ -0,0 +1,558 @@ +use byteorder::{ReadBytesExt, BE}; +use serde; +use serde::de::{Deserialize, Visitor}; +use std; +use std::fmt; +use std::io::{self, Read}; +use std::mem::transmute; +use std::str; +use std::{i16, i32, i64, i8}; +use thiserror::Error; + +/// A decoder for deserializing bytes from an order preserving format to a value. +/// +/// Please see the **Serializer** documentation for a precise overview of the `bytekey` format. +#[derive(Debug)] +pub struct Deserializer { + reader: R, +} + +/// Errors that may be occur when deserializing. +#[derive(Error, Debug)] +pub enum Error { + #[error("Couldn't setup connection to underlying datastore")] + DeserializeAnyUnsupported, + #[error("Couldn't setup connection to underlying datastore")] + UnexpectedEof, + #[error("Couldn't setup connection to underlying datastore")] + InvalidUtf8, + #[error("Couldn't setup connection to underlying datastore")] + Io(#[from] io::Error), + #[error("Couldn't setup connection to underlying datastore")] + Message(String), +} + +impl serde::de::Error for Error { + fn custom(msg: T) -> Self { + Error::Message(msg.to_string()) + } +} + +/// Shorthand for `Result`. +pub type Result = std::result::Result; + +/// Deserialize data from the given slice of bytes. +/// +/// #### Usage +/// +/// ``` +/// # use bytekey::{serialize, deserialize}; +/// let bytes = serialize(&42usize).unwrap(); +/// assert_eq!(42usize, deserialize::(&bytes).unwrap()); +/// ``` +pub fn deserialize(bytes: &[u8]) -> Result +where + T: for<'de> Deserialize<'de>, +{ + deserialize_from(bytes) +} + +/// Deserialize data from the given byte reader. +/// +/// #### Usage +/// +/// ``` +/// # use bytekey::{serialize, deserialize_from}; +/// let bytes = serialize(&42u64).unwrap(); +/// let result: u64 = deserialize_from(&bytes[..]).unwrap(); +/// assert_eq!(42u64, result); +/// ``` +pub fn deserialize_from(reader: R) -> Result +where + R: io::BufRead, + T: for<'de> Deserialize<'de>, +{ + let mut deserializer = Deserializer::new(reader); + T::deserialize(&mut deserializer) +} + +impl Deserializer { + /// Creates a new ordered bytes encoder whose output will be written to the provided writer. + pub fn new(reader: R) -> Deserializer { + Deserializer { + reader, + } + } + + /// Deserialize a `u64` that has been serialized using the `serialize_var_u64` method. + pub fn deserialize_var_u64(&mut self) -> Result { + let header = self.reader.read_u8()?; + let n = header >> 4; + let (mut val, _) = ((header & 0x0F) as u64).overflowing_shl(n as u32 * 8); + for i in 1..n + 1 { + let byte = self.reader.read_u8()?; + val += (byte as u64) << ((n - i) * 8); + } + Ok(val) + } + + /// Deserialize an `i64` that has been serialized using the `serialize_var_i64` method. + pub fn deserialize_var_i64(&mut self) -> Result { + let header = self.reader.read_u8()?; + let mask = ((header ^ 0x80) as i8 >> 7) as u8; + let n = ((header >> 3) ^ mask) & 0x0F; + let (mut val, _) = (((header ^ mask) & 0x07) as u64).overflowing_shl(n as u32 * 8); + for i in 1..n + 1 { + let byte = self.reader.read_u8()?; + val += ((byte ^ mask) as u64) << ((n - i) * 8); + } + let final_mask = (((mask as i64) << 63) >> 63) as u64; + val ^= final_mask; + Ok(val as i64) + } +} + +impl<'de, 'a, R> serde::de::Deserializer<'de> for &'a mut Deserializer +where + R: io::BufRead, +{ + type Error = Error; + + fn deserialize_any(self, _visitor: V) -> Result + where + V: Visitor<'de>, + { + Err(Error::DeserializeAnyUnsupported) + } + + fn deserialize_bool(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let b = match self.reader.read_u8()? { + 0 => false, + _ => true, + }; + visitor.visit_bool(b) + } + + fn deserialize_i8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let i = self.reader.read_i8()?; + visitor.visit_i8(i ^ i8::MIN) + } + + fn deserialize_i16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let i = self.reader.read_i16::()?; + visitor.visit_i16(i ^ i16::MIN) + } + + fn deserialize_i32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let i = self.reader.read_i32::()?; + visitor.visit_i32(i ^ i32::MIN) + } + + fn deserialize_i64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let i = self.reader.read_i64::()?; + visitor.visit_i64(i ^ i64::MIN) + } + + fn deserialize_u8(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let u = self.reader.read_u8()?; + visitor.visit_u8(u) + } + + fn deserialize_u16(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let u = self.reader.read_u16::()?; + visitor.visit_u16(u) + } + + fn deserialize_u32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let u = self.reader.read_u32::()?; + visitor.visit_u32(u) + } + + fn deserialize_u64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let u = self.reader.read_u64::()?; + visitor.visit_u64(u) + } + + fn deserialize_f32(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let val = self.reader.read_i32::()?; + let t = ((val ^ i32::MIN) >> 31) | i32::MIN; + let f: f32 = unsafe { transmute(val ^ t) }; + visitor.visit_f32(f) + } + + fn deserialize_f64(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let val = self.reader.read_i64::()?; + let t = ((val ^ i64::MIN) >> 63) | i64::MIN; + let f: f64 = unsafe { transmute(val ^ t) }; + visitor.visit_f64(f) + } + + fn deserialize_char(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut string = String::new(); + let mut buffer: Vec = vec![]; + match self.reader.read_until(0u8, &mut buffer) { + Ok(_) => match str::from_utf8(&buffer) { + Ok(mut s) => { + const EOF: char = '\u{0}'; + const EOF_STR: &'static str = "\u{0}"; + if s.len() >= EOF.len_utf8() { + let eof_start = s.len() - EOF.len_utf8(); + if &s[eof_start..] == EOF_STR { + s = &s[..eof_start]; + } + } + string.push_str(s) + } + Err(e) => panic!("1"), + }, + Err(e) => panic!("2"), + } + visitor.visit_string(string) + } + + fn deserialize_str(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut string = String::new(); + let mut buffer: Vec = vec![]; + match self.reader.read_until(0u8, &mut buffer) { + Ok(_) => match str::from_utf8(&buffer) { + Ok(mut s) => { + const EOF: char = '\u{0}'; + const EOF_STR: &'static str = "\u{0}"; + if s.len() >= EOF.len_utf8() { + let eof_start = s.len() - EOF.len_utf8(); + if &s[eof_start..] == EOF_STR { + s = &s[..eof_start]; + } + } + string.push_str(s) + } + Err(e) => panic!("1"), + }, + Err(e) => panic!("2"), + } + visitor.visit_string(string) + } + + fn deserialize_string(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_str(visitor) + } + + fn deserialize_bytes(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + let mut bytes = vec![]; + for byte in (&mut self.reader).bytes() { + bytes.push(byte?); + } + visitor.visit_byte_buf(bytes) + } + + fn deserialize_byte_buf(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.deserialize_bytes(visitor) + } + + fn deserialize_option(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.reader.read_u8()? { + 0 => visitor.visit_none(), + 1 => visitor.visit_some(&mut *self), + b => { + let msg = format!("expected `0` or `1` for option tag - found {}", b); + Err(Error::Message(msg)) + } + } + } + + fn deserialize_unit(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_unit_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_unit() + } + + fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_seq(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + struct Access<'a, R> + where + R: 'a + io::BufRead, + { + deserializer: &'a mut Deserializer, + } + + impl<'de, 'a, R> serde::de::SeqAccess<'de> for Access<'a, R> + where + R: io::BufRead, + { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: serde::de::DeserializeSeed<'de>, + { + match serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer) { + Ok(v) => Ok(Some(v)), + Err(Error::Io(ref err)) if err.kind() == io::ErrorKind::UnexpectedEof => { + Ok(None) + } + Err(err) => Err(err), + } + } + } + + visitor.visit_seq(Access { + deserializer: self, + }) + } + + fn deserialize_tuple(self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + struct Access<'a, R> + where + R: 'a + io::BufRead, + { + deserializer: &'a mut Deserializer, + len: usize, + } + + impl<'de, 'a, R> serde::de::SeqAccess<'de> for Access<'a, R> + where + R: io::BufRead, + { + type Error = Error; + + fn next_element_seed(&mut self, seed: T) -> Result> + where + T: serde::de::DeserializeSeed<'de>, + { + if self.len == 0 { + return Ok(None); + } + self.len -= 1; + let value = serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer)?; + Ok(Some(value)) + } + + fn size_hint(&self) -> Option { + Some(self.len) + } + } + + visitor.visit_seq(Access { + deserializer: self, + len, + }) + } + + fn deserialize_tuple_struct( + self, + _name: &'static str, + len: usize, + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_tuple(len, visitor) + } + + fn deserialize_map(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + struct Access<'a, R> + where + R: 'a + io::BufRead, + { + deserializer: &'a mut Deserializer, + } + + impl<'de, 'a, R> serde::de::MapAccess<'de> for Access<'a, R> + where + R: io::BufRead, + { + type Error = Error; + + fn next_key_seed(&mut self, seed: T) -> Result> + where + T: serde::de::DeserializeSeed<'de>, + { + match serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer) { + Ok(v) => Ok(Some(v)), + Err(Error::Io(ref err)) if err.kind() == io::ErrorKind::UnexpectedEof => { + Ok(None) + } + Err(err) => Err(err), + } + } + + fn next_value_seed(&mut self, seed: T) -> Result + where + T: serde::de::DeserializeSeed<'de>, + { + serde::de::DeserializeSeed::deserialize(seed, &mut *self.deserializer) + } + } + + visitor.visit_map(Access { + deserializer: self, + }) + } + + fn deserialize_struct( + self, + _name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.deserialize_tuple(fields.len(), visitor) + } + + fn deserialize_enum( + self, + _name: &'static str, + _fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + impl<'de, 'a, R> serde::de::EnumAccess<'de> for &'a mut Deserializer + where + R: io::BufRead, + { + type Error = Error; + type Variant = Self; + + fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant)> + where + V: serde::de::DeserializeSeed<'de>, + { + let idx: u32 = serde::de::Deserialize::deserialize(&mut *self)?; + let val: Result<_> = + seed.deserialize(serde::de::IntoDeserializer::into_deserializer(idx)); + Ok((val?, self)) + } + } + + impl<'de, 'a, R> serde::de::VariantAccess<'de> for &'a mut Deserializer + where + R: io::BufRead, + { + type Error = Error; + + fn unit_variant(self) -> Result<()> { + Ok(()) + } + + fn newtype_variant_seed(self, seed: T) -> Result + where + T: serde::de::DeserializeSeed<'de>, + { + serde::de::DeserializeSeed::deserialize(seed, self) + } + + fn tuple_variant(self, len: usize, visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_tuple(self, len, visitor) + } + + fn struct_variant( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_tuple(self, fields.len(), visitor) + } + } + + visitor.visit_enum(self) + } + + fn deserialize_ignored_any(self, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + Err(Error::DeserializeAnyUnsupported) + } + + fn deserialize_identifier(self, _visitor: V) -> Result + where + V: serde::de::Visitor<'de>, + { + Err(Error::DeserializeAnyUnsupported) + } +} diff --git a/src/key/bytes/encode.rs b/src/key/bytes/encode.rs new file mode 100644 index 00000000..a3caa59e --- /dev/null +++ b/src/key/bytes/encode.rs @@ -0,0 +1,696 @@ +use byteorder::{WriteBytesExt, BE}; +use serde::{self, Serialize}; +use std::fmt; +use std::io::{self, Write}; +use std::mem::transmute; +use std::{self, i16, i32, i64, i8}; +use thiserror::Error; + +/// A serializer for a byte format that preserves lexicographic sort order. +/// +/// The byte format is designed with a few goals: +/// +/// * Order must be preserved +/// * Serialized representations should be as compact as possible +/// * Type information is *not* serialized with values +/// +/// #### Supported Data Types +/// +/// ##### Unsigned Integers +/// +/// `u8`, `u16`, `u32`, and `u64` are serialized into 1, 2, 4, and 8 bytes of output, respectively. +/// Order is preserved by encoding the bytes in big-endian (most-significant bytes first) format. +/// `usize` is always serialized as if it were `u64`. +/// +/// The `Serializer` also supports variable-length serialization of unsigned integers via the +/// `serialize_var_u64` method. Smaller magnitude values (closer to 0) will encode into fewer +/// bytes. +/// +/// ##### Signed Integers +/// +/// `i8`, `i16`, `i32`, and `i64` are encoded into 1, 2, 4, and 8 bytes of output, respectively. +/// Order is preserved by taking the bitwise complement of the value, and encoding the resulting +/// bytes in big-endian format. `isize` is always serialized as if it were `i64`. +/// +/// The `Serializer` also supports variable-length serialization of signed integers via the +/// `serialize_var_i64` method. Smaller magnitude values (closer to 0) will encode into fewer +/// bytes. +/// +/// ##### Floating Point Numbers +/// +/// `f32` and `f64` are serialized into 4 and 8 bytes of output, respectively. Order is preserved +/// by encoding the value, or the bitwise complement of the value if negative, into bytes in +/// big-endian format. `NAN` values will sort after all other values. In general, it is unwise to +/// use IEEE 754 floating point values in keys, because rounding errors are pervasive. It is +/// typically hard or impossible to use an approximate 'epsilon' approach when using keys for +/// lookup. +/// +/// ##### Characters +/// +/// Characters are serialized into between 1 and 4 bytes of output. The resulting length is +/// equivalent to the result of `char::len_utf8`. +/// +/// ##### Booleans +/// +/// Booleans are serialized into a single byte of output. `false` values will sort before `true` +/// values. +/// +/// ##### Options +/// +/// An optional wrapper type adds a 1 byte overhead to the wrapped data type. `None` values will +/// sort before `Some` values. +/// +/// ##### Structs, Tuples and Fixed-Size Arrays +/// +/// Structs and tuples are serialized by serializing their consituent fields in order with no +/// prefix, suffix, or padding bytes. +/// +/// ##### Enums +/// +/// Enums are encoded with a `u32` variant index tag, plus the consituent fields in the case of an +/// enum-struct. +/// +/// ##### Sequences, Strings and Maps +/// +/// Sequences are ordered from the most significant to the least. Strings are serialized into their +/// natural UTF8 representation. +/// +/// The ordering of sequential elements follows the `Ord` implementation of `slice`, that is, from +/// left to write when viewing a `Vec` printed via the `{:?}` formatter. +/// +/// The caveat with these types is that their length must be known before deserialization. This is +/// because the length is *not* serialized prior to the elements in order to preserve ordering and +/// there is no trivial way to tokenise between sequential elements that 1. does not corrupt +/// ordering and 2. may not confuse tokenisation with following elements of a different type during +/// tuple or struct deserialization. Thus, when deserializing sequences, strings and maps, the +/// process will only be considered complete once the inner `reader` produces an EOF character. +#[derive(Debug)] +pub struct Serializer +where + W: Write, +{ + writer: W, +} + +/// Errors that might occur while serializing. +#[derive(Error, Debug)] +pub enum Error { + #[error("Couldn't setup connection to underlying datastore")] + Message(String), + #[error("Couldn't setup connection to underlying datastore")] + Io(#[from] io::Error), +} + +impl serde::ser::Error for Error { + fn custom(msg: T) -> Self { + Error::Message(msg.to_string()) + } +} + +/// Shorthand for `Result`. +pub type Result = std::result::Result; + +/// Serialize data into a vector of `u8` bytes. +/// +/// #### Usage +/// +/// ``` +/// # use bytekey::serialize; +/// assert_eq!(vec!(0x00, 0x00, 0x00, 0x2A), serialize(&42u32).unwrap()); +/// assert_eq!(vec!(0x66, 0x69, 0x7A, 0x7A, 0x62, 0x75, 0x7A, 0x7A, 0x00), serialize(&"fizzbuzz").unwrap()); +/// assert_eq!(vec!(0x2A, 0x66, 0x69, 0x7A, 0x7A, 0x00), serialize(&(42u8, "fizz")).unwrap()); +/// ``` +pub fn serialize(v: &T) -> Result> +where + T: Serialize, +{ + let mut bytes = vec![]; + { + let mut buffered = io::BufWriter::new(&mut bytes); + serialize_into(&mut buffered, v)?; + } + Ok(bytes) +} + +/// Serialize data into the given vector of `u8` bytes. +/// +/// #### Usage +/// +/// ``` +/// # use bytekey::serialize_into; +/// let mut bytes = vec![]; +/// bytekey::serialize_into(&mut bytes, &5u8).unwrap(); +/// assert_eq!(vec![5u8], bytes.clone()); +/// bytekey::serialize_into(&mut bytes, &10u8).unwrap(); +/// assert_eq!(vec![5u8, 10], bytes.clone()); +/// ``` +pub fn serialize_into(writer: W, value: &T) -> Result<()> +where + W: Write, + T: Serialize, +{ + let mut serializer = Serializer::new(writer); + value.serialize(&mut serializer) +} + +impl Serializer +where + W: Write, +{ + /// Creates a new ordered bytes encoder whose output will be written to the provided writer. + pub fn new(writer: W) -> Serializer { + Serializer { + writer, + } + } + + /// Encode a `u64` into a variable number of bytes. + /// + /// The variable-length encoding scheme uses between 1 and 9 bytes depending on the value. + /// Smaller magnitude (closer to 0) `u64`s will encode to fewer bytes. + /// + /// ##### Encoding + /// + /// The encoding uses the first 4 bits to store the number of trailing bytes, between 0 and 8. + /// Subsequent bits are the input value in big-endian format with leading 0 bytes removed. + /// + /// ##### Encoded Size + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
rangesize (bytes)
[0, 24)1
[24, 212)2
[212, 220)3
[220, 228)4
[228, 236)5
[236, 244)6
[244, 252)7
[252, 260)8
[260, 264)9
+ pub fn serialize_var_u64(&mut self, val: u64) -> Result<()> { + if val < 1 << 4 { + self.writer.write_u8(val as u8) + } else if val < 1 << 12 { + self.writer.write_u16::((val as u16) | 1 << 12) + } else if val < 1 << 20 { + self.writer.write_u8(((val >> 16) as u8) | 2 << 4)?; + self.writer.write_u16::(val as u16) + } else if val < 1 << 28 { + self.writer.write_u32::((val as u32) | 3 << 28) + } else if val < 1 << 36 { + self.writer.write_u8(((val >> 32) as u8) | 4 << 4)?; + self.writer.write_u32::(val as u32) + } else if val < 1 << 44 { + self.writer.write_u16::(((val >> 32) as u16) | 5 << 12)?; + self.writer.write_u32::(val as u32) + } else if val < 1 << 52 { + self.writer.write_u8(((val >> 48) as u8) | 6 << 4)?; + self.writer.write_u16::((val >> 32) as u16)?; + self.writer.write_u32::(val as u32) + } else if val < 1 << 60 { + self.writer.write_u64::((val as u64) | 7 << 60) + } else { + self.writer.write_u8(8 << 4)?; + self.writer.write_u64::(val) + } + .map_err(From::from) + } + + /// Encode an `i64` into a variable number of bytes. + /// + /// The variable-length encoding scheme uses between 1 and 9 bytes depending on the value. + /// Smaller magnitude (closer to 0) `i64`s will encode to fewer bytes. + /// + /// ##### Encoding + /// + /// The encoding uses the first bit to encode the sign: `0` for negative values and `1` for + /// positive values. The following 4 bits store the number of trailing bytes, between 0 and 8. + /// Subsequent bits are the absolute value of the input value in big-endian format with leading + /// 0 bytes removed. If the original value was negative, than 1 is subtracted from the absolute + /// value before encoding. Finally, if the value is negative, all bits except the sign bit are + /// flipped (1s become 0s and 0s become 1s). + /// + /// ##### Encoded Size + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
negative rangepositive rangesize (bytes)
[-23, 0)[0, 23)1
[-211, -23)[23, 211)2
[-219, -211)[211, 219)3
[-227, -219)[219, 227)4
[-235, -227)[227, 235)5
[-243, -235)[235, 243)6
[-251, -243)[243, 251)7
[-259, -251)[251, 259)8
[-263, -259)[259, 263)9
+ pub fn serialize_var_i64(&mut self, v: i64) -> Result<()> { + // The mask is 0 for positive input and u64::MAX for negative input + let mask = (v >> 63) as u64; + let val = v.abs() as u64 - (1 & mask); + if val < 1 << 3 { + let masked = (val | (0x10 << 3)) ^ mask; + self.writer.write_u8(masked as u8) + } else if val < 1 << 11 { + let masked = (val | (0x11 << 11)) ^ mask; + self.writer.write_u16::(masked as u16) + } else if val < 1 << 19 { + let masked = (val | (0x12 << 19)) ^ mask; + self.writer.write_u8((masked >> 16) as u8)?; + self.writer.write_u16::(masked as u16) + } else if val < 1 << 27 { + let masked = (val | (0x13 << 27)) ^ mask; + self.writer.write_u32::(masked as u32) + } else if val < 1 << 35 { + let masked = (val | (0x14 << 35)) ^ mask; + self.writer.write_u8((masked >> 32) as u8)?; + self.writer.write_u32::(masked as u32) + } else if val < 1 << 43 { + let masked = (val | (0x15 << 43)) ^ mask; + self.writer.write_u16::((masked >> 32) as u16)?; + self.writer.write_u32::(masked as u32) + } else if val < 1 << 51 { + let masked = (val | (0x16 << 51)) ^ mask; + self.writer.write_u8((masked >> 48) as u8)?; + self.writer.write_u16::((masked >> 32) as u16)?; + self.writer.write_u32::(masked as u32) + } else if val < 1 << 59 { + let masked = (val | (0x17 << 59)) ^ mask; + self.writer.write_u64::(masked as u64) + } else { + self.writer.write_u8((0x18 << 3) ^ mask as u8)?; + self.writer.write_u64::(val ^ mask) + } + .map_err(From::from) + } +} + +impl<'a, W> serde::Serializer for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + type SerializeSeq = Self; + type SerializeTuple = Self; + type SerializeTupleStruct = Self; + type SerializeTupleVariant = Self; + type SerializeMap = Self; + type SerializeStruct = Self; + type SerializeStructVariant = Self; + + fn is_human_readable(&self) -> bool { + false + } + + fn serialize_bool(self, v: bool) -> Result<()> { + let b = if v { + 1 + } else { + 0 + }; + self.writer.write_u8(b)?; + Ok(()) + } + + fn serialize_i8(self, v: i8) -> Result<()> { + self.writer.write_i8(v ^ i8::MIN)?; + Ok(()) + } + + fn serialize_i16(self, v: i16) -> Result<()> { + self.writer.write_i16::(v ^ i16::MIN)?; + Ok(()) + } + + fn serialize_i32(self, v: i32) -> Result<()> { + self.writer.write_i32::(v ^ i32::MIN)?; + Ok(()) + } + + fn serialize_i64(self, v: i64) -> Result<()> { + self.writer.write_i64::(v ^ i64::MIN)?; + Ok(()) + } + + fn serialize_u8(self, v: u8) -> Result<()> { + self.writer.write_u8(v)?; + Ok(()) + } + + fn serialize_u16(self, v: u16) -> Result<()> { + self.writer.write_u16::(v)?; + Ok(()) + } + + fn serialize_u32(self, v: u32) -> Result<()> { + self.writer.write_u32::(v)?; + Ok(()) + } + + fn serialize_u64(self, v: u64) -> Result<()> { + self.writer.write_u64::(v)?; + Ok(()) + } + + fn serialize_f32(self, v: f32) -> Result<()> { + let val = unsafe { transmute::(v) }; + let t = (val >> 31) | i32::MIN; + self.writer.write_i32::(val ^ t)?; + Ok(()) + } + + fn serialize_f64(self, v: f64) -> Result<()> { + let val = unsafe { transmute::(v) }; + let t = (val >> 63) | i64::MIN; + self.writer.write_i64::(val ^ t)?; + Ok(()) + } + + fn serialize_char(self, v: char) -> Result<()> { + self.serialize_str(&v.to_string())?; + Ok(()) + } + + fn serialize_str(self, v: &str) -> Result<()> { + self.writer.write_all(v.as_bytes())?; + self.writer.write_u8(0)?; + Ok(()) + } + + fn serialize_bytes(self, v: &[u8]) -> Result<()> { + self.writer.write_all(v)?; + Ok(()) + } + + fn serialize_none(self) -> Result<()> { + self.writer.write_u8(0)?; + Ok(()) + } + + fn serialize_some(self, v: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + self.writer.write_u8(1)?; + v.serialize(self) + } + + fn serialize_unit(self) -> Result<()> { + self.writer.write_all(&[])?; + Ok(()) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + ) -> Result<()> { + self.serialize_u32(variant_index) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + value: &T, + ) -> Result<()> + where + T: ?Sized + Serialize, + { + self.writer.write_u32::(variant_index)?; + value.serialize(self) + } + + fn serialize_seq(self, _len: Option) -> Result { + Ok(self) + } + + fn serialize_tuple(self, _len: usize) -> Result { + Ok(self) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result { + Ok(self) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + self.writer.write_u32::(variant_index)?; + Ok(self) + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(self) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + Ok(self) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result { + self.writer.write_u32::(variant_index)?; + Ok(self) + } +} + +// Compound Implementations. + +impl<'a, W> serde::ser::SerializeSeq for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeTuple for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeTupleStruct for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeTupleVariant for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeMap for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_key(&mut self, key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + key.serialize(&mut **self) + } + + fn serialize_value(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeStruct for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} + +impl<'a, W> serde::ser::SerializeStructVariant for &'a mut Serializer +where + W: Write, +{ + type Ok = (); + type Error = Error; + + fn serialize_field(&mut self, _key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + value.serialize(&mut **self) + } + + fn end(self) -> Result<()> { + Ok(()) + } +} diff --git a/src/key/bytes/mod.rs b/src/key/bytes/mod.rs new file mode 100644 index 00000000..988d533c --- /dev/null +++ b/src/key/bytes/mod.rs @@ -0,0 +1,64 @@ +//! Binary encoding for Rust values which preserves lexicographic sort order. Order-preserving +//! encoding is useful for creating keys for sorted key-value stores with byte string typed keys, +//! such as [leveldb](https://github.com/google/leveldb) and +//! [sled](https://github.com/spacejam/sled). +//! +//! `bytekey` is *not* a self-describing format. In other words, Type information is *not* +//! serialized alongside values, and thus the type of serialized data must be known in order to +//! perform deserialization. +//! +//! #### Supported Data Types +//! +//! `bytekey` currently supports all Rust primitives, strings, options, structs, enums, vecs, and +//! tuples. See **Serializer** for details on the serialization format. +//! +//! #### Usage +//! +//! ``` +//! #[macro_use] +//! extern crate serde_derive; +//! extern crate bytekey; +//! use bytekey::{deserialize, serialize}; +//! +//! #[derive(Debug, PartialEq, Serialize, Deserialize)] +//! struct MyKey { a: u32, b: String } +//! +//! # fn main() { +//! let a = MyKey { a: 1, b: "foo".to_string() }; +//! let b = MyKey { a: 2, b: "foo".to_string() }; +//! let c = MyKey { a: 2, b: "fooz".to_string() }; +//! +//! assert!(serialize(&a).unwrap() < serialize(&b).unwrap()); +//! assert!(serialize(&b).unwrap() < serialize(&c).unwrap()); +//! assert_eq!(a, deserialize(&serialize(&a).unwrap()).unwrap()); +//! # } +//! ``` +//! +//! #### Type Evolution +//! +//! In general, the exact type of a serialized value must be known in order to correctly +//! deserialize it. For structs and enums, the type is effectively frozen once any values of the +//! type have been serialized: changes to the struct or enum will cause deserialization of already +//! serialized values to fail or return incorrect values. The only exception is adding new variants +//! to the end of an existing enum. Enum variants may *not* change type, be removed, or be +//! reordered. All changes to structs, including adding, removing, reordering, or changing the type +//! of a field are forbidden. +//! +//! These restrictions lead to a few best-practices when using `bytekey` serialization: +//! +//! * Don't use `bytekey` unless you need lexicographic ordering of serialized values! A more +//! general encoding library such as [Cap'n Proto](https://github.com/dwrensha/capnproto-rust) or +//! [bincode](https://github.com/TyOverby/binary-encode) will serve you better if this feature is +//! not necessary. +//! * If you persist serialized values for longer than the life of a process (i.e. you write the +//! serialized values to a file or a database), consider using an enum as a top-level wrapper +//! type. This will allow you to seamlessly add a new variant when you need to change the key +//! format in a backwards-compatible manner (the different key types will sort seperately). If +//! your enum has less than 16 variants, then the overhead is just a single byte in serialized +//! output. + +pub mod decode; +pub mod encode; + +pub use self::decode::{deserialize, deserialize_from, Deserializer}; +pub use self::encode::{serialize, serialize_into, Serializer}; diff --git a/src/key/database.rs b/src/key/database.rs new file mode 100644 index 00000000..402e30c1 --- /dev/null +++ b/src/key/database.rs @@ -0,0 +1,51 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Database { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, +} + +pub fn new(ns: &str, db: &str) -> Database { + Database::new(ns.to_string(), db.to_string()) +} + +impl Database { + pub fn new(ns: String, db: String) -> Database { + Database { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Database::new( + "test".to_string(), + "test".to_string(), + ); + let enc = Database::encode(&val).unwrap(); + let dec = Database::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/db.rs b/src/key/db.rs new file mode 100644 index 00000000..605a8af3 --- /dev/null +++ b/src/key/db.rs @@ -0,0 +1,51 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Db { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, +} + +pub fn new(ns: &str, db: &str) -> Db { + Db::new(ns.to_string(), db.to_string()) +} + +impl Db { + pub fn new(ns: String, db: String) -> Db { + Db { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("!db"), + db, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Db::new( + "test".to_string(), + "test".to_string(), + ); + let enc = Db::encode(&val).unwrap(); + let dec = Db::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/dt.rs b/src/key/dt.rs new file mode 100644 index 00000000..d63f18ce --- /dev/null +++ b/src/key/dt.rs @@ -0,0 +1,56 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Dt { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tk: String, +} + +pub fn new(ns: &str, db: &str, tb: &str) -> Dt { + Dt::new(ns.to_string(), db.to_string(), tb.to_string()) +} + +impl Dt { + pub fn new(ns: String, db: String, tk: String) -> Dt { + Dt { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("!tk"), + tk, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Dt::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Dt::encode(&val).unwrap(); + let dec = Dt::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/du.rs b/src/key/du.rs new file mode 100644 index 00000000..ae2c8928 --- /dev/null +++ b/src/key/du.rs @@ -0,0 +1,56 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Du { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + us: String, +} + +pub fn new(ns: &str, db: &str, us: &str) -> Du { + Du::new(ns.to_string(), db.to_string(), us.to_string()) +} + +impl Du { + pub fn new(ns: String, db: String, us: String) -> Du { + Du { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("!us"), + us, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Du::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Du::encode(&val).unwrap(); + let dec = Du::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/ev.rs b/src/key/ev.rs new file mode 100644 index 00000000..f4e98dcc --- /dev/null +++ b/src/key/ev.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Ev { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + ev: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, ev: &str) -> Ev { + Ev::new(ns.to_string(), db.to_string(), tb.to_string(), ev.to_string()) +} + +impl Ev { + pub fn new(ns: String, db: String, tb: String, ev: String) -> Ev { + Ev { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("!ev"), + ev, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Ev::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Ev::encode(&val).unwrap(); + let dec = Ev::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/fd.rs b/src/key/fd.rs new file mode 100644 index 00000000..04d50792 --- /dev/null +++ b/src/key/fd.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Fd { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + fd: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, fd: &str) -> Fd { + Fd::new(ns.to_string(), db.to_string(), tb.to_string(), fd.to_string()) +} + +impl Fd { + pub fn new(ns: String, db: String, tb: String, fd: String) -> Fd { + Fd { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("!fd"), + fd, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Fd::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Fd::encode(&val).unwrap(); + let dec = Fd::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/ft.rs b/src/key/ft.rs new file mode 100644 index 00000000..8c079054 --- /dev/null +++ b/src/key/ft.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Ft { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _d: String, + tb: String, + _c: String, + ft: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, ft: &str) -> Ft { + Ft::new(ns.to_string(), db.to_string(), tb.to_string(), ft.to_string()) +} + +impl Ft { + pub fn new(ns: String, db: String, tb: String, ft: String) -> Ft { + Ft { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("!ft"), + ft, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Ft::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Ft::encode(&val).unwrap(); + let dec = Ft::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/index.rs b/src/key/index.rs new file mode 100644 index 00000000..cf0271b0 --- /dev/null +++ b/src/key/index.rs @@ -0,0 +1,65 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use crate::sql::value::Value; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Index { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + ix: String, + fd: Value, +} + +pub fn new(ns: &str, db: &str, tb: &str, ix: &str, fd: Value) -> Index { + Index::new(ns.to_string(), db.to_string(), tb.to_string(), ix.to_string(), fd) +} + +impl Index { + pub fn new(ns: String, db: String, tb: String, ix: String, fd: Value) -> Index { + Index { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("¤"), + ix, + fd, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Index::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".into(), + ); + let enc = Index::encode(&val).unwrap(); + let dec = Index::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/ix.rs b/src/key/ix.rs new file mode 100644 index 00000000..d9e7940e --- /dev/null +++ b/src/key/ix.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Ix { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + ix: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, ix: &str) -> Ix { + Ix::new(ns.to_string(), db.to_string(), tb.to_string(), ix.to_string()) +} + +impl Ix { + pub fn new(ns: String, db: String, tb: String, ix: String) -> Ix { + Ix { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("!ix"), + ix, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Ix::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Ix::encode(&val).unwrap(); + let dec = Ix::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/key.rs b/src/key/key.rs new file mode 100644 index 00000000..90cc83f3 --- /dev/null +++ b/src/key/key.rs @@ -0,0 +1,100 @@ +use super::*; +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use serde::{Deserialize, Serialize}; + +// Default base key +pub const BASE: &'static str = "surreal"; +// Ignore specifies an ignored field +pub const IGNORE: &'static str = "\x00"; +// Prefix is the lowest char found in a key +pub const PREFIX: &'static str = "\x01"; +// Suffix is the highest char found in a key +pub const SUFFIX: &'static str = "\x7f"; + +/// KV {$kv} +/// NS {$kv}!ns{$ns} +/// +/// Namespace {$kv}*{$ns} +/// NT {$kv}*{$ns}!tk{$tk} +/// NU {$kv}*{$ns}!us{$us} +/// DB {$kv}*{$ns}!db{$db} +/// +/// Database {$kv}*{$ns}*{$db} +/// DT {$kv}*{$ns}*{$db}!tk{$tk} +/// DU {$kv}*{$ns}*{$db}!us{$us} +/// SC {$kv}*{$ns}*{$db}!sc{$sc} +/// ST {$kv}*{$ns}*{$db}!st{$sc}!tk{$tk} +/// +/// TB {$kv}*{$ns}*{$db}!tb{$tb} +/// +/// Table {$kv}*{$ns}*{$db}*{$tb} +/// FT {$kv}*{$ns}*{$db}*{$tb}!ft{$ft} +/// FD {$kv}*{$ns}*{$db}*{$tb}!fd{$fd} +/// EV {$kv}*{$ns}*{$db}*{$tb}!ev{$ev} +/// IX {$kv}*{$ns}*{$db}*{$tb}!ix{$ix} +/// LV {$kv}*{$ns}*{$db}*{$tb}!lv{$lv} +/// +/// Thing {$kv}*{$ns}*{$db}*{$tb}*{$id} +/// +/// Patch {$kv}*{$ns}*{$db}*{$tb}~{$id}{$at} +/// +/// Index {$kv}*{$ns}*{$db}*{$tb}¤{$ix}{$fd} +/// Point {$kv}*{$ns}*{$db}*{$tb}¤{$ix}{$fd}{$id} + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub enum Key { + Ns(ns::Ns), // Namespace definition key + Nt(nt::Nt), // Namespace token definition key + Nu(nu::Nu), // Namespace user definition key + Db(db::Db), // Database definition key + Dt(dt::Dt), // Database token definition key + Du(du::Du), // Database user definition key + Sc(sc::Sc), // Scope definition key + St(st::St), // Scope token definition key + Tb(tb::Tb), // Table definition key + Ft(ft::Ft), // Foreign table definition key + Ev(ev::Ev), // Event definition key + Fd(fd::Fd), // Field definition key + Ix(ix::Ix), // Index definition key + Lv(lv::Lv), // Live definition key + Namespace, // Namespace resource data key + Database, // Database resource data key + Table, // Table resource data key + Thing, // Thing resource data key + Index, // Index resource data key + Point, // Index resource data key + Patch, // Patch resource data key + Edge, // Edge resource data key +} + +impl Key { + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Key::Tb(tb::new("test", "test", "test")); + let enc = Key::encode(&val).unwrap(); + let dec = Key::decode(&enc).unwrap(); + assert_eq!(val, dec); + } + #[test] + fn sort() { + use super::*; + let less = Key::Tb(tb::new("test", "test", "")); + let item = Key::Tb(tb::new("test", "test", "item")); + let more = Key::Tb(tb::new("test", "test", "test")); + assert!(less.encode().unwrap() < item.encode().unwrap()); + assert!(item.encode().unwrap() < more.encode().unwrap()); + } +} diff --git a/src/key/kv.rs b/src/key/kv.rs new file mode 100644 index 00000000..fbb50ae1 --- /dev/null +++ b/src/key/kv.rs @@ -0,0 +1,40 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Kv { + kv: String, +} + +pub fn new() -> Kv { + Kv::new() +} + +impl Kv { + pub fn new() -> Kv { + Kv { + kv: BASE.to_owned(), + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Kv::new(); + let enc = Kv::encode(&val).unwrap(); + let dec = Kv::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/lv.rs b/src/key/lv.rs new file mode 100644 index 00000000..9e4a3c2f --- /dev/null +++ b/src/key/lv.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Lv { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + lv: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, lv: &str) -> Lv { + Lv::new(ns.to_string(), db.to_string(), tb.to_string(), lv.to_string()) +} + +impl Lv { + pub fn new(ns: String, db: String, tb: String, lv: String) -> Lv { + Lv { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("!lv"), + lv, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Lv::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Lv::encode(&val).unwrap(); + let dec = Lv::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/mod.rs b/src/key/mod.rs new file mode 100644 index 00000000..a69e0cda --- /dev/null +++ b/src/key/mod.rs @@ -0,0 +1,25 @@ +pub use self::key::*; + +pub mod bytes; +pub mod database; +pub mod db; +pub mod dt; +pub mod du; +pub mod ev; +pub mod fd; +pub mod ft; +pub mod index; +pub mod ix; +pub mod key; +pub mod kv; +pub mod lv; +pub mod namespace; +pub mod ns; +pub mod nt; +pub mod nu; +pub mod point; +pub mod sc; +pub mod st; +pub mod table; +pub mod tb; +pub mod thing; diff --git a/src/key/namespace.rs b/src/key/namespace.rs new file mode 100644 index 00000000..36aa949d --- /dev/null +++ b/src/key/namespace.rs @@ -0,0 +1,46 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Namespace { + kv: String, + _a: String, + ns: String, +} + +pub fn new(ns: &str) -> Namespace { + Namespace::new(ns.to_string()) +} + +impl Namespace { + pub fn new(ns: String) -> Namespace { + Namespace { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize::(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Namespace::new( + "test".to_string(), + ); + let enc = Namespace::encode(&val).unwrap(); + let dec = Namespace::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/ns.rs b/src/key/ns.rs new file mode 100644 index 00000000..ca94954f --- /dev/null +++ b/src/key/ns.rs @@ -0,0 +1,46 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Ns { + kv: String, + _a: String, + ns: String, +} + +pub fn new(ns: &str) -> Ns { + Ns::new(ns.to_string()) +} + +impl Ns { + pub fn new(ns: String) -> Ns { + Ns { + kv: BASE.to_owned(), + _a: String::from("!ns"), + ns, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize::(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Ns::new( + "test".to_string(), + ); + let enc = Ns::encode(&val).unwrap(); + let dec = Ns::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/nt.rs b/src/key/nt.rs new file mode 100644 index 00000000..a6ffee5b --- /dev/null +++ b/src/key/nt.rs @@ -0,0 +1,51 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Nt { + kv: String, + _a: String, + ns: String, + _b: String, + tk: String, +} + +pub fn new(ns: &str, tk: &str) -> Nt { + Nt::new(ns.to_string(), tk.to_string()) +} + +impl Nt { + pub fn new(ns: String, tk: String) -> Nt { + Nt { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("!tk"), + tk, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Nt::new( + "test".to_string(), + "test".to_string(), + ); + let enc = Nt::encode(&val).unwrap(); + let dec = Nt::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/nu.rs b/src/key/nu.rs new file mode 100644 index 00000000..abbcd69e --- /dev/null +++ b/src/key/nu.rs @@ -0,0 +1,51 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Nu { + kv: String, + _a: String, + ns: String, + _b: String, + us: String, +} + +pub fn new(ns: &str, us: &str) -> Nu { + Nu::new(ns.to_string(), us.to_string()) +} + +impl Nu { + pub fn new(ns: String, us: String) -> Nu { + Nu { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("!us"), + us, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Nu::new( + "test".to_string(), + "test".to_string(), + ); + let enc = Nu::encode(&val).unwrap(); + let dec = Nu::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/point.rs b/src/key/point.rs new file mode 100644 index 00000000..ba908f2b --- /dev/null +++ b/src/key/point.rs @@ -0,0 +1,68 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use crate::sql::value::Value; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Index { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + ix: String, + fd: Value, + id: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, ix: &str, fd: Value, id: &str) -> Index { + Index::new(ns.to_string(), db.to_string(), tb.to_string(), ix.to_string(), fd, id.to_string()) +} + +impl Index { + pub fn new(ns: String, db: String, tb: String, ix: String, fd: Value, id: String) -> Index { + Index { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("¤"), + ix, + fd, + id, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Index::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".into(), + "test".into(), + ); + let enc = Index::encode(&val).unwrap(); + let dec = Index::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/sc.rs b/src/key/sc.rs new file mode 100644 index 00000000..114a6187 --- /dev/null +++ b/src/key/sc.rs @@ -0,0 +1,56 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Sc { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + sc: String, +} + +pub fn new(ns: &str, db: &str, sc: &str) -> Sc { + Sc::new(ns.to_string(), db.to_string(), sc.to_string()) +} + +impl Sc { + pub fn new(ns: String, db: String, sc: String) -> Sc { + Sc { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("!sc"), + sc, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Sc::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Sc::encode(&val).unwrap(); + let dec = Sc::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/st.rs b/src/key/st.rs new file mode 100644 index 00000000..0543edab --- /dev/null +++ b/src/key/st.rs @@ -0,0 +1,61 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct St { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + sc: String, + _d: String, + tk: String, +} + +pub fn new(ns: &str, db: &str, sc: &str, tk: &str) -> St { + St::new(ns.to_string(), db.to_string(), sc.to_string(), tk.to_string()) +} + +impl St { + pub fn new(ns: String, db: String, sc: String, tk: String) -> St { + St { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("!st"), + sc, + _d: String::from("!tk"), + tk, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = St::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = St::encode(&val).unwrap(); + let dec = St::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/table.rs b/src/key/table.rs new file mode 100644 index 00000000..a482a693 --- /dev/null +++ b/src/key/table.rs @@ -0,0 +1,56 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Table { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, +} + +pub fn new(ns: &str, db: &str, tb: &str) -> Table { + Table::new(ns.to_string(), db.to_string(), tb.to_string()) +} + +impl Table { + pub fn new(ns: String, db: String, tb: String) -> Table { + Table { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Table::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Table::encode(&val).unwrap(); + let dec = Table::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/tb.rs b/src/key/tb.rs new file mode 100644 index 00000000..e0894319 --- /dev/null +++ b/src/key/tb.rs @@ -0,0 +1,56 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Tb { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, +} + +pub fn new(ns: &str, db: &str, tb: &str) -> Tb { + Tb::new(ns.to_string(), db.to_string(), tb.to_string()) +} + +impl Tb { + pub fn new(ns: String, db: String, tb: String) -> Tb { + Tb { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("!tb"), + tb, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Tb::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + ); + let enc = Tb::encode(&val).unwrap(); + let dec = Tb::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +} diff --git a/src/key/thing.rs b/src/key/thing.rs new file mode 100644 index 00000000..6b3a4512 --- /dev/null +++ b/src/key/thing.rs @@ -0,0 +1,62 @@ +use crate::err::Error; +use crate::key::bytes::{deserialize, serialize}; +use crate::key::BASE; +use crate::sql::value::Value; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Serialize, Deserialize)] +pub struct Thing { + kv: String, + _a: String, + ns: String, + _b: String, + db: String, + _c: String, + tb: String, + _d: String, + id: String, +} + +pub fn new(ns: &str, db: &str, tb: &str, id: &str) -> Thing { + Thing::new(ns.to_string(), db.to_string(), tb.to_string(), id.to_string()) +} + +impl Thing { + pub fn new(ns: String, db: String, tb: String, id: String) -> Thing { + Thing { + kv: BASE.to_owned(), + _a: String::from("*"), + ns, + _b: String::from("*"), + db, + _c: String::from("*"), + tb, + _d: String::from("*"), + id, + } + } + pub fn encode(&self) -> Result, Error> { + Ok(serialize(self)?) + } + pub fn decode(v: &[u8]) -> Result { + Ok(deserialize(v)?) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn key() { + use super::*; + #[rustfmt::skip] + let val = Thing::new( + "test".to_string(), + "test".to_string(), + "test".to_string(), + "test".into(), + ); + let enc = Thing::encode(&val).unwrap(); + let dec = Thing::decode(&enc).unwrap(); + assert_eq!(val, dec); + } +}