use crate::types::Type;
use ecow::EcoVec;
use num_traits::ToPrimitive;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use std::hash::{Hash, Hasher};
macro_rules! unsafe_irrefutable_let {
($pattern:pat = $value:expr) => {
let $pattern = $value else {
#[cfg(debug_assertions)]
unreachable!("this pattern shouldn't be reachable");
#[cfg(not(debug_assertions))]
unsafe {
std::hint::unreachable_unchecked()
};
};
};
}
#[derive(Clone)]
pub struct Value<T = Type, B = EcoVec<u8>> {
r#type: T,
bytes: B,
}
fn size_of_type(typ: &Type) -> usize {
match typ {
Type::Unknown => unimplemented!(),
Type::Boolean => 1,
Type::Integer => 4,
Type::Real => 4,
Type::Array { elem, size } => size * size_of_type(elem),
Type::Tuple(inner) => inner.iter().map(size_of_type).sum(),
}
}
impl<T: Borrow<Type>, B> Value<T, B> {
pub fn type_of(&self) -> &Type {
self.r#type.borrow()
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> Value<T, B> {
unsafe fn new_raw(r#type: T, bytes: B) -> Self {
debug_assert_eq!(size_of_type(r#type.borrow()), bytes.as_ref().len());
Self { r#type, bytes }
}
pub fn unpack(&self) -> UValue {
let r#type = self.r#type.borrow();
let bytes = self.bytes.as_ref();
match r#type {
Type::Unknown => unreachable!(),
Type::Boolean => {
unsafe_irrefutable_let!(Some([b @ 0..=1]) = bytes.get(..));
if *b == 0 {
UValue::Bool(false)
} else {
UValue::Bool(true)
}
}
Type::Integer => {
unsafe_irrefutable_let!(Some(&[a, b, c, d]) = bytes.get(..));
UValue::Int(i32::from_ne_bytes([a, b, c, d]))
}
Type::Real => {
unsafe_irrefutable_let!(Some(&[a, b, c, d]) = bytes.get(..));
UValue::Real(decorum::N32::from_inner(f32::from_ne_bytes([a, b, c, d])))
}
array_type @ Type::Array { elem, size } => UValue::Array(UArray {
element_type: array_type,
element_size: size_of_type(elem),
remaining_len: *size,
total_len: *size,
bytes,
}),
Type::Tuple(elements) => UValue::Tuple(UTuple {
elements: elements.iter(),
remaining_len: elements.len(),
bytes,
}),
}
}
pub fn as_ref(&self) -> Value<&Type, &[u8]> {
unsafe { Value::new_raw(self.r#type.borrow(), self.bytes.as_ref()) }
}
pub fn to_owned(&self) -> Value {
Value {
r#type: self.r#type.borrow().clone(),
bytes: self.bytes.as_ref().into(),
}
}
}
impl Value {
pub fn from_bool(value: bool) -> Self {
unsafe { Self::new_raw(Type::Boolean, [value as u8].into()) }
}
pub fn from_int(value: i32) -> Self {
unsafe { Self::new_raw(Type::Integer, value.to_ne_bytes().into()) }
}
pub fn from_real(value: decorum::N32) -> Self {
unsafe { Self::new_raw(Type::Real, value.to_f32().unwrap().to_ne_bytes().into()) }
}
pub fn repeat(self, n: usize) -> Self {
Self {
r#type: Type::Array {
elem: Box::new(self.r#type),
size: n,
},
bytes: self.bytes.repeat(n).into(),
}
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> Debug for Value<T, B> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.unpack(), f)
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> Eq for Value<T, B> {}
impl<T: Borrow<Type>, B: AsRef<[u8]>> PartialEq for Value<T, B> {
fn eq(&self, other: &Self) -> bool {
self.r#type.borrow() == other.r#type.borrow() && self.bytes.as_ref() == other.bytes.as_ref()
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> Ord for Value<T, B> {
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(self.r#type.borrow(), other.r#type.borrow())
.then_with(|| Ord::cmp(&self.unpack(), &other.unpack()))
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> PartialOrd for Value<T, B> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}
impl<T: Borrow<Type>, B: AsRef<[u8]>> Hash for Value<T, B> {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(self.r#type.borrow(), state);
Hash::hash(self.bytes.as_ref(), state);
}
}
#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum UValue<'value> {
Bool(bool),
Int(i32),
Real(decorum::N32),
Array(UArray<'value>),
Tuple(UTuple<'value>),
}
impl Debug for UValue<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
UValue::Bool(value) => Debug::fmt(value, f),
UValue::Int(value) => Debug::fmt(value, f),
UValue::Real(value) => Debug::fmt(value, f),
UValue::Array(value) => {
let mut f = f.debug_list();
for element in value.clone() {
f.entry(&element);
}
f.finish()
}
UValue::Tuple(value) => {
let mut f = f.debug_tuple("");
for element in value.clone() {
f.field(&element);
}
f.finish()
}
}
}
}
#[derive(Clone, Eq)]
pub struct UArray<'value> {
element_type: &'value Type,
element_size: usize,
remaining_len: usize,
total_len: usize,
bytes: &'value [u8],
}
impl<'value> UArray<'value> {
pub fn element_type(&self) -> &Type {
self.element_type
}
pub fn total_len(&self) -> usize {
self.total_len
}
pub fn is_empty(&self) -> bool {
self.remaining_len == 0
}
unsafe fn unsafe_advance(&mut self) -> Value<&'value Type, &'value [u8]> {
let (element, rest) = self.bytes.split_at_unchecked(self.element_size);
self.bytes = rest;
self.remaining_len -= 1;
Value::new_raw(self.element_type, element)
}
}
impl<'value> Iterator for UArray<'value> {
type Item = Value<&'value Type, &'value [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.is_empty() {
None
} else {
Some(unsafe { self.unsafe_advance() })
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.total_len - self.bytes.len() / self.element_size;
(remaining, Some(remaining))
}
}
impl PartialEq for UArray<'_> {
fn eq(&self, other: &Self) -> bool {
Iterator::eq(self.clone(), other.clone())
}
}
impl Ord for UArray<'_> {
fn cmp(&self, other: &Self) -> Ordering {
Iterator::cmp(self.clone(), other.clone())
}
}
impl PartialOrd for UArray<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}
impl Hash for UArray<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&self.element_type, state);
Hash::hash(&self.bytes, state);
}
}
#[derive(Clone)]
pub struct UTuple<'value> {
elements: std::slice::Iter<'value, Type>,
remaining_len: usize,
bytes: &'value [u8],
}
impl<'value> UTuple<'value> {
pub fn is_empty(&self) -> bool {
self.remaining_len == 0
}
unsafe fn unsafe_advance(&mut self) -> Value<&'value Type, &'value [u8]> {
unsafe_irrefutable_let!(Some(next_element) = self.elements.next());
let (element, rest) = self.bytes.split_at_unchecked(size_of_type(next_element));
self.bytes = rest;
self.remaining_len -= 1;
Value::new_raw(next_element, element)
}
}
impl<'value> Iterator for UTuple<'value> {
type Item = Value<&'value Type, &'value [u8]>;
fn next(&mut self) -> Option<Self::Item> {
if self.is_empty() {
None
} else {
Some(unsafe { self.unsafe_advance() })
}
}
}
impl Eq for UTuple<'_> {}
impl PartialEq for UTuple<'_> {
fn eq(&self, other: &Self) -> bool {
Iterator::eq(self.clone(), other.clone())
}
}
impl Ord for UTuple<'_> {
fn cmp(&self, other: &Self) -> Ordering {
Iterator::cmp(self.clone(), other.clone())
}
}
impl PartialOrd for UTuple<'_> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}
impl Hash for UTuple<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
for element in self.clone() {
Hash::hash(&element, state);
}
}
}