use serde_json::{Map, Number, Value};
pub trait Instance<'a>: Copy {
type Array: ArrayView<'a, Item = Self>;
type Object: ObjectView<'a, Item = Self>;
fn view(self) -> View<'a, Self>;
#[inline]
fn kind(self) -> Kind {
match self.view() {
View::Null => Kind::Null,
View::Bool(_) => Kind::Bool,
View::Number(_) => Kind::Number,
View::String(_) => Kind::String,
View::Array(_) => Kind::Array,
View::Object(_) => Kind::Object,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(u8)]
pub enum Kind {
Null = 1,
Bool = 2,
Object = 4,
Array = 8,
Number = 16,
String = 32,
}
pub enum View<'a, I: Instance<'a>> {
Null,
Bool(bool),
Number(Number),
String(&'a str),
Array(I::Array),
Object(I::Object),
}
pub trait ArrayView<'a>: Copy {
type Item: Instance<'a>;
fn len(self) -> usize;
fn is_empty(self) -> bool {
self.len() == 0
}
fn get(self, index: usize) -> Self::Item;
fn iter(self) -> impl Iterator<Item = Self::Item>;
fn tail(self, start: usize) -> impl Iterator<Item = Self::Item> {
self.iter().skip(start)
}
}
pub trait ObjectView<'a>: Copy {
type Item: Instance<'a>;
fn len(self) -> usize;
fn is_empty(self) -> bool {
self.len() == 0
}
fn get(self, name: &str) -> Option<Self::Item>;
fn contains_key(self, name: &str) -> bool {
self.get(name).is_some()
}
fn iter(self) -> impl Iterator<Item = (&'a str, Self::Item)>;
fn values(self) -> impl Iterator<Item = Self::Item> {
self.iter().map(|(_, v)| v)
}
}
impl<'a> Instance<'a> for &'a Value {
type Array = &'a [Value];
type Object = &'a Map<String, Value>;
#[inline(always)]
fn view(self) -> View<'a, Self> {
match self {
Value::Null => View::Null,
Value::Bool(b) => View::Bool(*b),
Value::Number(n) => View::Number(n.clone()),
Value::String(s) => View::String(s),
Value::Array(a) => View::Array(a.as_slice()),
Value::Object(o) => View::Object(o),
}
}
#[inline(always)]
fn kind(self) -> Kind {
match self {
Value::Null => Kind::Null,
Value::Bool(_) => Kind::Bool,
Value::Number(_) => Kind::Number,
Value::String(_) => Kind::String,
Value::Array(_) => Kind::Array,
Value::Object(_) => Kind::Object,
}
}
}
impl<'a> ArrayView<'a> for &'a [Value] {
type Item = &'a Value;
#[inline(always)]
fn len(self) -> usize {
<[Value]>::len(self)
}
#[inline(always)]
fn get(self, index: usize) -> &'a Value {
&self[index]
}
#[inline(always)]
fn iter(self) -> impl Iterator<Item = &'a Value> {
<[Value]>::iter(self)
}
#[inline(always)]
fn tail(self, start: usize) -> impl Iterator<Item = &'a Value> {
self.get(start..).unwrap_or_default().iter()
}
}
const LINEAR_KEYS: usize = 32;
impl<'a> ObjectView<'a> for &'a Map<String, Value> {
type Item = &'a Value;
#[inline(always)]
fn len(self) -> usize {
Map::len(self)
}
#[inline]
fn get(self, name: &str) -> Option<&'a Value> {
if Map::len(self) <= LINEAR_KEYS {
Map::iter(self).find(|(k, _)| str_eq(k, name)).map(|(_, v)| v)
} else {
Map::get(self, name)
}
}
#[inline]
fn contains_key(self, name: &str) -> bool {
if Map::len(self) <= LINEAR_KEYS { self.keys().any(|k| str_eq(k, name)) } else { Map::contains_key(self, name) }
}
#[inline(always)]
fn iter(self) -> impl Iterator<Item = (&'a str, &'a Value)> {
Map::iter(self).map(|(k, v)| (k.as_str(), v))
}
#[inline(always)]
fn values(self) -> impl Iterator<Item = &'a Value> {
Map::values(self)
}
}
#[inline(always)]
pub(crate) fn str_eq(a: &str, b: &str) -> bool {
let (a, b) = (a.as_bytes(), b.as_bytes());
if a.len() != b.len() {
return false;
}
let n = a.len();
if n <= 8 {
if n >= 4 {
let word = |s: &[u8], i: usize| u32::from_le_bytes(s[i..i + 4].try_into().unwrap());
return word(a, 0) == word(b, 0) && word(a, n - 4) == word(b, n - 4);
}
return a == b;
}
let word = |s: &[u8], i: usize| u64::from_le_bytes(s[i..i + 8].try_into().unwrap());
let mut i = 0;
while i + 8 < n {
if word(a, i) != word(b, i) {
return false;
}
i += 8;
}
word(a, n - 8) == word(b, n - 8)
}
const _: () = {
use crate::node::type_mask;
assert!(Kind::Null as u8 == type_mask::NULL);
assert!(Kind::Bool as u8 == type_mask::BOOLEAN);
assert!(Kind::Object as u8 == type_mask::OBJECT);
assert!(Kind::Array as u8 == type_mask::ARRAY);
assert!(Kind::Number as u8 == type_mask::NUMBER);
assert!(Kind::String as u8 == type_mask::STRING);
};