mod de;
mod from;
mod index;
mod partial_eq;
mod ser;
use core::fmt::{self, Debug, Display};
use core::mem;
use core::str;
use std::io;
use std::rc::Rc;
pub use self::index::Index;
use crate::JsonString;
pub use crate::Map;
pub use serde::ser::Serializer;
pub use serde_json::Number;
#[derive(Clone, Eq, PartialEq)]
pub enum JValue {
Null,
Bool(bool),
Number(Number),
String(JsonString),
Array(Rc<[JValue]>),
Object(Rc<Map<JsonString, JValue>>),
}
impl Debug for JValue {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self {
JValue::Null => formatter.write_str("Null"),
JValue::Bool(boolean) => write!(formatter, "Bool({})", boolean),
JValue::Number(number) => Debug::fmt(number, formatter),
JValue::String(string) => write!(formatter, "String({:?})", string),
JValue::Array(vec) => {
tri!(formatter.write_str("Array "));
Debug::fmt(vec, formatter)
}
JValue::Object(map) => {
tri!(formatter.write_str("Object "));
Debug::fmt(&**map, formatter)
}
}
}
}
impl Display for JValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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 { str::from_utf8_unchecked(buf) };
tri!(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::new(io::ErrorKind::Other, "fmt error")
}
let alternate = f.alternate();
let mut wr = WriterFormatter { inner: f };
if alternate {
serde_json::ser::to_writer_pretty(&mut wr, self).map_err(|_| fmt::Error)
} else {
serde_json::ser::to_writer(&mut wr, self).map_err(|_| fmt::Error)
}
}
}
fn parse_index(s: &str) -> Option<usize> {
if s.starts_with('+') || (s.starts_with('0') && s.len() != 1) {
return None;
}
s.parse().ok()
}
impl JValue {
#[inline]
pub fn string(s: impl Into<Rc<str>>) -> Self {
Self::String(s.into())
}
#[inline]
pub fn array(vec: impl Into<Rc<[JValue]>>) -> Self {
Self::Array(vec.into())
}
pub fn array_from_iter(into_iter: impl IntoIterator<Item = impl Into<JValue>>) -> Self {
Self::Array(into_iter.into_iter().map(Into::into).collect())
}
pub fn object(map: impl Into<Map<JsonString, JValue>>) -> Self {
Self::Object(Rc::new(map.into()))
}
pub fn object_from_pairs(
into_iter: impl IntoIterator<Item = (impl Into<JsonString>, impl Into<JValue>)>,
) -> Self {
Self::Object(Rc::new(
into_iter
.into_iter()
.map(|(k, v)| (k.into(), v.into()))
.collect(),
))
}
pub fn get<I: Index>(&self, index: I) -> Option<&JValue> {
index.index_into(self)
}
#[inline]
pub fn is_object(&self) -> bool {
self.as_object().is_some()
}
#[inline]
pub fn as_object(&self) -> Option<&Map<JsonString, JValue>> {
match self {
JValue::Object(map) => Some(map),
_ => None,
}
}
#[inline]
pub fn is_array(&self) -> bool {
self.as_array().is_some()
}
#[inline]
pub fn as_array(&self) -> Option<&[JValue]> {
match self {
JValue::Array(array) => Some(array),
_ => None,
}
}
#[inline]
pub fn is_string(&self) -> bool {
self.as_str().is_some()
}
#[inline]
pub fn as_str(&self) -> Option<&JsonString> {
match self {
JValue::String(s) => Some(s),
_ => None,
}
}
#[inline]
pub fn is_number(&self) -> bool {
matches!(self, JValue::Number(_))
}
#[inline]
pub fn as_number(&self) -> Option<&Number> {
match self {
JValue::Number(number) => Some(number),
_ => None,
}
}
#[inline]
pub fn is_i64(&self) -> bool {
match self {
JValue::Number(n) => n.is_i64(),
_ => false,
}
}
#[inline]
pub fn is_u64(&self) -> bool {
match self {
JValue::Number(n) => n.is_u64(),
_ => false,
}
}
#[inline]
pub fn is_f64(&self) -> bool {
match self {
JValue::Number(n) => n.is_f64(),
_ => false,
}
}
#[inline]
pub fn as_i64(&self) -> Option<i64> {
match self {
JValue::Number(n) => n.as_i64(),
_ => None,
}
}
#[inline]
pub fn as_u64(&self) -> Option<u64> {
match self {
JValue::Number(n) => n.as_u64(),
_ => None,
}
}
#[inline]
pub fn as_f64(&self) -> Option<f64> {
match self {
JValue::Number(n) => n.as_f64(),
_ => None,
}
}
#[inline]
pub fn is_boolean(&self) -> bool {
self.as_bool().is_some()
}
#[inline]
pub fn as_bool(&self) -> Option<bool> {
match *self {
JValue::Bool(b) => Some(b),
_ => None,
}
}
#[inline]
pub fn is_null(&self) -> bool {
self.as_null().is_some()
}
#[inline]
pub fn as_null(&self) -> Option<()> {
match *self {
JValue::Null => Some(()),
_ => None,
}
}
pub fn pointer(&self, pointer: &str) -> Option<&JValue> {
if pointer.is_empty() {
return Some(self);
}
if !pointer.starts_with('/') {
return None;
}
pointer
.split('/')
.skip(1)
.map(|x| x.replace("~1", "/").replace("~0", "~"))
.try_fold(self, |target, token| match target {
JValue::Object(map) => map.get(token.as_str()),
JValue::Array(list) => parse_index(&token).and_then(|x| list.get(x)),
_ => None,
})
}
#[inline]
pub fn take(&mut self) -> JValue {
mem::replace(self, JValue::Null)
}
}
impl Default for JValue {
#[inline]
fn default() -> JValue {
JValue::Null
}
}