#![cfg_attr(target_arch = "aarch64", feature(stdsimd,))]
#![warn(unused_extern_crates)]
#![deny(
clippy::all,
clippy::unwrap_used,
clippy::unnecessary_unwrap,
clippy::pedantic
)]
#![forbid(warnings)]
#![allow(clippy::module_name_repetitions, clippy::inline_always)]
#![deny(missing_docs)]
use std::borrow::{Borrow, Cow};
use std::convert::TryInto;
use std::fmt;
use std::hash::Hash;
use std::io::{self, Write};
use std::ops::{Index, IndexMut};
mod array;
pub mod generator;
mod node;
mod object;
mod option;
pub mod prelude;
pub use array::Array;
pub use node::StaticNode;
pub use object::Object;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum AccessError {
NotAnObject,
NotAnArray,
}
#[cfg(not(tarpaulin_include))]
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,
#[cfg(feature = "custom-types")]
Custom(&'static str),
}
pub trait Writable {
#[must_use]
fn encode(&self) -> String;
#[must_use]
fn encode_pp(&self) -> String;
fn write<'writer, W>(&self, w: &mut W) -> io::Result<()>
where
W: 'writer + Write;
fn write_pp<'writer, W>(&self, w: &mut W) -> io::Result<()>
where
W: 'writer + Write;
}
pub trait Builder<'input>:
Default
+ From<StaticNode>
+ From<i8>
+ From<i16>
+ From<i32>
+ From<i64>
+ From<u8>
+ From<u16>
+ From<u32>
+ From<u64>
+ From<f32>
+ From<f64>
+ From<bool>
+ From<()>
+ From<String>
+ From<&'input str>
+ From<Cow<'input, str>>
{
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 ValueAccess: Sized {
type Target: ValueAccess;
type Key: Hash + Eq;
type Array: Array<Element = Self::Target>;
type Object: Object<Key = Self::Key, Element = Self::Target>;
#[inline]
#[must_use]
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&Self::Target>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.as_object().and_then(|a| a.get(k))
}
#[inline]
#[must_use]
fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.as_object().and_then(|a| a.get(k)).is_some()
}
#[inline]
#[must_use]
fn get_idx(&self, i: usize) -> Option<&Self::Target> {
self.as_array().and_then(|a| a.get(i))
}
#[inline]
#[must_use]
fn get_bool<Q: ?Sized>(&self, k: &Q) -> Option<bool>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_bool)
}
#[must_use]
fn as_bool(&self) -> Option<bool>;
#[inline]
#[must_use]
fn as_i128(&self) -> Option<i128> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_i128<Q: ?Sized>(&self, k: &Q) -> Option<i128>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_i128)
}
#[must_use]
fn as_i64(&self) -> Option<i64>;
#[inline]
#[must_use]
fn get_i64<Q: ?Sized>(&self, k: &Q) -> Option<i64>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_i64)
}
#[inline]
#[must_use]
fn as_i32(&self) -> Option<i32> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_i32<Q: ?Sized>(&self, k: &Q) -> Option<i32>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_i32)
}
#[inline]
#[must_use]
fn as_i16(&self) -> Option<i16> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_i16<Q: ?Sized>(&self, k: &Q) -> Option<i16>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_i16)
}
#[inline]
#[must_use]
fn as_i8(&self) -> Option<i8> {
self.as_i64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_i8<Q: ?Sized>(&self, k: &Q) -> Option<i8>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_i8)
}
#[inline]
#[must_use]
fn as_u128(&self) -> Option<u128> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_u128<Q: ?Sized>(&self, k: &Q) -> Option<u128>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_u128)
}
#[must_use]
fn as_u64(&self) -> Option<u64>;
#[inline]
#[must_use]
fn get_u64<Q: ?Sized>(&self, k: &Q) -> Option<u64>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_u64)
}
#[inline]
#[must_use]
fn as_usize(&self) -> Option<usize> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_usize<Q: ?Sized>(&self, k: &Q) -> Option<usize>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_usize)
}
#[inline]
#[must_use]
fn as_u32(&self) -> Option<u32> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_u32<Q: ?Sized>(&self, k: &Q) -> Option<u32>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_u32)
}
#[inline]
#[must_use]
fn as_u16(&self) -> Option<u16> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_u16<Q: ?Sized>(&self, k: &Q) -> Option<u16>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_u16)
}
#[inline]
#[must_use]
fn as_u8(&self) -> Option<u8> {
self.as_u64().and_then(|u| u.try_into().ok())
}
#[inline]
#[must_use]
fn get_u8<Q: ?Sized>(&self, k: &Q) -> Option<u8>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_u8)
}
#[must_use]
fn as_f64(&self) -> Option<f64>;
#[inline]
#[must_use]
fn get_f64<Q: ?Sized>(&self, k: &Q) -> Option<f64>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_f64)
}
#[must_use]
#[inline]
#[allow(clippy::cast_precision_loss, clippy::option_if_let_else)]
fn cast_f64(&self) -> Option<f64> {
if let Some(f) = self.as_f64() {
Some(f)
} else if let Some(u) = self.as_u128() {
Some(u as f64)
} else if let Some(i) = self.as_i128() {
Some(i as f64)
} else {
None
}
}
#[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 get_f32<Q: ?Sized>(&self, k: &Q) -> Option<f32>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_f32)
}
#[must_use]
fn as_str(&self) -> Option<&str>;
#[inline]
#[must_use]
fn as_char(&self) -> Option<char> {
self.as_str().and_then(|s| s.chars().next())
}
#[inline]
#[must_use]
fn get_str<Q: ?Sized>(&self, k: &Q) -> Option<&str>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_str)
}
#[must_use]
fn as_array(&self) -> Option<&Self::Array>;
#[inline]
#[must_use]
fn get_array<Q: ?Sized>(
&self,
k: &Q,
) -> Option<&<<Self as ValueAccess>::Target as ValueAccess>::Array>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_array)
}
#[must_use]
fn as_object(&self) -> Option<&Self::Object>;
#[inline]
#[must_use]
fn get_object<Q: ?Sized>(
&self,
k: &Q,
) -> Option<&<<Self as ValueAccess>::Target as ValueAccess>::Object>
where
Self::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.get(k).and_then(ValueAccess::as_object)
}
}
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<()>
+ ValueAccess
{
#[must_use]
fn value_type(&self) -> ValueType;
#[must_use]
fn is_null(&self) -> bool;
#[inline]
#[must_use]
fn is_float(&self) -> bool {
self.is_f64()
}
#[inline]
#[must_use]
fn is_integer(&self) -> bool {
self.is_i128() || self.is_u128()
}
#[inline]
#[must_use]
fn is_number(&self) -> bool {
self.is_float() || self.is_integer()
}
#[inline]
#[must_use]
fn is_bool(&self) -> bool {
self.as_bool().is_some()
}
#[inline]
#[must_use]
fn is_i128(&self) -> bool {
self.as_i128().is_some()
}
#[inline]
#[must_use]
fn is_i64(&self) -> bool {
self.as_i64().is_some()
}
#[inline]
#[must_use]
fn is_i32(&self) -> bool {
self.as_i32().is_some()
}
#[inline]
#[must_use]
fn is_i16(&self) -> bool {
self.as_i16().is_some()
}
#[inline]
#[must_use]
fn is_i8(&self) -> bool {
self.as_i8().is_some()
}
#[inline]
#[must_use]
fn is_u128(&self) -> bool {
self.as_u128().is_some()
}
#[inline]
#[must_use]
fn is_u64(&self) -> bool {
self.as_u64().is_some()
}
#[inline]
#[must_use]
fn is_usize(&self) -> bool {
self.as_usize().is_some()
}
#[inline]
#[must_use]
fn is_u32(&self) -> bool {
self.as_u32().is_some()
}
#[inline]
#[must_use]
fn is_u16(&self) -> bool {
self.as_u16().is_some()
}
#[inline]
#[must_use]
fn is_u8(&self) -> bool {
self.as_u8().is_some()
}
#[inline]
#[must_use]
fn is_f64(&self) -> bool {
self.as_f64().is_some()
}
#[inline]
#[must_use]
fn is_f64_castable(&self) -> bool {
self.cast_f64().is_some()
}
#[inline]
#[must_use]
fn is_f32(&self) -> bool {
self.as_f32().is_some()
}
#[inline]
#[must_use]
fn is_str(&self) -> bool {
self.as_str().is_some()
}
#[inline]
#[must_use]
fn is_char(&self) -> bool {
self.as_char().is_some()
}
#[inline]
#[must_use]
fn is_array(&self) -> bool {
self.as_array().is_some()
}
#[inline]
#[must_use]
fn is_object(&self) -> bool {
self.as_object().is_some()
}
#[cfg(feature = "custom-types")]
fn is_custom(&self) -> bool {
false
}
}
pub trait Mutable: IndexMut<usize> + Value + Sized {
#[inline]
fn insert<K, V>(&mut self, k: K, v: V) -> std::result::Result<Option<Self::Target>, AccessError>
where
K: Into<<Self as ValueAccess>::Key>,
V: Into<<Self as ValueAccess>::Target>,
<Self as ValueAccess>::Key: Hash + Eq,
{
self.as_object_mut()
.ok_or(AccessError::NotAnObject)
.map(|o| o.insert(k.into(), v.into()))
}
#[inline]
fn try_insert<K, V>(&mut self, k: K, v: V) -> Option<Self::Target>
where
K: Into<<Self as ValueAccess>::Key>,
V: Into<<Self as ValueAccess>::Target>,
<Self as ValueAccess>::Key: Hash + Eq,
{
self.insert(k, v).ok().flatten()
}
#[inline]
fn remove<Q: ?Sized>(&mut self, k: &Q) -> std::result::Result<Option<Self::Target>, AccessError>
where
<Self as ValueAccess>::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.as_object_mut()
.ok_or(AccessError::NotAnObject)
.map(|o| o.remove(k))
}
#[inline]
fn try_remove<Q: ?Sized>(&mut self, k: &Q) -> Option<Self::Target>
where
<Self as ValueAccess>::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.remove(k).ok().flatten()
}
#[inline]
fn push<V>(&mut self, v: V) -> std::result::Result<(), AccessError>
where
V: Into<<Self as ValueAccess>::Target>,
{
self.as_array_mut()
.ok_or(AccessError::NotAnArray)
.map(|o| o.push(v.into()))
}
fn try_push<V>(&mut self, v: V)
where
V: Into<<Self as ValueAccess>::Target>,
{
let _ = self.push(v);
}
#[inline]
fn pop(&mut self) -> std::result::Result<Option<Self::Target>, AccessError> {
self.as_array_mut()
.ok_or(AccessError::NotAnArray)
.map(Array::pop)
}
#[inline]
fn try_pop(&mut self) -> Option<Self::Target> {
self.pop().ok().flatten()
}
fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut Self::Target>
where
<Self as ValueAccess>::Key: Borrow<Q> + Hash + Eq,
Q: Hash + Eq + Ord,
{
self.as_object_mut().and_then(|m| m.get_mut(&k))
}
#[inline]
fn get_idx_mut(&mut self, i: usize) -> Option<&mut Self::Target> {
self.as_array_mut().and_then(|a| a.get_mut(i))
}
fn as_array_mut(&mut self) -> Option<&mut <Self as ValueAccess>::Array>;
fn as_object_mut(&mut self) -> Option<&mut Self::Object>;
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}