use core::{fmt, marker::PhantomData};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct TableId(pub u16);
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct IndexKey(pub Vec<u8>);
impl IndexKey {
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
}
pub struct Index<T, K> {
pub position: usize,
pub name: &'static str,
_record: PhantomData<fn(&T) -> K>,
}
impl<T, K> Index<T, K> {
#[doc(hidden)]
pub const fn new(position: usize, name: &'static str) -> Self {
Index {
position,
name,
_record: PhantomData,
}
}
}
impl<T, K> Clone for Index<T, K> {
fn clone(&self) -> Self {
*self
}
}
impl<T, K> Copy for Index<T, K> {}
impl<T, K> fmt::Debug for Index<T, K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Index({})", self.name)
}
}
pub struct IndexDesc<T> {
pub name: &'static str,
pub unique: bool,
pub extract: fn(&T) -> IndexKey,
}
impl<T> Clone for IndexDesc<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for IndexDesc<T> {}
pub trait Encodable {
fn encode_to(&self, out: &mut Vec<u8>);
fn encode(&self) -> IndexKey {
let mut out = Vec::new();
self.encode_to(&mut out);
IndexKey(out)
}
}
macro_rules! impl_encodable_uint {
($($t:ty),*) => {$(
impl Encodable for $t {
#[inline]
fn encode_to(&self, out: &mut Vec<u8>) {
out.extend_from_slice(&self.to_be_bytes());
}
}
)*};
}
impl_encodable_uint!(u8, u16, u32, u64, u128);
macro_rules! impl_encodable_int {
($($t:ty => $u:ty),*) => {$(
impl Encodable for $t {
#[inline]
fn encode_to(&self, out: &mut Vec<u8>) {
let biased = (*self as $u) ^ (1 << (<$u>::BITS - 1));
out.extend_from_slice(&biased.to_be_bytes());
}
}
)*};
}
impl_encodable_int!(i8 => u8, i16 => u16, i32 => u32, i64 => u64, i128 => u128);
impl Encodable for String {
fn encode_to(&self, out: &mut Vec<u8>) {
self.as_str().encode_to(out);
}
}
impl Encodable for str {
fn encode_to(&self, out: &mut Vec<u8>) {
for &b in self.as_bytes() {
if b == 0x00 {
out.extend_from_slice(&[0x00, 0xff]);
} else {
out.push(b);
}
}
out.extend_from_slice(&[0x00, 0x00]);
}
}
impl<T: Encodable> Encodable for &T {
fn encode_to(&self, out: &mut Vec<u8>) {
(**self).encode_to(out);
}
}
#[cfg(test)]
mod tests {
use super::*;
fn key<T: Encodable>(v: T) -> Vec<u8> {
v.encode().0
}
#[test]
fn unsigned_keys_sort_numerically() {
assert!(key(1u64) < key(2u64));
assert!(key(255u64) < key(256u64));
}
#[test]
fn signed_keys_sort_with_negatives_first() {
assert!(key(-1i64) < key(0i64));
assert!(key(i64::MIN) < key(i64::MAX));
assert!(key(-5i64) < key(-4i64));
}
#[test]
fn string_prefixes_sort_before_extensions() {
assert!(key("ab".to_string()) < key("abc".to_string()));
assert!(key("a".to_string()) < key("b".to_string()));
}
#[test]
fn embedded_nul_cannot_forge_a_separator() {
assert_ne!(key("a\0b".to_string()), {
let mut v = key("a".to_string());
v.extend_from_slice(&key("b".to_string()));
v
});
}
}