litl-val 0.2.0

A memory efficient representation of JSON values
Documentation
use std::ptr::NonNull;

use nanval::cell::{
    from_tag_and_data, from_tag_and_pointer, unwrap_cell, unwrap_cell_rawptr, unwrap_tag, CellTag,
};
use ordered_float::NotNan;

use crate::ValRef;

use super::{
    key::{Key, ValKeyError},
    key_e::KeyE,
    map::Map,
    map_ref::MapRef,
    slim_boxed_slice::{slim_box_parts_for_slice, SlimBoxedSlice, SlimBoxedString},
    tiny_string::TinyString,
    val::Val,
    val_e::ValE,
};

impl From<ValE> for Val {
    #[inline]
    fn from(val_e: ValE) -> Self {
        match val_e {
            ValE::Null => Self(f64::from_bits(from_tag_and_data(CellTag::Tag1, 2).unwrap())),
            ValE::Bool(b) => Self(f64::from_bits(
                from_tag_and_data(CellTag::Tag1, if b { 1 } else { 0 }).unwrap(),
            )),
            ValE::Number(num) => Self(num.into_inner()),
            ValE::ShortString(s) => {
                let bytes6 = s.to_bytes();
                let bytes8: [u8; 8] = [
                    bytes6[0], bytes6[1], bytes6[2], bytes6[3], bytes6[4], bytes6[5], 0, 0,
                ];
                Self(f64::from_bits(
                    from_tag_and_data(CellTag::Tag2, u64::from_ne_bytes(bytes8)).unwrap(),
                ))
            }
            ValE::LongString(slim_box) => Self(f64::from_bits(
                from_tag_and_pointer(CellTag::Tag3, slim_box.into_raw() as *mut ()).unwrap(),
            )),
            ValE::Array(slim_box) => Self(f64::from_bits(
                from_tag_and_pointer(CellTag::Tag4, slim_box.into_raw() as *mut ()).unwrap(),
            )),
            ValE::Object(map) => Self(f64::from_bits(
                from_tag_and_pointer(CellTag::Tag5, map.into_raw() as *mut ()).unwrap(),
            )),
        }
    }
}

impl From<Val> for ValE {
    fn from(val: Val) -> Self {
        match unwrap_tag(val.0) {
            Some(CellTag::Tag1) => match unwrap_cell(val.0).unwrap() {
                0 => ValE::Bool(false),
                1 => ValE::Bool(true),
                2 => ValE::Null,
                _ => unreachable!("Invalid symbol value"),
            },
            Some(CellTag::Tag2) => {
                let bytes8 = unwrap_cell(val.0).unwrap().to_ne_bytes();
                let bytes6 = [
                    bytes8[0], bytes8[1], bytes8[2], bytes8[3], bytes8[4], bytes8[5],
                ];
                ValE::ShortString(unsafe { TinyString::from_bytes_unchecked(bytes6) })
            }
            Some(CellTag::Tag3) => {
                let ptr = unwrap_cell_rawptr(val.0).unwrap() as *mut ();
                ValE::LongString(unsafe { SlimBoxedString::from_raw(ptr) })
            }
            Some(CellTag::Tag4) => {
                let ptr = unwrap_cell_rawptr(val.0).unwrap() as *mut ();
                ValE::Array(unsafe { SlimBoxedSlice::from_raw(ptr) })
            }
            Some(CellTag::Tag5) => {
                let ptr = unwrap_cell_rawptr(val.0).unwrap() as *mut ();
                ValE::Object(unsafe { Map::from_raw(ptr) })
            }
            Some(_) => unreachable!("Invalid tag"),
            None => ValE::Number(NotNan::new(val.0).unwrap()),
        }
    }
}

impl ValE {
    pub fn as_ref(&self) -> ValRef {
        match &self {
            ValE::Null => ValRef::Null,
            ValE::Bool(b) => ValRef::Bool(*b),
            ValE::Number(n) => ValRef::Number(*n),
            ValE::ShortString(s) => ValRef::String(s.as_ref()),
            ValE::LongString(s) => ValRef::String(s.as_ref()),
            ValE::Array(a) => ValRef::Array(a.as_ref()),
            ValE::Object(o) => ValRef::Object(o.as_ref()),
        }
    }
}

impl Val {
    #[inline]
    pub fn direct_ref(&self) -> ValRef {
        match unwrap_tag(self.0) {
            Some(CellTag::Tag1) => match unwrap_cell(self.0).unwrap() {
                0 => ValRef::Bool(false),
                1 => ValRef::Bool(true),
                2 => ValRef::Null,
                _ => unreachable!("Invalid symbol value"),
            },
            Some(CellTag::Tag2) => unsafe {
                let slice = (&*(&self.0 as *const f64 as *const [u8; 8])).get_unchecked(0..6);
                let len = slice.iter().position(|&b| b == 0).unwrap_or(6);
                ValRef::String(std::str::from_utf8_unchecked(&slice[0..len]))
            },
            Some(CellTag::Tag3) => {
                let ptr = unwrap_cell_rawptr(self.0).unwrap() as *mut ();
                unsafe {
                    let (data, len) = slim_box_parts_for_slice(NonNull::new(ptr as *mut i32));
                    ValRef::String(std::str::from_utf8_unchecked(std::slice::from_raw_parts(
                        data, len,
                    )))
                }
            }
            Some(CellTag::Tag4) => {
                let ptr = unwrap_cell_rawptr(self.0).unwrap() as *mut ();
                unsafe {
                    let (data, len) = slim_box_parts_for_slice(NonNull::new(ptr as *mut i32));
                    ValRef::Array(std::slice::from_raw_parts(data, len))
                }
            }
            Some(CellTag::Tag5) => {
                let ptr = unwrap_cell_rawptr(self.0).unwrap() as *mut ();
                unsafe {
                    let (data, len) = slim_box_parts_for_slice(NonNull::new(ptr as *mut i32));
                    ValRef::Object(MapRef(std::slice::from_raw_parts(data, len)))
                }
            }
            Some(_) => unreachable!("Invalid tag"),
            None => ValRef::Number(NotNan::new(self.0).unwrap()),
        }
    }
}

impl TryFrom<ValE> for KeyE {
    type Error = ValKeyError;

    #[inline]
    fn try_from(value: ValE) -> Result<Self, Self::Error> {
        match value {
            ValE::Number(n) => Ok(ValE::string(n.to_string()).try_into().unwrap()),
            ValE::ShortString(s) => Ok(KeyE::ShortString(s)),
            ValE::LongString(s) => Ok(KeyE::LongString(s)),
            _ => Err(ValKeyError::InvalidKey),
        }
    }
}

impl TryFrom<Val> for Key {
    type Error = ValKeyError;

    #[inline]
    fn try_from(value: Val) -> Result<Self, Self::Error> {
        let key: KeyE = Into::<ValE>::into(value).try_into()?;
        Ok(key.into())
    }
}

impl From<KeyE> for ValE {
    #[inline]
    fn from(key: KeyE) -> Self {
        match key {
            KeyE::ShortString(s) => ValE::ShortString(s),
            KeyE::LongString(s) => ValE::LongString(s),
        }
    }
}

impl From<Key> for Val {
    #[inline]
    fn from(key: Key) -> Self {
        key.0
    }
}

impl From<Key> for KeyE {
    #[inline]
    fn from(key: Key) -> Self {
        let c_value_e: ValE = key.0.into();
        c_value_e.try_into().unwrap()
    }
}

impl From<KeyE> for Key {
    #[inline]
    fn from(key: KeyE) -> Self {
        let c_value_e: ValE = key.into();
        Key(c_value_e.into())
    }
}