litl-val 0.2.0

A memory efficient representation of JSON values
Documentation
use std::{
    fmt::Debug,
    hash::{Hash, Hasher},
    ops::Index,
};

use deepsize::DeepSizeOf;
use ordered_float::NotNan;

use super::{key_e::KeyE, slim_boxed_slice::SlimBoxedSlice, val_ref::ValRef, Map, ValE};

pub struct Val(pub(crate) f64);

impl Val {
    #[inline]
    pub fn str(s: &str) -> Val {
        ValE::str(s).into()
    }

    #[inline]
    pub fn string(s: String) -> Val {
        ValE::string(s).into()
    }

    #[inline]
    pub fn number(n: f64) -> Val {
        ValE::Number(NotNan::new(n).unwrap()).into()
    }

    #[inline]
    pub fn bool(b: bool) -> Val {
        ValE::Bool(b).into()
    }

    #[inline]
    pub fn null() -> Val {
        ValE::Null.into()
    }

    #[inline]
    pub fn array<V: Into<Val>, I: IntoIterator<Item = V>>(items: I) -> Val {
        ValE::Array(SlimBoxedSlice::from_vec(
            items.into_iter().map(Into::into).collect::<Vec<_>>(),
        ))
        .into()
    }

    #[inline]
    pub fn object<K: ToString, V: Into<Val>, I: IntoIterator<Item = (K, V)>>(items: I) -> Val {
        ValE::Object(Map::new(
            items
                .into_iter()
                .map(|(k, v)| (KeyE::string(k.to_string()).into(), v.into()))
                .collect::<Vec<_>>(),
        ))
        .into()
    }

    #[inline]
    pub fn as_str(&self) -> Option<&str> {
        self.direct_ref().as_str()
    }

    #[inline]
    pub fn is_null(&self) -> bool {
        matches!(self.direct_ref(), ValRef::Null)
    }

    #[inline]
    pub fn get<S: AsRef<str>>(&self, key: S) -> Option<&Val> {
        self.direct_ref().get(key)
    }
}

impl PartialEq for Val {
    fn eq(&self, other: &Self) -> bool {
        self.direct_ref() == other.direct_ref()
    }
}

impl Eq for Val {}

impl PartialOrd for Val {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.direct_ref().partial_cmp(&other.direct_ref())
    }
}

impl Ord for Val {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.direct_ref().cmp(&other.direct_ref())
    }
}

impl Debug for Val {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.direct_ref().fmt(f)
    }
}

impl Clone for Val {
    #[inline]
    fn clone(&self) -> Self {
        match self.direct_ref() {
            ValRef::Null => ValE::Null,
            ValRef::Bool(b) => ValE::Bool(b),
            ValRef::Number(n) => ValE::Number(n),
            ValRef::String(s) => ValE::str(s),
            ValRef::Array(a) => ValE::Array(SlimBoxedSlice::from_vec(a.to_vec())),
            ValRef::Object(o) => ValE::Object(Map::clone_from_ref(&o)),
        }
        .into()
    }
}

impl Hash for Val {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.direct_ref().hash(state)
    }
}

impl Index<usize> for Val {
    type Output = Val;

    #[inline]
    fn index(&self, index: usize) -> &Self::Output {
        match self.direct_ref() {
            ValRef::Array(a) => &a[index],
            _ => panic!("Tried to index into Val that is not an array"),
        }
    }
}

impl DeepSizeOf for Val {
    fn deep_size_of_children(&self, context: &mut deepsize::Context) -> usize {
        let unsafe_clone = Val(self.0).into();
        let size = match &unsafe_clone {
            ValE::Bool(_) => 8,
            ValE::Null => 8,
            ValE::Number(_) => 8,
            ValE::ShortString(_) => 8,
            ValE::LongString(s) => s.deep_size_of_children(context),
            ValE::Array(a) => a.deep_size_of_children(context),
            ValE::Object(o) => o.deep_size_of_children(context),
        };
        std::mem::forget(unsafe_clone);
        size
    }
}