feat: encoding of nested option types
This commit is contained in:
parent
af5490e2dc
commit
896d40ab64
1 changed files with 132 additions and 65 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
use crate::error::TypeConversionError;
|
use crate::error::TypeConversionError;
|
||||||
use std::cmp::Ordering;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::fmt::format;
|
||||||
|
|
||||||
// ==============Types================
|
// ==============Types================
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
|
@ -9,7 +10,7 @@ pub enum DbType {
|
||||||
Int,
|
Int,
|
||||||
Number,
|
Number,
|
||||||
Uuid,
|
Uuid,
|
||||||
Option(Box<DbType>)
|
Option(Box<DbType>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==============Values================
|
// ==============Values================
|
||||||
|
|
@ -48,7 +49,7 @@ impl PartialOrd for IndexableValue {
|
||||||
(IndexableValue::None(_), IndexableValue::Some(_)) => Some(Ordering::Less),
|
(IndexableValue::None(_), IndexableValue::Some(_)) => Some(Ordering::Less),
|
||||||
(IndexableValue::Some(_), IndexableValue::None(_)) => Some(Ordering::Greater),
|
(IndexableValue::Some(_), IndexableValue::None(_)) => Some(Ordering::Greater),
|
||||||
(IndexableValue::Some(v0), IndexableValue::Some(v1)) => v0.partial_cmp(v1),
|
(IndexableValue::Some(v0), IndexableValue::Some(v1)) => v0.partial_cmp(v1),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,29 +65,38 @@ impl Ord for IndexableValue {
|
||||||
(IndexableValue::Some(_), IndexableValue::None(_)) => Ordering::Greater,
|
(IndexableValue::Some(_), IndexableValue::None(_)) => Ordering::Greater,
|
||||||
(IndexableValue::Some(v0), IndexableValue::Some(v1)) => v0.cmp(v1),
|
(IndexableValue::Some(v0), IndexableValue::Some(v1)) => v0.cmp(v1),
|
||||||
_ =>
|
_ =>
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// We are using indexable values as keys in key-value maps.
|
// We are using indexable values as keys in key-value maps.
|
||||||
// When validation is done, it can't happen that we will be comparing two values
|
// When validation is done, it can't happen that we will be comparing two values
|
||||||
// of different types.
|
// of different types.
|
||||||
// Ofcourse another option is to artificialy order e.g.
|
// Ofcourse another option is to artificialy order e.g.
|
||||||
// None < Some(...) < String < Int < Uuid
|
// None < Some(...) < String < Int < Uuid
|
||||||
// where ... is again None < Some(...) < String < Int < Uuid
|
// where ... is again None < Some(...) < String < Int < Uuid
|
||||||
// where ...
|
// where ...
|
||||||
// infinitely deep total order. But this is pointless for our usecase.
|
// infinitely deep total order. But this is pointless for our usecase.
|
||||||
unreachable!()
|
{
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DbType {
|
impl DbType {
|
||||||
|
fn new_n_option(n: usize, inside: DbType) -> DbType {
|
||||||
|
if n == 0 {
|
||||||
|
inside
|
||||||
|
} else {
|
||||||
|
DbType::Option(Box::new(DbType::new_n_option(n - 1, inside)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_indexable(&self) -> bool {
|
pub fn is_indexable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::String => true,
|
Self::String => true,
|
||||||
Self::Int => true,
|
Self::Int => true,
|
||||||
Self::Number => false,
|
Self::Number => false,
|
||||||
Self::Uuid => true,
|
Self::Uuid => true,
|
||||||
Self::Option(type_) => type_.is_indexable()
|
Self::Option(type_) => type_.is_indexable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,24 +131,39 @@ impl DbType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_oid_and_size(oid: i32, size: i16) -> Option<DbType> {
|
||||||
|
match (oid, size) {
|
||||||
|
(25, -2) => Some(DbType::String),
|
||||||
|
(23, 8) => Some(DbType::Int),
|
||||||
|
(701, 8) => Some(DbType::Number),
|
||||||
|
(2950, 16) => Some(DbType::Uuid),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn type_oid(&self) -> i32 {
|
pub fn type_oid(&self) -> i32 {
|
||||||
// match self {
|
match self {
|
||||||
// Self::String => 25,
|
Self::String => 25,
|
||||||
// Self::Int => 23,
|
Self::Int => 23,
|
||||||
// Self::Number => 701,
|
Self::Number => 701,
|
||||||
// Self::Uuid => 2950,
|
Self::Uuid => 2950,
|
||||||
// }
|
Self::Option(t) => {
|
||||||
todo!()
|
let oid = t.type_oid();
|
||||||
|
let type_part = (oid & 0x0000FFFF) as u16;
|
||||||
|
let nest_part = ((oid & 0xFFFF0000) >> 16) as u16 + 1;
|
||||||
|
(type_part | (nest_part << 16)) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_size(&self) -> i16 {
|
pub fn type_size(&self) -> i16 {
|
||||||
// match self {
|
match self {
|
||||||
// Self::String => -2, // null terminated string
|
Self::String => -2, // null terminated string
|
||||||
// Self::Int => 8,
|
Self::Int => 8,
|
||||||
// Self::Number => 8,
|
Self::Number => 8,
|
||||||
// Self::Uuid => 16,
|
Self::Uuid => 16,
|
||||||
// }
|
Self::Option(t) => t.type_size(),
|
||||||
todo!()
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -216,17 +241,20 @@ impl Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
pub fn as_text_bytes(&self) -> Vec<u8> {
|
pub fn as_text_bytes(&self) -> Vec<u8> {
|
||||||
// match self {
|
match self {
|
||||||
// Self::Number(n) => format!("{n}").into_bytes(),
|
Self::Number(n) => format!("{n}").into_bytes(),
|
||||||
// Self::Indexable(i) => match i {
|
Self::String(s) => format!("{s}\0").into_bytes(),
|
||||||
// IndexableValue::String(s) => format!("{s}\0").into_bytes(),
|
Self::Int(i) => format!("{i}").into_bytes(),
|
||||||
// IndexableValue::Int(i) => format!("{i}").into_bytes(),
|
Self::Uuid(u) => format!("u{u}").into_bytes(),
|
||||||
// IndexableValue::Uuid(u) => format!("{u}").into_bytes(),
|
Self::None(_) => b"None".into(),
|
||||||
// },
|
Self::Some(val) => {
|
||||||
// }
|
let mut bytes = Vec::from(b"Some(");
|
||||||
todo!()
|
bytes.append(&mut val.as_text_bytes());
|
||||||
|
bytes.push(b')');
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_text_bytes(
|
pub fn from_text_bytes(
|
||||||
|
|
@ -234,30 +262,68 @@ impl Value {
|
||||||
type_oid: i32,
|
type_oid: i32,
|
||||||
type_size: i16,
|
type_size: i16,
|
||||||
) -> Result<Value, TypeConversionError> {
|
) -> Result<Value, TypeConversionError> {
|
||||||
// match (type_oid, type_size) {
|
let text = std::str::from_utf8(bytes)?;
|
||||||
// (701, 8) => {
|
let type_part = (type_oid & 0x0000FFFF) as u16;
|
||||||
// let s = std::str::from_utf8(bytes)?;
|
let nest_part = ((type_oid as u32 & 0xFFFF0000) >> 16) as u16;
|
||||||
// let n = s.parse::<f64>()?;
|
|
||||||
// Ok(Value::Number(n))
|
Self::internal_from_text_bytes(text, type_part, nest_part, type_size)
|
||||||
// }
|
}
|
||||||
// (25, -2) => {
|
|
||||||
// let s = std::str::from_utf8(bytes)?;
|
fn internal_from_text_bytes(
|
||||||
// let s = &s[..s.len() - 1]; // remove null terminator
|
text: &str,
|
||||||
// Ok(Value::Indexable(IndexableValue::String(s.to_string())))
|
type_part: u16,
|
||||||
// }
|
nest_part: u16,
|
||||||
// (23, 8) => {
|
type_size: i16,
|
||||||
// let s = std::str::from_utf8(bytes)?;
|
) -> Result<Value, TypeConversionError> {
|
||||||
// let n = s.parse::<u64>()?;
|
if text == "None" {
|
||||||
// Ok(Value::Indexable(IndexableValue::Int(n)))
|
let db_type =
|
||||||
// }
|
DbType::from_oid_and_size(type_part as i32, type_size).ok_or_else(|| {
|
||||||
// (2950, 16) => {
|
TypeConversionError::UnknownType {
|
||||||
// let s = std::str::from_utf8(bytes)?;
|
oid: type_part as i32,
|
||||||
// let n = s.parse::<Uuid>()?;
|
size: type_size,
|
||||||
// Ok(Value::Indexable(IndexableValue::Uuid(n)))
|
}
|
||||||
// }
|
})?;
|
||||||
// (oid, size) => Err(TypeConversionError::UnknownType { oid, size }),
|
return if nest_part == 0 {
|
||||||
// }
|
Ok(Value::None(db_type))
|
||||||
todo!()
|
} else {
|
||||||
|
Ok(Value::None(DbType::new_n_option(
|
||||||
|
nest_part as usize,
|
||||||
|
db_type,
|
||||||
|
)))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if text.starts_with("Some(") {
|
||||||
|
let val = Self::from_text_bytes(
|
||||||
|
&text[5..text.len() - 1].as_bytes(),
|
||||||
|
type_part as i32,
|
||||||
|
type_size,
|
||||||
|
)?;
|
||||||
|
return Ok(Value::Some(Box::new(val)));
|
||||||
|
}
|
||||||
|
|
||||||
|
match (type_part, type_size) {
|
||||||
|
(701, 8) => {
|
||||||
|
let n = text.parse::<f64>()?;
|
||||||
|
Ok(Value::Number(n))
|
||||||
|
}
|
||||||
|
(25, -2) => {
|
||||||
|
let s = &text[..text.len() - 1]; // remove null terminator
|
||||||
|
Ok(Value::String(s.to_string()))
|
||||||
|
}
|
||||||
|
(23, 8) => {
|
||||||
|
let n = text.parse::<u64>()?;
|
||||||
|
Ok(Value::Int(n))
|
||||||
|
}
|
||||||
|
(2950, 16) => {
|
||||||
|
let n = text.parse::<Uuid>()?;
|
||||||
|
Ok(Value::Uuid(n))
|
||||||
|
}
|
||||||
|
(oid, size) => Err(TypeConversionError::UnknownType {
|
||||||
|
oid: oid as i32,
|
||||||
|
size,
|
||||||
|
}),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,7 +333,9 @@ impl IndexableValue {
|
||||||
IndexableValue::String(str) => Value::String(str),
|
IndexableValue::String(str) => Value::String(str),
|
||||||
IndexableValue::Int(n) => Value::Int(n),
|
IndexableValue::Int(n) => Value::Int(n),
|
||||||
IndexableValue::Uuid(id) => Value::Uuid(id),
|
IndexableValue::Uuid(id) => Value::Uuid(id),
|
||||||
IndexableValue::Some(indexable_value) => Value::Some(Box::new(indexable_value.to_value())),
|
IndexableValue::Some(indexable_value) => {
|
||||||
|
Value::Some(Box::new(indexable_value.to_value()))
|
||||||
|
}
|
||||||
IndexableValue::None(type_) => Value::None(type_),
|
IndexableValue::None(type_) => Value::None(type_),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -322,7 +390,6 @@ impl From<IndexableValue> for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Own string serialization so enums can be used as keys in maps
|
// Own string serialization so enums can be used as keys in maps
|
||||||
impl From<IndexableValue> for String {
|
impl From<IndexableValue> for String {
|
||||||
fn from(value: IndexableValue) -> Self {
|
fn from(value: IndexableValue) -> Self {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue