use std::fmt;
use std::hash::{Hash, Hasher};
use super::*;
use bytes::Buf;
use serde_json::Number;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ValueRef<'a> {
Null,
String(StringRef<'a>),
Number(NumberRef<'a>),
Bool(bool),
Array(ArrayRef<'a>),
Object(ObjectRef<'a>),
}
impl<'a> ValueRef<'a> {
pub fn from_bytes(bytes: &[u8]) -> ValueRef<'_> {
let entry = Entry::from(&bytes[bytes.len() - 4..]);
ValueRef::from_slice(bytes, entry)
}
pub fn is_null(self) -> bool {
matches!(self, Self::Null)
}
pub fn is_boolean(self) -> bool {
matches!(self, Self::Bool(_))
}
pub fn is_number(self) -> bool {
matches!(self, Self::Number(_))
}
pub fn is_u64(self) -> bool {
matches!(self, Self::Number(n) if n.is_u64())
}
pub fn is_i64(self) -> bool {
matches!(self, Self::Number(n) if n.is_i64())
}
pub fn is_f64(self) -> bool {
matches!(self, Self::Number(n) if n.is_f64())
}
pub fn is_string(self) -> bool {
matches!(self, Self::String(_))
}
pub fn is_array(self) -> bool {
matches!(self, Self::Array(_))
}
pub fn is_object(self) -> bool {
matches!(self, Self::Object(_))
}
pub fn as_null(self) -> Option<()> {
match self {
Self::Null => Some(()),
_ => None,
}
}
pub fn as_bool(self) -> Option<bool> {
match self {
Self::Bool(b) => Some(b),
_ => None,
}
}
pub fn as_number(self) -> Option<NumberRef<'a>> {
match self {
Self::Number(n) => Some(n),
_ => None,
}
}
pub fn as_u64(self) -> Option<u64> {
match self {
Self::Number(n) => n.as_u64(),
_ => None,
}
}
pub fn as_i64(self) -> Option<i64> {
match self {
Self::Number(n) => n.as_i64(),
_ => None,
}
}
pub fn as_f64(self) -> Option<f64> {
match self {
Self::Number(n) => n.as_f64(),
_ => None,
}
}
pub fn as_str(self) -> Option<&'a str> {
match self {
Self::String(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_array(self) -> Option<ArrayRef<'a>> {
match self {
Self::Array(a) => Some(a),
_ => None,
}
}
pub fn as_object(self) -> Option<ObjectRef<'a>> {
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
pub fn to_owned(self) -> Value {
self.into()
}
pub(crate) fn from_slice(data: &'a [u8], entry: Entry) -> Self {
match entry.tag() {
Entry::NULL_TAG => Self::Null,
Entry::FALSE_TAG => Self::Bool(false),
Entry::TRUE_TAG => Self::Bool(true),
Entry::NUMBER_TAG => {
let ptr = entry.offset();
let data = &data[ptr..ptr + 1 + number_size(data[ptr])];
Self::Number(NumberRef { data })
}
Entry::STRING_TAG => {
let ptr = entry.offset();
let len = (&data[ptr..]).get_u32_ne() as usize;
Self::String(StringRef::from_bytes(&data[ptr..ptr + 4 + len]))
}
Entry::ARRAY_TAG => {
let ptr = entry.offset();
Self::Array(ArrayRef::from_slice(data, ptr))
}
Entry::OBJECT_TAG => {
let ptr = entry.offset();
Self::Object(ObjectRef::from_slice(data, ptr))
}
_ => panic!("invalid entry"),
}
}
pub(crate) fn as_slice(self) -> &'a [u8] {
match self {
Self::Null => &[],
Self::Bool(_) => &[],
Self::Number(n) => n.data,
Self::String(s) => s.as_slice(),
Self::Array(a) => a.as_slice(),
Self::Object(o) => o.as_slice(),
}
}
pub(crate) fn make_entry(self, offset: usize) -> Entry {
match self {
Self::Null => Entry::null(),
Self::Bool(b) => Entry::bool(b),
Self::Number(_) => Entry::number(offset),
Self::String(_) => Entry::string(offset),
Self::Array(a) => Entry::array(offset + a.as_slice().len()),
Self::Object(o) => Entry::object(offset + o.as_slice().len()),
}
}
pub fn to_raw_parts(self) -> (Entry, &'a [u8]) {
(self.make_entry(0), self.as_slice())
}
pub fn from_raw_parts(entry: Entry, data: &'a [u8]) -> Self {
Self::from_slice(data, entry)
}
pub fn capacity(self) -> usize {
self.as_slice().len()
}
pub fn get(self, index: impl Index) -> Option<ValueRef<'a>> {
index.index_into(self)
}
pub fn pointer(self, pointer: &str) -> Option<Self> {
if pointer.is_empty() {
return Some(self);
}
if !pointer.starts_with('/') {
return None;
}
fn parse_index(s: &str) -> Option<usize> {
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
}
pointer
.split('/')
.skip(1)
.map(|x| x.replace("~1", "/").replace("~0", "~"))
.try_fold(self, |target, token| match target {
Self::Object(map) => map.get(&token),
Self::Array(list) => parse_index(&token).and_then(|x| list.get(x)),
_ => None,
})
}
}
impl fmt::Debug for ValueRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Null => f.write_str("null"),
Self::Bool(b) => b.fmt(f),
Self::Number(n) => n.fmt(f),
Self::String(s) => s.as_str().fmt(f),
Self::Array(a) => a.fmt(f),
Self::Object(o) => o.fmt(f),
}
}
}
impl fmt::Display for ValueRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
serialize_in_json(self, f)
}
}
impl From<ValueRef<'_>> for serde_json::Value {
fn from(value: ValueRef<'_>) -> Self {
match value {
ValueRef::Null => Self::Null,
ValueRef::Bool(b) => Self::Bool(b),
ValueRef::Number(n) => Self::Number(n.to_number()),
ValueRef::String(s) => Self::String(s.as_str().to_owned()),
ValueRef::Array(a) => Self::Array(a.iter().map(Self::from).collect()),
ValueRef::Object(o) => Self::Object(
o.iter()
.map(|(k, v)| (k.to_owned(), Self::from(v)))
.collect(),
),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct StringRef<'a> {
data: &'a [u8],
}
impl<'a> StringRef<'a> {
pub(crate) fn from_bytes(data: &'a [u8]) -> Self {
Self { data }
}
pub fn as_str(&self) -> &'a str {
let len = (&self.data[..4]).get_u32_ne() as usize;
unsafe { std::str::from_utf8_unchecked(&self.data[4..4 + len]) }
}
pub(crate) fn as_slice(&self) -> &'a [u8] {
self.data
}
}
#[derive(Clone, Copy)]
pub struct NumberRef<'a> {
data: &'a [u8],
}
impl NumberRef<'_> {
pub fn to_number(self) -> Number {
let mut data = self.data;
match data.get_u8() {
NUMBER_ZERO => Number::from(0),
NUMBER_I8 => Number::from(data.get_i8()),
NUMBER_I16 => Number::from(data.get_i16_ne()),
NUMBER_I32 => Number::from(data.get_i32_ne()),
NUMBER_I64 => Number::from(data.get_i64_ne()),
NUMBER_U64 => Number::from(data.get_u64_ne()),
NUMBER_F64 => Number::from_f64(data.get_f64_ne()).unwrap(),
t => panic!("invalid number tag: {t}"),
}
}
pub fn as_u64(self) -> Option<u64> {
self.to_number().as_u64()
}
pub fn as_i64(self) -> Option<i64> {
self.to_number().as_i64()
}
pub fn as_f64(self) -> Option<f64> {
self.to_number().as_f64()
}
pub(crate) fn as_f32(&self) -> Option<f32> {
let mut data = self.data;
Some(match data.get_u8() {
NUMBER_ZERO => 0 as f32,
NUMBER_I8 => data.get_i8() as f32,
NUMBER_I16 => data.get_i16_ne() as f32,
NUMBER_I32 => data.get_i32_ne() as f32,
NUMBER_I64 => data.get_i64_ne() as f32,
NUMBER_U64 => data.get_u64_ne() as f32,
NUMBER_F64 => data.get_f64_ne() as f32,
t => panic!("invalid number tag: {t}"),
})
}
pub fn is_u64(self) -> bool {
self.to_number().is_u64()
}
pub fn is_i64(self) -> bool {
self.to_number().is_i64()
}
pub fn is_f64(self) -> bool {
self.to_number().is_f64()
}
}
impl fmt::Debug for NumberRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_number().fmt(f)
}
}
impl fmt::Display for NumberRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.to_number().fmt(f)
}
}
impl PartialEq for NumberRef<'_> {
fn eq(&self, other: &Self) -> bool {
let a = self.to_number();
let b = other.to_number();
match (a.as_u64(), b.as_u64()) {
(Some(a), Some(b)) => return a == b, (Some(_), None) if b.is_i64() => return false, (None, Some(_)) if a.is_i64() => return false, (None, None) => {
if let (Some(a), Some(b)) = (a.as_i64(), b.as_i64()) {
return a == b; }
}
_ => {}
}
let a = a.as_f64().unwrap();
let b = b.as_f64().unwrap();
a == b
}
}
impl Eq for NumberRef<'_> {}
impl PartialOrd for NumberRef<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for NumberRef<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
let a = self.to_number();
let b = other.to_number();
match (a.as_u64(), b.as_u64()) {
(Some(a), Some(b)) => return a.cmp(&b), (Some(_), None) if b.is_i64() => return std::cmp::Ordering::Greater, (None, Some(_)) if a.is_i64() => return std::cmp::Ordering::Less, (None, None) => {
if let (Some(a), Some(b)) = (a.as_i64(), b.as_i64()) {
return a.cmp(&b); }
}
_ => {}
}
let a = a.as_f64().unwrap();
let b = b.as_f64().unwrap();
a.partial_cmp(&b).expect("NaN or Inf in JSON number")
}
}
impl Hash for NumberRef<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.to_number().hash(state);
}
}
#[derive(Clone, Copy)]
pub struct ArrayRef<'a> {
data: &'a [u8],
}
impl<'a> ArrayRef<'a> {
pub fn get(self, index: usize) -> Option<ValueRef<'a>> {
let len = self.len();
if index >= len {
return None;
}
let offset = self.data.len() - 8 - 4 * (len - index);
let entry = Entry::from(&self.data[offset..offset + 4]);
Some(ValueRef::from_slice(self.data, entry))
}
pub fn len(self) -> usize {
(&self.data[self.data.len() - 8..]).get_u32_ne() as usize
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
pub fn iter(self) -> impl ExactSizeIterator<Item = ValueRef<'a>> {
let len = self.len();
let offset = self.data.len() - 8 - 4 * len;
self.data[offset..offset + 4 * len]
.chunks_exact(4)
.map(|slice| ValueRef::from_slice(self.data, Entry::from(slice)))
}
pub(crate) fn as_slice(self) -> &'a [u8] {
self.data
}
fn from_slice(data: &'a [u8], end: usize) -> Self {
let size = (&data[end - 4..end]).get_u32_ne() as usize;
Self {
data: &data[end - size..end],
}
}
}
impl fmt::Debug for ArrayRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl fmt::Display for ArrayRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
serialize_in_json(self, f)
}
}
impl PartialEq for ArrayRef<'_> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().eq(other.iter())
}
}
impl Eq for ArrayRef<'_> {}
impl PartialOrd for ArrayRef<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ArrayRef<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.len().cmp(&other.len()) {
std::cmp::Ordering::Equal => self.iter().cmp(other.iter()),
ord => ord,
}
}
}
impl Hash for ArrayRef<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
for v in self.iter() {
v.hash(state);
}
}
}
#[derive(Clone, Copy)]
pub struct ObjectRef<'a> {
data: &'a [u8],
}
impl<'a> ObjectRef<'a> {
pub fn get(self, key: &str) -> Option<ValueRef<'a>> {
let entries = self.entries();
let idx = entries
.binary_search_by_key(&key, |&(kentry, _)| {
ValueRef::from_slice(self.data, kentry)
.as_str()
.expect("key must be string")
})
.ok()?;
let (_, ventry) = entries[idx];
Some(ValueRef::from_slice(self.data, ventry))
}
pub fn contains_key(self, key: &str) -> bool {
let entries = self.entries();
entries
.binary_search_by_key(&key, |&(kentry, _)| {
ValueRef::from_slice(self.data, kentry)
.as_str()
.expect("key must be string")
})
.is_ok()
}
pub fn len(self) -> usize {
(&self.data[self.data.len() - 8..]).get_u32_ne() as usize
}
pub fn is_empty(self) -> bool {
self.len() == 0
}
pub fn iter(self) -> impl ExactSizeIterator<Item = (&'a str, ValueRef<'a>)> {
self.entries().iter().map(move |&(kentry, ventry)| {
let k = ValueRef::from_slice(self.data, kentry);
let v = ValueRef::from_slice(self.data, ventry);
(k.as_str().expect("key must be string"), v)
})
}
pub fn keys(self) -> impl ExactSizeIterator<Item = &'a str> {
self.iter().map(|(k, _)| k)
}
pub fn values(self) -> impl ExactSizeIterator<Item = ValueRef<'a>> {
self.iter().map(|(_, v)| v)
}
pub(crate) fn as_slice(self) -> &'a [u8] {
self.data
}
fn from_slice(data: &'a [u8], end: usize) -> Self {
let size = (&data[end - 4..end]).get_u32_ne() as usize;
Self {
data: &data[end - size..end],
}
}
fn entries(self) -> &'a [(Entry, Entry)] {
let len = self.len();
let base = self.data.len() - 8 - 8 * len;
let slice = &self.data[base..base + 8 * len];
unsafe { std::slice::from_raw_parts(slice.as_ptr() as _, len) }
}
}
impl fmt::Debug for ObjectRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
impl fmt::Display for ObjectRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
serialize_in_json(self, f)
}
}
impl PartialEq for ObjectRef<'_> {
fn eq(&self, other: &Self) -> bool {
if self.len() != other.len() {
return false;
}
self.iter().eq(other.iter())
}
}
impl Eq for ObjectRef<'_> {}
impl PartialOrd for ObjectRef<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ObjectRef<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
match self.len().cmp(&other.len()) {
std::cmp::Ordering::Equal => self.iter().cmp(other.iter()),
ord => ord,
}
}
}
impl Hash for ObjectRef<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
for (k, v) in self.iter() {
k.hash(state);
v.hash(state);
}
}
}
fn serialize_in_json(value: &impl ::serde::Serialize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use std::io;
struct WriterFormatter<'a, 'b: 'a> {
inner: &'a mut fmt::Formatter<'b>,
}
impl<'a, 'b> io::Write for WriterFormatter<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let s = unsafe { std::str::from_utf8_unchecked(buf) };
self.inner.write_str(s).map_err(io_error)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
fn io_error(_: fmt::Error) -> io::Error {
io::Error::other("fmt error")
}
let alternate = f.alternate();
let mut wr = WriterFormatter { inner: f };
if alternate {
value
.serialize(&mut serde_json::Serializer::pretty(&mut wr))
.map_err(|_| fmt::Error)
} else {
value
.serialize(&mut serde_json::Serializer::new(&mut wr))
.map_err(|_| fmt::Error)
}
}
pub trait Index: private::Sealed {
#[doc(hidden)]
fn index_into<'v>(&self, v: ValueRef<'v>) -> Option<ValueRef<'v>>;
}
impl Index for usize {
fn index_into<'v>(&self, v: ValueRef<'v>) -> Option<ValueRef<'v>> {
match v {
ValueRef::Array(a) => a.get(*self),
_ => None,
}
}
}
impl Index for str {
fn index_into<'v>(&self, v: ValueRef<'v>) -> Option<ValueRef<'v>> {
match v {
ValueRef::Object(o) => o.get(self),
_ => None,
}
}
}
impl Index for String {
fn index_into<'v>(&self, v: ValueRef<'v>) -> Option<ValueRef<'v>> {
match v {
ValueRef::Object(o) => o.get(self),
_ => None,
}
}
}
impl<T> Index for &T
where
T: ?Sized + Index,
{
fn index_into<'v>(&self, v: ValueRef<'v>) -> Option<ValueRef<'v>> {
(**self).index_into(v)
}
}
mod private {
pub trait Sealed {}
impl Sealed for usize {}
impl Sealed for str {}
impl Sealed for String {}
impl<T> Sealed for &T where T: ?Sized + Sealed {}
}