pub use json_number::{InvalidNumber, Number};
use smallvec::SmallVec;
use std::{fmt, str::FromStr};
pub mod array;
pub mod code_map;
pub mod object;
pub mod parse;
mod unordered;
pub use code_map::CodeMap;
pub use parse::Parse;
pub mod print;
pub use print::Print;
pub mod kind;
pub use kind::{Kind, KindSet};
mod convert;
mod macros;
mod try_from;
pub use try_from::*;
pub mod number {
pub use json_number::Buffer;
}
#[cfg(feature = "serde")]
mod serde;
#[cfg(feature = "serde")]
pub use self::serde::*;
pub use unordered::*;
pub const SMALL_STRING_CAPACITY: usize = 16;
pub type String = smallstr::SmallString<[u8; SMALL_STRING_CAPACITY]>;
pub use array::Array;
pub use object::Object;
pub const NUMBER_CAPACITY: usize = SMALL_STRING_CAPACITY;
pub type NumberBuf = json_number::SmallNumberBuf<NUMBER_CAPACITY>;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub enum Value {
Null,
Boolean(bool),
Number(NumberBuf),
String(String),
Array(Array),
Object(Object),
}
pub fn get_array_fragment(array: &[Value], mut index: usize) -> Result<FragmentRef, usize> {
for v in array {
match v.get_fragment(index) {
Ok(value) => return Ok(value),
Err(i) => index = i,
}
}
Err(index)
}
impl Value {
pub fn get_fragment(&self, index: usize) -> Result<FragmentRef, usize> {
if index == 0 {
Ok(FragmentRef::Value(self))
} else {
match self {
Self::Array(a) => get_array_fragment(a, index - 1),
Self::Object(o) => o.get_fragment(index - 1),
_ => Err(index - 1),
}
}
}
#[inline]
pub fn kind(&self) -> Kind {
match self {
Self::Null => Kind::Null,
Self::Boolean(_) => Kind::Boolean,
Self::Number(_) => Kind::Number,
Self::String(_) => Kind::String,
Self::Array(_) => Kind::Array,
Self::Object(_) => Kind::Object,
}
}
#[inline]
pub fn is_kind(&self, kind: Kind) -> bool {
self.kind() == kind
}
#[inline]
pub fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
#[inline]
pub fn is_boolean(&self) -> bool {
matches!(self, Self::Boolean(_))
}
#[inline]
pub fn is_number(&self) -> bool {
matches!(self, Self::Number(_))
}
#[inline]
pub fn is_string(&self) -> bool {
matches!(self, Self::String(_))
}
#[inline]
pub fn is_array(&self) -> bool {
matches!(self, Self::Array(_))
}
#[inline]
pub fn is_object(&self) -> bool {
matches!(self, Self::Object(_))
}
#[inline]
pub fn is_empty_array_or_object(&self) -> bool {
match self {
Self::Array(a) => a.is_empty(),
Self::Object(o) => o.is_empty(),
_ => false,
}
}
#[inline]
pub fn as_boolean(&self) -> Option<bool> {
match self {
Self::Boolean(b) => Some(*b),
_ => None,
}
}
#[inline]
pub fn as_boolean_mut(&mut self) -> Option<&mut bool> {
match self {
Self::Boolean(b) => Some(b),
_ => None,
}
}
#[inline]
pub fn as_number(&self) -> Option<&Number> {
match self {
Self::Number(n) => Some(n),
_ => None,
}
}
#[inline]
pub fn as_number_mut(&mut self) -> Option<&mut NumberBuf> {
match self {
Self::Number(n) => Some(n),
_ => None,
}
}
#[inline]
pub fn as_string(&self) -> Option<&str> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn as_str(&self) -> Option<&str> {
self.as_string()
}
#[inline]
pub fn as_string_mut(&mut self) -> Option<&mut String> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn as_array(&self) -> Option<&[Self]> {
match self {
Self::Array(a) => Some(a),
_ => None,
}
}
#[inline]
pub fn as_array_mut(&mut self) -> Option<&mut Array> {
match self {
Self::Array(a) => Some(a),
_ => None,
}
}
#[inline]
pub fn force_as_array(&self) -> &[Self] {
match self {
Self::Array(a) => a,
other => core::slice::from_ref(other),
}
}
#[inline]
pub fn as_object(&self) -> Option<&Object> {
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
#[inline]
pub fn as_object_mut(&mut self) -> Option<&mut Object> {
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
#[inline]
pub fn into_boolean(self) -> Option<bool> {
match self {
Self::Boolean(b) => Some(b),
_ => None,
}
}
#[inline]
pub fn into_number(self) -> Option<NumberBuf> {
match self {
Self::Number(n) => Some(n),
_ => None,
}
}
#[inline]
pub fn into_string(self) -> Option<String> {
match self {
Self::String(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn into_array(self) -> Option<Array> {
match self {
Self::Array(a) => Some(a),
_ => None,
}
}
#[inline]
pub fn into_object(self) -> Option<Object> {
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
pub fn traverse(&self) -> Traverse {
let mut stack = SmallVec::new();
stack.push(FragmentRef::Value(self));
Traverse { offset: 0, stack }
}
pub fn count(&self, mut f: impl FnMut(usize, FragmentRef) -> bool) -> usize {
self.traverse().filter(|(i, q)| f(*i, *q)).count()
}
pub fn volume(&self) -> usize {
self.traverse().filter(|(_, f)| f.is_value()).count()
}
#[inline(always)]
pub fn take(&mut self) -> Self {
let mut result = Self::Null;
std::mem::swap(&mut result, self);
result
}
#[cfg(feature = "canonicalize")]
pub fn canonicalize_with(&mut self, buffer: &mut ryu_js::Buffer) {
match self {
Self::Number(n) => *n = NumberBuf::from_number(n.canonical_with(buffer)),
Self::Array(a) => {
for item in a {
item.canonicalize_with(buffer)
}
}
Self::Object(o) => o.canonicalize_with(buffer),
_ => (),
}
}
#[cfg(feature = "canonicalize")]
pub fn canonicalize(&mut self) {
let mut buffer = ryu_js::Buffer::new();
self.canonicalize_with(&mut buffer)
}
}
impl UnorderedPartialEq for Value {
fn unordered_eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Null, Self::Null) => true,
(Self::Boolean(a), Self::Boolean(b)) => a == b,
(Self::Number(a), Self::Number(b)) => a == b,
(Self::String(a), Self::String(b)) => a == b,
(Self::Array(a), Self::Array(b)) => a.unordered_eq(b),
(Self::Object(a), Self::Object(b)) => a.unordered_eq(b),
_ => false,
}
}
}
impl UnorderedEq for Value {}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.compact_print().fmt(f)
}
}
impl From<Value> for ::std::string::String {
fn from(value: Value) -> Self {
value.to_string()
}
}
impl From<bool> for Value {
fn from(b: bool) -> Self {
Self::Boolean(b)
}
}
impl From<NumberBuf> for Value {
fn from(n: NumberBuf) -> Self {
Self::Number(n)
}
}
impl<'n> From<&'n Number> for Value {
fn from(n: &'n Number) -> Self {
Self::Number(unsafe { NumberBuf::new_unchecked(n.as_bytes().into()) })
}
}
impl From<String> for Value {
fn from(s: String) -> Self {
Self::String(s)
}
}
impl From<::std::string::String> for Value {
fn from(s: ::std::string::String) -> Self {
Self::String(s.into())
}
}
impl<'s> From<&'s str> for Value {
fn from(s: &'s str) -> Self {
Self::String(s.into())
}
}
impl From<Array> for Value {
fn from(a: Array) -> Self {
Self::Array(a)
}
}
impl From<Object> for Value {
fn from(o: Object) -> Self {
Self::Object(o)
}
}
impl FromStr for Value {
type Err = parse::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self::parse_str(s)?.0)
}
}
macro_rules! from_integer {
($($ty:ident),*) => {
$(
impl From<$ty> for Value {
fn from(n: $ty) -> Self {
Value::Number(n.into())
}
}
)*
};
}
from_integer! {
u8,
u16,
u32,
u64,
i8,
i16,
i32,
i64
}
macro_rules! try_from_float {
($($ty:ident),*) => {
$(
impl TryFrom<$ty> for Value {
type Error = json_number::TryFromFloatError;
fn try_from(n: $ty) -> Result<Self, Self::Error> {
Ok(Value::Number(n.try_into()?))
}
}
)*
};
}
try_from_float! {
f32,
f64
}
pub enum FragmentRef<'a> {
Value(&'a Value),
Entry(&'a object::Entry),
Key(&'a object::Key),
}
impl<'a> FragmentRef<'a> {
pub fn is_entry(&self) -> bool {
matches!(self, Self::Entry(_))
}
pub fn is_key(&self) -> bool {
matches!(self, Self::Key(_))
}
pub fn is_value(&self) -> bool {
matches!(self, Self::Value(_))
}
pub fn is_null(&self) -> bool {
matches!(self, Self::Value(Value::Null))
}
pub fn is_number(&self) -> bool {
matches!(self, Self::Value(Value::Number(_)))
}
pub fn is_string(&self) -> bool {
matches!(self, Self::Value(Value::String(_)))
}
pub fn is_array(&self) -> bool {
matches!(self, Self::Value(Value::Array(_)))
}
pub fn is_object(&self) -> bool {
matches!(self, Self::Value(Value::Object(_)))
}
pub fn strip(self) -> FragmentRef<'a> {
match self {
Self::Value(v) => FragmentRef::Value(v),
Self::Entry(e) => FragmentRef::Entry(e),
Self::Key(k) => FragmentRef::Key(k),
}
}
}
impl<'a> Clone for FragmentRef<'a> {
fn clone(&self) -> Self {
*self
}
}
impl<'a> Copy for FragmentRef<'a> {}
impl<'a> FragmentRef<'a> {
pub fn sub_fragments(&self) -> SubFragments<'a> {
match self {
Self::Value(Value::Array(a)) => SubFragments::Array(a.iter()),
Self::Value(Value::Object(o)) => SubFragments::Object(o.iter()),
Self::Entry(e) => SubFragments::Entry(Some(&e.key), Some(&e.value)),
_ => SubFragments::None,
}
}
}
pub enum SubFragments<'a> {
None,
Array(core::slice::Iter<'a, Value>),
Object(core::slice::Iter<'a, object::Entry>),
Entry(Option<&'a object::Key>, Option<&'a Value>),
}
impl<'a> Iterator for SubFragments<'a> {
type Item = FragmentRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::None => None,
Self::Array(a) => a.next().map(FragmentRef::Value),
Self::Object(e) => e.next().map(FragmentRef::Entry),
Self::Entry(k, v) => k
.take()
.map(FragmentRef::Key)
.or_else(|| v.take().map(FragmentRef::Value)),
}
}
}
impl<'a> DoubleEndedIterator for SubFragments<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
match self {
Self::None => None,
Self::Array(a) => a.next_back().map(FragmentRef::Value),
Self::Object(e) => e.next_back().map(FragmentRef::Entry),
Self::Entry(k, v) => v
.take()
.map(FragmentRef::Value)
.or_else(|| k.take().map(FragmentRef::Key)),
}
}
}
pub struct Traverse<'a> {
offset: usize,
stack: SmallVec<[FragmentRef<'a>; 8]>,
}
impl<'a> Iterator for Traverse<'a> {
type Item = (usize, FragmentRef<'a>);
fn next(&mut self) -> Option<Self::Item> {
match self.stack.pop() {
Some(v) => {
self.stack.extend(v.sub_fragments().rev());
let i = self.offset;
self.offset += 1;
Some((i, v))
}
None => None,
}
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "canonicalize")]
#[test]
fn canonicalize_01() {
use super::*;
let mut value: Value = json!({
"b": 0.00000000001,
"c": {
"foo": true,
"bar": false
},
"a": [ "foo", "bar" ]
});
value.canonicalize();
assert_eq!(
value.compact_print().to_string(),
"{\"a\":[\"foo\",\"bar\"],\"b\":1e-11,\"c\":{\"bar\":false,\"foo\":true}}"
)
}
#[cfg(feature = "canonicalize")]
#[test]
fn canonicalize_02() {
use super::*;
let (mut value, _) = Value::parse_str(
"{
\"numbers\": [333333333.33333329, 1E30, 4.50, 2e-3, 0.000000000000000000000000001],
\"string\": \"\\u20ac$\\u000F\\u000aA'\\u0042\\u0022\\u005c\\\\\\\"\\/\",
\"literals\": [null, true, false]
}",
)
.unwrap();
value.canonicalize();
assert_eq!(
value.compact_print().to_string(),
"{\"literals\":[null,true,false],\"numbers\":[333333333.3333333,1e+30,4.5,0.002,1e-27],\"string\":\"€$\\u000f\\nA'B\\\"\\\\\\\\\\\"/\"}"
)
}
}