pub mod borrowed;
pub(crate) mod generator;
pub mod owned;
pub mod tape;
pub use self::borrowed::{to_value as to_borrowed_value, Value as BorrowedValue};
pub use self::owned::{to_value as to_owned_value, Value as OwnedValue};
use crate::{Deserializer, Result};
use halfbrown::HashMap;
use std::borrow::Borrow;
use std::convert::TryInto;
use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use tape::{Node, StaticNode};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AccessError {
NotAnObject,
NotAnArray,
}
#[cfg_attr(tarpaulin, skip)]
impl fmt::Display for AccessError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotAnArray => write!(f, "The value is not an array"),
Self::NotAnObject => write!(f, "The value is not an object"),
}
}
}
impl std::error::Error for AccessError {}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ValueType {
Null,
Bool,
I64,
#[cfg(feature = "128bit")]
I128,
U64,
#[cfg(feature = "128bit")]
U128,
F64,
String,
Array,
Object,
}
use std::ops::{Index, IndexMut};
pub trait ValueBuilder:
Default
+ From<StaticNode>
+ From<i8>
+ From<i16>
+ From<i32>
+ From<i64>
+ From<u8>
+ From<u16>
+ From<u32>
+ From<u64>
+ From<f32>
+ From<f64>
+ From<String>
+ From<bool>
+ From<()>
{
fn array_with_capacity(capacity: usize) -> Self;
fn object_with_capacity(capacity: usize) -> Self;
#[must_use]
fn array() -> Self {
Self::array_with_capacity(0)
}
#[must_use]
fn object() -> Self {
Self::object_with_capacity(0)
}
fn null() -> Self;
}
pub trait MutableValue: IndexMut<usize> + Value + Sized {
type Key;
#[inline]
fn insert<K, V>(&mut self, k: K, v: V) -> std::result::Result<Option<Self>, AccessError>
where
K: Into<<Self as MutableValue>::Key>,
V: Into<Self>,
<Self as MutableValue>::Key: Hash + Eq,
{
self.as_object_mut()
.ok_or(AccessError::NotAnObject)
.map(|o| o.insert(k.into(), v.into()))
}
#[inline]
fn remove<Q: ?Sized>(&mut self, k: &Q) -> std::result::Result<Option<Self>, AccessError>
where
<Self as MutableValue>::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq,
{
self.as_object_mut()
.ok_or(AccessError::NotAnObject)
.map(|o| o.remove(k))
}
#[inline]
fn push<V>(&mut self, v: V) -> std::result::Result<(), AccessError>
where
V: Into<Self>,
{
self.as_array_mut()
.ok_or(AccessError::NotAnArray)
.map(|o| o.push(v.into()))
}
#[inline]
fn pop(&mut self) -> std::result::Result<Option<Self>, AccessError> {
self.as_array_mut()
.ok_or(AccessError::NotAnArray)
.map(Vec::pop)
}
fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut Self>
where
<Self as MutableValue>::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq,
{
self.as_object_mut().and_then(|m| m.get_mut(&k))
}
#[inline]
fn get_idx_mut(&mut self, i: usize) -> Option<&mut Self> {
self.as_array_mut().and_then(|a| a.get_mut(i))
}
fn as_array_mut(&mut self) -> Option<&mut Vec<Self>>;
fn as_object_mut(&mut self) -> Option<&mut HashMap<<Self as MutableValue>::Key, Self>>;
}
pub trait Value:
Sized
+ Index<usize>
+ PartialEq<i8>
+ PartialEq<i16>
+ PartialEq<i32>
+ PartialEq<i64>
+ PartialEq<i128>
+ PartialEq<u8>
+ PartialEq<u16>
+ PartialEq<u32>
+ PartialEq<u64>
+ PartialEq<u128>
+ PartialEq<f32>
+ PartialEq<f64>
+ PartialEq<String>
+ PartialEq<bool>
+ PartialEq<()>
{
type Key;
#[inline]
#[must_use]
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&Self>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq,
{
self.as_object().and_then(|a| a.get(k))
}
#[inline]
#[must_use]
fn get_idx(&self, i: usize) -> Option<&Self> {
self.as_array().and_then(|a| a.get(i))
}
#[must_use]
fn value_type(&self) -> ValueType;
#[must_use]
fn is_null(&self) -> bool;
#[must_use]
fn as_bool(&self) -> Option<bool>;
#[inline]
#[must_use]
fn is_bool(&self) -> bool {
self.as_bool().is_some()
}
#[inline]
#[must_use]
fn as_i128(&self) -> Option<i128> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_i128(&self) -> bool {
self.as_i128().is_some()
}
#[must_use]
fn as_i64(&self) -> Option<i64>;
#[inline]
#[must_use]
fn is_i64(&self) -> bool {
self.as_i64().is_some()
}
#[inline]
#[must_use]
fn as_i32(&self) -> Option<i32> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_i32(&self) -> bool {
self.as_i32().is_some()
}
#[inline]
#[must_use]
fn as_i16(&self) -> Option<i16> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_i16(&self) -> bool {
self.as_i16().is_some()
}
#[inline]
#[must_use]
fn as_i8(&self) -> Option<i8> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_i8(&self) -> bool {
self.as_i8().is_some()
}
#[inline]
#[must_use]
fn as_u128(&self) -> Option<u128> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_u128(&self) -> bool {
self.as_u128().is_some()
}
#[must_use]
fn as_u64(&self) -> Option<u64>;
#[inline]
#[must_use]
fn is_u64(&self) -> bool {
self.as_u64().is_some()
}
#[inline]
#[must_use]
fn as_usize(&self) -> Option<usize> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_usize(&self) -> bool {
self.as_usize().is_some()
}
#[inline]
#[must_use]
fn as_u32(&self) -> Option<u32> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_u32(&self) -> bool {
self.as_u32().is_some()
}
#[inline]
#[must_use]
fn as_u16(&self) -> Option<u16> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_u16(&self) -> bool {
self.as_u16().is_some()
}
#[inline]
#[must_use]
fn as_u8(&self) -> Option<u8> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn is_u8(&self) -> bool {
self.as_u8().is_some()
}
#[must_use]
fn as_f64(&self) -> Option<f64>;
#[inline]
#[must_use]
fn is_f64(&self) -> bool {
self.as_f64().is_some()
}
#[must_use]
fn cast_f64(&self) -> Option<f64>;
#[inline]
#[must_use]
fn is_f64_castable(&self) -> bool {
self.cast_f64().is_some()
}
#[allow(clippy::cast_possible_truncation)]
#[inline]
#[must_use]
fn as_f32(&self) -> Option<f32> {
self.as_f64().and_then(|u| {
if u <= f64::from(std::f32::MAX) && u >= f64::from(std::f32::MIN) {
Some(u as f32)
} else {
None
}
})
}
#[inline]
#[must_use]
fn is_f32(&self) -> bool {
self.as_f32().is_some()
}
#[must_use]
fn as_str(&self) -> Option<&str>;
#[inline]
#[must_use]
fn is_str(&self) -> bool {
self.as_str().is_some()
}
#[must_use]
fn as_array(&self) -> Option<&Vec<Self>>;
#[inline]
#[must_use]
fn is_array(&self) -> bool {
self.as_array().is_some()
}
#[must_use]
fn as_object(&self) -> Option<&HashMap<Self::Key, Self>>;
#[inline]
#[must_use]
fn is_object(&self) -> bool {
self.as_object().is_some()
}
}
pub fn deserialize<'de, Value, Key>(s: &'de mut [u8]) -> Result<Value>
where
Value: ValueBuilder + From<&'de str> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
match Deserializer::from_slice(s) {
Ok(de) => Ok(ValueDeserializer::from_deserializer(de).parse()),
Err(e) => Err(e),
}
}
struct ValueDeserializer<'de, Value, Key>
where
Value: ValueBuilder + From<&'de str> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
de: Deserializer<'de>,
_marker: PhantomData<(Value, Key)>,
}
impl<'de, Value, Key> ValueDeserializer<'de, Value, Key>
where
Value: ValueBuilder + From<&'de str> + From<Vec<Value>> + From<HashMap<Key, Value>> + 'de,
Key: Hash + Eq + From<&'de str>,
{
pub fn from_deserializer(de: Deserializer<'de>) -> Self {
Self {
de,
_marker: PhantomData::default(),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
pub fn parse(&mut self) -> Value {
match self.de.next_() {
Node::Static(s) => Value::from(s),
Node::String(s) => Value::from(s),
Node::Array(len, _) => self.parse_array(len),
Node::Object(len, _) => self.parse_map(len),
}
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_array(&mut self, len: usize) -> Value {
let mut res = Vec::with_capacity(len);
unsafe {
res.set_len(len);
for i in 0..len {
std::ptr::write(res.get_unchecked_mut(i), self.parse());
}
}
Value::from(res)
}
#[cfg_attr(not(feature = "no-inline"), inline(always))]
fn parse_map(&mut self, len: usize) -> Value {
let mut res: HashMap<Key, Value> = HashMap::with_capacity(len);
for _ in 0..len {
if let Node::String(key) = self.de.next_() {
res.insert_nocheck(key.into(), self.parse());
} else {
unreachable!()
}
}
Value::from(res)
}
}