#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
use core::convert::Infallible;
use core::fmt::{self, Display};
use core::ops::{Deref, DerefMut, Index, IndexMut};
use crate::parser::{JsonKind, ParseConfig, ParseDelegate, Parser};
use crate::{Error, JsonNumber, JsonString};
#[derive(Debug, Eq, PartialEq)]
pub enum Value<'a> {
Number(JsonNumber<'a>),
String(JsonString<'a>),
Boolean(bool),
Object(Object<'a>),
Array(Vec<Value<'a>>),
Null,
}
impl<'a> Value<'a> {
pub fn from_json(json: &'a str) -> Result<Self, Error> {
Self::from_json_with_config(json, ParseConfig::default())
}
pub fn from_json_with_config(json: &'a str, config: ParseConfig) -> Result<Self, Error> {
Parser::parse_json_with_config(json, config, ValueParser)
}
pub fn from_json_bytes(json: &'a [u8]) -> Result<Self, Error> {
Self::from_json_bytes_with_config(json, ParseConfig::default())
}
pub fn from_json_bytes_with_config(json: &'a [u8], config: ParseConfig) -> Result<Self, Error> {
Parser::parse_json_bytes_with_config(json, config, ValueParser)
}
#[must_use]
#[inline]
pub const fn as_object(&self) -> Option<&Object<'a>> {
if let Self::Object(obj) = self {
Some(obj)
} else {
None
}
}
#[must_use]
#[inline]
pub fn as_object_mut(&mut self) -> Option<&mut Object<'a>> {
if let Self::Object(obj) = self {
Some(obj)
} else {
None
}
}
#[must_use]
#[inline]
pub fn get(&self, key: &str) -> Option<&Value<'a>> {
let object = self.as_object()?;
object.get(key)
}
#[must_use]
#[inline]
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value<'a>> {
let object = self.as_object_mut()?;
object.get_mut(key)
}
#[must_use]
#[inline]
pub const fn as_string(&self) -> Option<&JsonString<'a>> {
if let Self::String(obj) = self {
Some(obj)
} else {
None
}
}
#[must_use]
#[inline]
pub fn as_str(&self) -> Option<&str> {
if let Self::String(json_string) = self {
json_string.as_str()
} else {
None
}
}
#[must_use]
#[inline]
pub const fn as_number(&self) -> Option<&JsonNumber<'a>> {
if let Self::Number(obj) = self {
Some(obj)
} else {
None
}
}
#[must_use]
pub fn as_f32(&self) -> Option<f32> {
self.as_number().and_then(JsonNumber::as_f32)
}
#[must_use]
pub fn as_f64(&self) -> Option<f64> {
self.as_number().and_then(JsonNumber::as_f64)
}
#[must_use]
#[inline]
pub const fn as_bool(&self) -> Option<bool> {
if let Self::Boolean(value) = self {
Some(*value)
} else {
None
}
}
#[must_use]
#[inline]
pub fn as_array(&self) -> Option<&[Self]> {
if let Self::Array(value) = self {
Some(value)
} else {
None
}
}
#[must_use]
#[inline]
pub fn as_array_mut(&mut self) -> Option<&mut Vec<Self>> {
if let Self::Array(value) = self {
Some(value)
} else {
None
}
}
#[must_use]
#[inline]
pub fn get_index(&self, index: usize) -> Option<&Value<'a>> {
let sequence = self.as_array()?;
sequence.get(index)
}
#[must_use]
#[inline]
pub fn get_index_mut(&mut self, index: usize) -> Option<&mut Value<'a>> {
let sequence = self.as_array_mut()?;
sequence.get_mut(index)
}
#[must_use]
#[inline]
pub const fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
fn write_json<W: fmt::Write, const PRETTY: bool>(
&self,
indentation: &str,
line_ending: &str,
destination: W,
) -> fmt::Result {
let mut state = WriteState::<W, PRETTY>::new(destination, indentation, line_ending);
self.write_json_value(&mut state)
}
fn write_json_value<W: fmt::Write, const PRETTY: bool>(
&self,
state: &mut WriteState<'_, W, PRETTY>,
) -> fmt::Result {
match self {
Value::String(string) => state.write_json(string),
Value::Number(number) => state.write(number.source()),
Value::Boolean(bool) => state.write(if *bool { "true" } else { "false" }),
Value::Null => state.write("null"),
Value::Object(obj) => Self::write_json_object(obj, state),
Value::Array(array) => Self::write_json_array(array, state),
}
}
fn write_json_object<W: fmt::Write, const PRETTY: bool>(
obj: &Object<'_>,
state: &mut WriteState<'_, W, PRETTY>,
) -> fmt::Result {
state.begin_object()?;
if !obj.0.is_empty() {
state.new_line()?;
for (index, entry) in obj.0.iter().enumerate() {
state.write_json(&entry.key)?;
state.write_object_key_end()?;
entry.value.write_json_value(state)?;
if index != obj.0.len() - 1 {
state.write(",")?;
}
state.new_line()?;
}
}
state.end_object()
}
fn write_json_array<W: fmt::Write, const PRETTY: bool>(
array: &Vec<Self>,
state: &mut WriteState<'_, W, PRETTY>,
) -> fmt::Result {
state.begin_array()?;
if !array.is_empty() {
state.new_line()?;
for (index, value) in array.iter().enumerate() {
value.write_json_value(state)?;
if index != array.len() - 1 {
state.write(",")?;
}
state.new_line()?;
}
}
state.end_array()
}
#[must_use]
pub fn to_json_pretty(&self) -> String {
let mut out = String::new();
self.pretty_write_json_to(&mut out).expect("out of memory");
out
}
#[must_use]
pub fn to_json_pretty_custom(&self, indentation: &str, line_ending: &str) -> String {
let mut out = String::new();
self.pretty_write_json_to_custom(indentation, line_ending, &mut out)
.expect("out of memory");
out
}
#[must_use]
pub fn to_json(&self) -> String {
let mut out = String::new();
self.write_json_to(&mut out).expect("out of memory");
out
}
pub fn write_json_to<W: fmt::Write>(&self, destination: W) -> fmt::Result {
self.write_json::<W, false>("", "", destination)
}
pub fn pretty_write_json_to<W: fmt::Write>(&self, destination: W) -> fmt::Result {
self.pretty_write_json_to_custom(" ", "\n", destination)
}
pub fn pretty_write_json_to_custom<W: fmt::Write>(
&self,
indentation: &str,
line_ending: &str,
destination: W,
) -> fmt::Result {
self.write_json::<W, true>(indentation, line_ending, destination)
}
}
macro_rules! impl_as_number {
($name:ident, $type:ident) => {
impl Value<'_> {
#[doc = concat!("[`", stringify!($type), "`]")]
#[must_use]
pub fn $name(&self) -> Option<$type> {
self.as_number().and_then(JsonNumber::$name)
}
}
};
}
impl_as_number!(as_u8, u8);
impl_as_number!(as_u16, u16);
impl_as_number!(as_u32, u32);
impl_as_number!(as_u64, u64);
impl_as_number!(as_u128, u128);
impl_as_number!(as_usize, usize);
impl_as_number!(as_i8, i8);
impl_as_number!(as_i16, i16);
impl_as_number!(as_i32, i32);
impl_as_number!(as_i64, i64);
impl_as_number!(as_i128, i128);
impl_as_number!(as_isize, isize);
#[test]
fn value_ases() {
assert!(Value::from(true).as_bool().unwrap());
assert_eq!(
Value::String(JsonString::from_json("\"\"").unwrap())
.as_string()
.unwrap(),
""
);
assert_eq!(
Value::String(JsonString::from_json("\"\"").unwrap())
.as_str()
.unwrap(),
""
);
assert_eq!(
Value::Number(JsonNumber::from_json("1").unwrap())
.as_number()
.unwrap()
.as_u64()
.unwrap(),
1
);
assert_eq!(
Value::Object(Object::new()).as_object().unwrap(),
&Object::new()
);
assert_eq!(Value::Array(Vec::new()).as_array().unwrap(), &[]);
assert!(Value::Null.is_null());
assert!(!Value::from(true).is_null());
assert_eq!(Value::Null.as_bool(), None);
assert_eq!(Value::Null.as_number(), None);
assert_eq!(Value::Null.as_string(), None);
assert_eq!(Value::Null.as_str(), None);
assert_eq!(Value::Null.as_object(), None);
assert_eq!(Value::Null.as_array(), None);
}
impl<'a> Display for Value<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
self.pretty_write_json_to(f)
} else {
self.write_json_to(f)
}
}
}
pub(crate) struct ValueParser;
impl<'a> ParseDelegate<'a> for ValueParser {
type Array = Vec<Value<'a>>;
type Error = Infallible;
type Key = JsonString<'a>;
type Object = Object<'a>;
type Value = Value<'a>;
#[inline]
fn null(&mut self) -> Result<Self::Value, Self::Error> {
Ok(Value::Null)
}
#[inline]
fn boolean(&mut self, value: bool) -> Result<Self::Value, Self::Error> {
Ok(Value::Boolean(value))
}
#[inline]
fn number(&mut self, value: JsonNumber<'a>) -> Result<Self::Value, Self::Error> {
Ok(Value::Number(value))
}
#[inline]
fn string(&mut self, value: JsonString<'a>) -> Result<Self::Value, Self::Error> {
Ok(Value::String(value))
}
#[inline]
fn begin_object(&mut self) -> Result<Self::Object, Self::Error> {
Ok(Object::default())
}
#[inline]
fn object_key(
&mut self,
_object: &mut Self::Object,
key: JsonString<'a>,
) -> Result<Self::Key, Self::Error> {
Ok(key)
}
#[inline]
fn object_value(
&mut self,
object: &mut Self::Object,
key: Self::Key,
value: Self::Value,
) -> Result<(), Self::Error> {
object.push(Entry { key, value });
Ok(())
}
#[inline]
fn object_is_empty(&self, object: &Self::Object) -> bool {
object.is_empty()
}
#[inline]
fn end_object(&mut self, object: Self::Object) -> Result<Self::Value, Self::Error> {
Ok(Value::Object(object))
}
#[inline]
fn begin_array(&mut self) -> Result<Self::Array, Self::Error> {
Ok(Vec::new())
}
#[inline]
fn array_value(
&mut self,
array: &mut Self::Array,
value: Self::Value,
) -> Result<(), Self::Error> {
array.push(value);
Ok(())
}
#[inline]
fn array_is_empty(&self, array: &Self::Array) -> bool {
array.is_empty()
}
#[inline]
fn end_array(&mut self, array: Self::Array) -> Result<Self::Value, Self::Error> {
Ok(Value::Array(array))
}
#[inline]
fn kind_of(&self, value: &Self::Value) -> JsonKind {
match value {
Value::Number(_) => JsonKind::Number,
Value::String(_) => JsonKind::String,
Value::Boolean(_) => JsonKind::Boolean,
Value::Object(_) => JsonKind::Object,
Value::Array(_) => JsonKind::Array,
Value::Null => JsonKind::Null,
}
}
}
struct WriteState<'a, W, const PRETTY: bool> {
writer: W,
level: usize,
indent_per_level: &'a str,
line_ending: &'a str,
is_at_line_start: bool,
}
impl<'a, W, const PRETTY: bool> WriteState<'a, W, PRETTY>
where
W: fmt::Write,
{
fn new(writer: W, indentation: &'a str, line_ending: &'a str) -> Self {
Self {
writer,
level: 0,
is_at_line_start: true,
indent_per_level: indentation,
line_ending,
}
}
fn write(&mut self, str: &str) -> fmt::Result {
if PRETTY && self.is_at_line_start {
self.is_at_line_start = false;
for _ in 0..self.level {
self.writer.write_str(self.indent_per_level)?;
}
}
self.writer.write_str(str)?;
Ok(())
}
fn write_json(&mut self, str: &JsonString<'_>) -> fmt::Result {
if PRETTY && self.is_at_line_start {
self.is_at_line_start = false;
for _ in 0..self.level {
self.writer.write_str(self.indent_per_level)?;
}
}
write!(self.writer, "\"{}\"", str.as_json())
}
fn new_line(&mut self) -> fmt::Result {
if PRETTY {
self.write(self.line_ending)?;
self.is_at_line_start = true;
}
Ok(())
}
fn begin_object(&mut self) -> fmt::Result {
self.write("{")?;
self.level += 1;
Ok(())
}
fn write_object_key_end(&mut self) -> fmt::Result {
if PRETTY {
self.write(": ")?;
} else {
self.write(":")?;
}
Ok(())
}
fn end_object(&mut self) -> fmt::Result {
self.level -= 1;
self.write("}")?;
Ok(())
}
fn begin_array(&mut self) -> fmt::Result {
self.write("[")?;
self.level += 1;
Ok(())
}
fn end_array(&mut self) -> fmt::Result {
self.level -= 1;
self.write("]")?;
Ok(())
}
}
impl<'a> Index<usize> for Value<'a> {
type Output = Value<'a>;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
self.get_index(index).expect("index not found")
}
}
impl<'a> IndexMut<usize> for Value<'a> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
self.get_index_mut(index).expect("index not found")
}
}
impl<'b, 'a> Index<&'b str> for Value<'a> {
type Output = Value<'a>;
#[inline]
fn index(&self, index: &'b str) -> &Self::Output {
self.get(index).expect("key not found")
}
}
impl<'b, 'a> IndexMut<&'b str> for Value<'a> {
#[inline]
fn index_mut(&mut self, index: &'b str) -> &mut Self::Output {
self.get_mut(index).expect("key not found")
}
}
impl<'a> From<bool> for Value<'a> {
#[inline]
fn from(value: bool) -> Self {
Self::Boolean(value)
}
}
impl<'a> From<Object<'a>> for Value<'a> {
#[inline]
fn from(value: Object<'a>) -> Self {
Self::Object(value)
}
}
impl<'a> From<Vec<Value<'a>>> for Value<'a> {
#[inline]
fn from(value: Vec<Value<'a>>) -> Self {
Self::Array(value)
}
}
impl<'a> From<&'a str> for Value<'a> {
#[inline]
fn from(value: &'a str) -> Self {
Self::from(JsonString::from(value))
}
}
impl<'a> From<String> for Value<'a> {
#[inline]
fn from(value: String) -> Self {
Self::from(JsonString::from(value))
}
}
impl<'a> From<JsonString<'a>> for Value<'a> {
#[inline]
fn from(value: JsonString<'a>) -> Self {
Self::String(value)
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Object<'a>(Vec<Entry<'a>>);
impl<'a> Default for Object<'a> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<'a> Object<'a> {
#[must_use]
#[inline]
pub const fn new() -> Self {
Self(Vec::new())
}
#[must_use]
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
#[must_use]
#[inline]
pub fn get(&self, key: &str) -> Option<&Value<'a>> {
self.iter()
.find_map(|entry| (entry.key == key).then_some(&entry.value))
}
#[must_use]
#[inline]
pub fn get_mut(&mut self, key: &str) -> Option<&mut Value<'a>> {
self.get_entry_mut(key).map(|entry| &mut entry.value)
}
#[must_use]
#[inline]
pub fn get_entry_mut(&mut self, key: &str) -> Option<&mut Entry<'a>> {
self.iter_mut().find(|entry| entry.key == key)
}
}
impl<'a> Deref for Object<'a> {
type Target = Vec<Entry<'a>>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> DerefMut for Object<'a> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a> FromIterator<(JsonString<'a>, Value<'a>)> for Object<'a> {
fn from_iter<T: IntoIterator<Item = (JsonString<'a>, Value<'a>)>>(iter: T) -> Self {
iter.into_iter()
.map(|(key, value)| Entry { key, value })
.collect()
}
}
impl<'a> FromIterator<Entry<'a>> for Object<'a> {
fn from_iter<T: IntoIterator<Item = Entry<'a>>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
pub key: JsonString<'a>,
pub value: Value<'a>,
}
impl<'a> Entry<'a> {
#[inline]
pub fn new(key: impl Into<JsonString<'a>>, value: impl Into<Value<'a>>) -> Self {
Self {
key: key.into(),
value: value.into(),
}
}
}
#[test]
fn primitive_values() {
assert_eq!(Value::from_json("true").unwrap(), Value::from(true));
assert_eq!(Value::from_json("false").unwrap(), Value::from(false));
assert_eq!(Value::from_json("null").unwrap(), Value::Null);
}
#[test]
fn objects() {
assert_eq!(
Value::from_json("{}").unwrap(),
Value::Object(Object::default())
);
assert_eq!(
Value::from_json(r#"{"hello":"world"}"#).unwrap(),
Value::Object(Object::from_iter([(
JsonString::from_json(r#""hello""#).unwrap(),
Value::String(JsonString::from_json(r#""world""#).unwrap())
)]))
);
assert_eq!(
Value::from_json(r#" { "hello" : "world" , "another" : "value" }"#).unwrap(),
Value::Object(Object::from_iter([
Entry::new(
JsonString::from_json(r#""hello""#).unwrap(),
Value::String(JsonString::from_json(r#""world""#).unwrap())
),
Entry::new(
JsonString::from_json(r#""another""#).unwrap(),
Value::String(JsonString::from_json(r#""value""#).unwrap())
)
]))
);
}
#[test]
fn cow() {
let mut value =
Value::from_json_bytes(br#"{"a":1,"b":true,"c":"hello","d":[],"e":{}}"#).unwrap();
value["b"] = Value::from(false);
let root = value.as_object_mut().unwrap();
root[0].key = JsonString::from("newa");
root[0].value = JsonString::from("a").into();
let Value::Array(d_array) = &mut root[3].value else {
unreachable!()
};
d_array.push(Value::Null);
value["d"][0] = Value::from(false);
let generated = value.to_json();
assert_eq!(
generated,
r#"{"newa":"a","b":false,"c":"hello","d":[false],"e":{}}"#
);
}
#[test]
fn index() {
let mut value = Value::from_json_bytes(br#"{"b":true,"a":[false]}"#).unwrap();
assert_eq!(value["b"], Value::from(true));
assert_eq!(value.get_index_mut(0), None);
assert_eq!(value["a"][0], Value::from(false));
assert_eq!(value["a"].get_mut("a"), None);
}
#[test]
fn froms() {
assert_eq!(Value::from(true), Value::Boolean(true));
assert_eq!(Value::from(Object::new()), Value::Object(Object::new()));
assert_eq!(Value::from(Vec::new()), Value::Array(Vec::new()));
assert_eq!(
Value::from(String::from("a")),
Value::String(JsonString::from("a"))
);
assert_eq!(Value::from("a"), Value::String(JsonString::from("a")));
assert_eq!(
Value::from(JsonString::from("a")),
Value::String(JsonString::from("a"))
);
}
#[test]
fn as_es() {
macro_rules! test_as {
($as:ident) => {
assert_eq!(
Value::Number(JsonNumber::from_json("1").unwrap()).$as(),
Some(1)
);
};
}
test_as!(as_i8);
test_as!(as_i16);
test_as!(as_i32);
test_as!(as_i64);
test_as!(as_i128);
test_as!(as_isize);
test_as!(as_u8);
test_as!(as_u16);
test_as!(as_u32);
test_as!(as_u64);
test_as!(as_u128);
test_as!(as_usize);
assert!(
Value::Number(JsonNumber::from_json("0").unwrap())
.as_f32()
.unwrap()
.abs()
< f32::EPSILON
);
assert!(
Value::Number(JsonNumber::from_json("0").unwrap())
.as_f64()
.unwrap()
.abs()
< f64::EPSILON
);
}