use std::cmp::Ordering;
use std::convert::TryInto;
use std::fmt::Debug;
use std::mem::size_of;
#[derive(Eq, PartialEq, Clone, Debug)]
enum TypeClassification {
Internal,
UserDefined,
}
impl TypeClassification {
fn to_byte(&self) -> u8 {
match self {
TypeClassification::Internal => 1,
TypeClassification::UserDefined => 2,
}
}
fn from_byte(value: u8) -> Self {
match value {
1 => TypeClassification::Internal,
2 => TypeClassification::UserDefined,
_ => unreachable!(),
}
}
}
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct TypeName {
classification: TypeClassification,
name: String,
}
impl TypeName {
pub fn new(name: &str) -> Self {
Self {
classification: TypeClassification::UserDefined,
name: name.to_string(),
}
}
pub(crate) fn internal(name: &str) -> Self {
Self {
classification: TypeClassification::Internal,
name: name.to_string(),
}
}
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::with_capacity(self.name.as_bytes().len() + 1);
result.push(self.classification.to_byte());
result.extend_from_slice(self.name.as_bytes());
result
}
pub(crate) fn from_bytes(bytes: &[u8]) -> Self {
let classification = TypeClassification::from_byte(bytes[0]);
let name = std::str::from_utf8(&bytes[1..]).unwrap().to_string();
Self {
classification,
name,
}
}
pub(crate) fn name(&self) -> &str {
&self.name
}
}
pub trait Value: Debug {
type SelfType<'a>: Debug + 'a
where
Self: 'a;
type AsBytes<'a>: AsRef<[u8]> + 'a
where
Self: 'a;
fn fixed_width() -> Option<usize>;
fn from_bytes<'a>(data: &'a [u8]) -> Self::SelfType<'a>
where
Self: 'a;
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Self::AsBytes<'a>
where
Self: 'a,
Self: 'b;
fn type_name() -> TypeName;
}
pub trait MutInPlaceValue: Value {
type BaseRefType: Debug + ?Sized;
fn initialize(data: &mut [u8]);
fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType;
}
impl MutInPlaceValue for &[u8] {
type BaseRefType = [u8];
fn initialize(_data: &mut [u8]) {
}
fn from_bytes_mut(data: &mut [u8]) -> &mut Self::BaseRefType {
data
}
}
pub trait Key: Value {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering;
}
impl Value for () {
type SelfType<'a> = ()
where
Self: 'a;
type AsBytes<'a> = &'a [u8]
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(0)
}
#[allow(clippy::unused_unit)]
fn from_bytes<'a>(_data: &'a [u8]) -> ()
where
Self: 'a,
{
()
}
fn as_bytes<'a, 'b: 'a>(_: &'a Self::SelfType<'b>) -> &'a [u8]
where
Self: 'a,
Self: 'b,
{
&[]
}
fn type_name() -> TypeName {
TypeName::internal("()")
}
}
impl Key for () {
fn compare(_data1: &[u8], _data2: &[u8]) -> Ordering {
Ordering::Equal
}
}
impl Value for bool {
type SelfType<'a> = bool
where
Self: 'a;
type AsBytes<'a> = &'a [u8]
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(1)
}
fn from_bytes<'a>(data: &'a [u8]) -> bool
where
Self: 'a,
{
match data[0] {
0 => false,
1 => true,
_ => unreachable!(),
}
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
where
Self: 'a,
Self: 'b,
{
match value {
true => &[1],
false => &[0],
}
}
fn type_name() -> TypeName {
TypeName::internal("bool")
}
}
impl Key for bool {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
let value1 = Self::from_bytes(data1);
let value2 = Self::from_bytes(data2);
value1.cmp(&value2)
}
}
impl<T: Value> Value for Option<T> {
type SelfType<'a> = Option<T::SelfType<'a>>
where
Self: 'a;
type AsBytes<'a> = Vec<u8>
where
Self: 'a;
fn fixed_width() -> Option<usize> {
T::fixed_width().map(|x| x + 1)
}
fn from_bytes<'a>(data: &'a [u8]) -> Option<T::SelfType<'a>>
where
Self: 'a,
{
match data[0] {
0 => None,
1 => Some(T::from_bytes(&data[1..])),
_ => unreachable!(),
}
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Vec<u8>
where
Self: 'a,
Self: 'b,
{
let mut result = vec![0];
if let Some(x) = value {
result[0] = 1;
result.extend_from_slice(T::as_bytes(x).as_ref());
} else if let Some(fixed_width) = T::fixed_width() {
result.extend_from_slice(&vec![0; fixed_width]);
}
result
}
fn type_name() -> TypeName {
TypeName::internal(&format!("Option<{}>", T::type_name().name()))
}
}
impl<T: Key> Key for Option<T> {
#[allow(clippy::collapsible_else_if)]
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
if data1[0] == 0 {
if data2[0] == 0 {
Ordering::Equal
} else {
Ordering::Less
}
} else {
if data2[0] == 0 {
Ordering::Greater
} else {
T::compare(&data1[1..], &data2[1..])
}
}
}
}
impl Value for &[u8] {
type SelfType<'a> = &'a [u8]
where
Self: 'a;
type AsBytes<'a> = &'a [u8]
where
Self: 'a;
fn fixed_width() -> Option<usize> {
None
}
fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8]
where
Self: 'a,
{
data
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8]
where
Self: 'a,
Self: 'b,
{
value
}
fn type_name() -> TypeName {
TypeName::internal("&[u8]")
}
}
impl Key for &[u8] {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
data1.cmp(data2)
}
}
impl<const N: usize> Value for &[u8; N] {
type SelfType<'a> = &'a [u8; N]
where
Self: 'a;
type AsBytes<'a> = &'a [u8; N]
where
Self: 'a;
fn fixed_width() -> Option<usize> {
Some(N)
}
fn from_bytes<'a>(data: &'a [u8]) -> &'a [u8; N]
where
Self: 'a,
{
data.try_into().unwrap()
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a [u8; N]
where
Self: 'a,
Self: 'b,
{
value
}
fn type_name() -> TypeName {
TypeName::internal(&format!("[u8;{N}]"))
}
}
impl<const N: usize> Key for &[u8; N] {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
data1.cmp(data2)
}
}
impl<const N: usize, T: Value> Value for [T; N] {
type SelfType<'a> = [T::SelfType<'a>; N]
where
Self: 'a;
type AsBytes<'a> = Vec<u8>
where
Self: 'a;
fn fixed_width() -> Option<usize> {
T::fixed_width().map(|x| x * N)
}
fn from_bytes<'a>(data: &'a [u8]) -> [T::SelfType<'a>; N]
where
Self: 'a,
{
let mut result = Vec::with_capacity(N);
if let Some(fixed) = T::fixed_width() {
for i in 0..N {
result.push(T::from_bytes(&data[fixed * i..fixed * (i + 1)]));
}
} else {
let mut start = size_of::<u32>() * N;
for i in 0..N {
let range = size_of::<u32>() * i..size_of::<u32>() * (i + 1);
let end = u32::from_le_bytes(data[range].try_into().unwrap()) as usize;
result.push(T::from_bytes(&data[start..end]));
start = end;
}
}
result.try_into().unwrap()
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> Vec<u8>
where
Self: 'a,
Self: 'b,
{
if let Some(fixed) = T::fixed_width() {
let mut result = Vec::with_capacity(fixed * N);
for item in value.iter() {
result.extend_from_slice(T::as_bytes(item).as_ref());
}
result
} else {
let mut result = vec![0u8; size_of::<u32>() * N];
for i in 0..N {
result.extend_from_slice(T::as_bytes(&value[i]).as_ref());
let end: u32 = result.len().try_into().unwrap();
result[size_of::<u32>() * i..size_of::<u32>() * (i + 1)]
.copy_from_slice(&end.to_le_bytes());
}
result
}
}
fn type_name() -> TypeName {
TypeName::internal(&format!("[{};{N}]", T::type_name().name()))
}
}
impl<const N: usize, T: Key> Key for [T; N] {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
if let Some(fixed) = T::fixed_width() {
for i in 0..N {
let range = fixed * i..fixed * (i + 1);
let comparison = T::compare(&data1[range.clone()], &data2[range]);
if !comparison.is_eq() {
return comparison;
}
}
} else {
let mut start1 = size_of::<u32>() * N;
let mut start2 = size_of::<u32>() * N;
for i in 0..N {
let range = size_of::<u32>() * i..size_of::<u32>() * (i + 1);
let end1 = u32::from_le_bytes(data1[range.clone()].try_into().unwrap()) as usize;
let end2 = u32::from_le_bytes(data2[range].try_into().unwrap()) as usize;
let comparison = T::compare(&data1[start1..end1], &data2[start2..end2]);
if !comparison.is_eq() {
return comparison;
}
start1 = end1;
start2 = end2;
}
}
Ordering::Equal
}
}
impl Value for &str {
type SelfType<'a> = &'a str
where
Self: 'a;
type AsBytes<'a> = &'a str
where
Self: 'a;
fn fixed_width() -> Option<usize> {
None
}
fn from_bytes<'a>(data: &'a [u8]) -> &'a str
where
Self: 'a,
{
std::str::from_utf8(data).unwrap()
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a str
where
Self: 'a,
Self: 'b,
{
value
}
fn type_name() -> TypeName {
TypeName::internal("&str")
}
}
impl Key for &str {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
let str1 = Self::from_bytes(data1);
let str2 = Self::from_bytes(data2);
str1.cmp(str2)
}
}
impl Value for String {
type SelfType<'a> = String
where
Self: 'a;
type AsBytes<'a> = &'a str
where
Self: 'a;
fn fixed_width() -> Option<usize> {
None
}
fn from_bytes<'a>(data: &'a [u8]) -> String
where
Self: 'a,
{
std::str::from_utf8(data).unwrap().to_string()
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> &'a str
where
Self: 'a,
Self: 'b,
{
value.as_str()
}
fn type_name() -> TypeName {
TypeName::internal("String")
}
}
impl Key for String {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
let str1 = std::str::from_utf8(data1).unwrap();
let str2 = std::str::from_utf8(data2).unwrap();
str1.cmp(str2)
}
}
impl Value for char {
type SelfType<'a> = char;
type AsBytes<'a> = [u8; 3] where Self: 'a;
fn fixed_width() -> Option<usize> {
Some(3)
}
fn from_bytes<'a>(data: &'a [u8]) -> char
where
Self: 'a,
{
char::from_u32(u32::from_le_bytes([data[0], data[1], data[2], 0])).unwrap()
}
fn as_bytes<'a, 'b: 'a>(value: &'a Self::SelfType<'b>) -> [u8; 3]
where
Self: 'a,
Self: 'b,
{
let bytes = u32::from(*value).to_le_bytes();
[bytes[0], bytes[1], bytes[2]]
}
fn type_name() -> TypeName {
TypeName::internal(stringify!(char))
}
}
impl Key for char {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
}
}
macro_rules! le_value {
($t:ty) => {
impl Value for $t {
type SelfType<'a> = $t;
type AsBytes<'a> = [u8; std::mem::size_of::<$t>()] where Self: 'a;
fn fixed_width() -> Option<usize> {
Some(std::mem::size_of::<$t>())
}
fn from_bytes<'a>(data: &'a [u8]) -> $t
where
Self: 'a,
{
<$t>::from_le_bytes(data.try_into().unwrap())
}
fn as_bytes<'a, 'b: 'a>(
value: &'a Self::SelfType<'b>,
) -> [u8; std::mem::size_of::<$t>()]
where
Self: 'a,
Self: 'b,
{
value.to_le_bytes()
}
fn type_name() -> TypeName {
TypeName::internal(stringify!($t))
}
}
};
}
macro_rules! le_impl {
($t:ty) => {
le_value!($t);
impl Key for $t {
fn compare(data1: &[u8], data2: &[u8]) -> Ordering {
Self::from_bytes(data1).cmp(&Self::from_bytes(data2))
}
}
};
}
le_impl!(u8);
le_impl!(u16);
le_impl!(u32);
le_impl!(u64);
le_impl!(u128);
le_impl!(i8);
le_impl!(i16);
le_impl!(i32);
le_impl!(i64);
le_impl!(i128);
le_value!(f32);
le_value!(f64);