#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate alloc;
mod prelude {
pub use alloc::string::{String,ToString};
pub use core::fmt::{self,Display,Write};
pub use alloc::vec::Vec;
pub use alloc::borrow::{Cow,ToOwned};
pub use alloc::boxed::Box;
#[cfg(feature = "std")]
pub type Map<K,V> = std::collections::HashMap<K,V>;
#[cfg(not(feature = "std"))]
pub type Map<K,V> = alloc::collections::BTreeMap<K,V>;
}
use prelude::*;
mod lexer;
mod parser;
#[cfg(feature = "bindings")]
pub mod export;
pub type Result<T> = core::result::Result<T,Cow<'static,str>>;
#[derive(Debug,PartialEq)]
pub enum Json {
Array(Box<[Json]>),
Object(Map<Box<str>,Json>),
String(Box<str>),
Number(f64),
True, False, Null,
}
#[repr(C)]
pub struct JsonConfig {
pub max_depth: u32,
pub recover_from_errors: bool,
}
const DEFAULT_CONFIG: JsonConfig = JsonConfig {
max_depth: 500,
recover_from_errors: false,
};
impl Default for JsonConfig {
fn default() -> Self { DEFAULT_CONFIG }
}
macro_rules! deserialize {
($text:ident, $conf:ident) => {
{
let mut tokens = lexer::tokenize($text .as_ref())?;
parser::parse(&mut tokens, $conf)
}
};
}
impl Json {
pub fn deserialize(text: impl AsRef<str>) -> Result<Json> {
deserialize!(text, DEFAULT_CONFIG)
}
pub fn deserialize_with_config(text: impl AsRef<str>, conf: JsonConfig) -> Result<Json> {
deserialize!(text, conf)
}
pub fn serialize(&self, out: &mut dyn Write) -> core::fmt::Result {
match self {
Json::Array(elements) => {
out.write_char('[')?;
for i in 0..elements.len() {
elements[i].serialize(out)?;
if i < elements.len() -1 {
out.write_char(',')?;
}
}
out.write_char(']')?;
},
Json::Object(obj) => {
out.write_char('{')?;
let mut first = true;
for (k,v) in obj {
if !first {
out.write_char(',')?;
}
first = false;
write!(out, "\"{k}\":")?;
v.serialize(out)?;
}
out.write_char('}')?;
},
Json::String(s) => { write!(out, "\"{s}\"")?; },
Json::Number(n) => { write!(out, "{n}")?; },
Json::True => { out.write_str("true")? },
Json::False => { out.write_str("false")? },
Json::Null => { out.write_str("null")? },
}
Ok(())
}
pub fn get(&self, key: impl AsRef<str>) -> Option<&Json> {
if let Json::Object(o) = self {
o.get(key.as_ref())
} else {
None
}
}
pub fn get_mut(&mut self, key: impl AsRef<str>) -> Option<&mut Json> {
if let Json::Object(o) = self {
o.get_mut(key.as_ref())
} else {
None
}
}
pub fn nth(&self, i: usize) -> Option<&Json> {
if let Json::Array(arr) = self {
arr.get(i)
} else {
None
}
}
pub fn nth_mut(&mut self, i: usize) -> Option<&mut Json> {
if let Json::Array(arr) = self {
arr.get_mut(i)
} else {
None
}
}
pub fn number(&self) -> Option<f64> {
if let Json::Number(n) = self {
Some(*n)
} else { None }
}
pub fn string(&self) -> Option<&str> {
if let Json::String(s) = self {
Some(s)
} else { None }
}
pub fn object(&self) -> Option<&Map<Box<str>,Json>> {
if let Json::Object(o) = self {
Some(o)
} else { None }
}
pub fn array(&self) -> Option<&[Json]> {
if let Json::Array(o) = self {
Some(o)
} else { None }
}
pub fn boolean(&self) -> Option<bool> {
if let Json::True = self {
Some(true)
} else if let Json::False = self {
Some(false)
} else { None }
}
pub fn is_null(&self) -> bool {
matches!(self,Json::Null)
}
}
impl Display for Json {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut string = String::new();
self.serialize(&mut string).unwrap();
write!(f, "{}", string)
}
}
macro_rules! from_num {
( $( $nty:ty ),* ) => {
$(
impl From<$nty> for Json {
fn from(value: $nty) -> Self {
Self::Number(value.into())
}
}
)*
};
}
from_num!(f64,f32,i32,i16,u16,u8);
impl From<Box<str>> for Json {
fn from(value: Box<str>) -> Self {
Self::String(value)
}
}
impl<'a> From<&'a str> for Json {
fn from(value: &'a str) -> Self {
Self::String(value.into())
}
}
impl From<Vec<Json>> for Json {
fn from(value: Vec<Json>) -> Self {
Self::Array(value.into())
}
}
impl From<Map<Box<str>,Json>> for Json {
fn from(value: Map<Box<str>,Json>) -> Self {
Self::Object(value)
}
}
impl From<bool> for Json {
fn from(value: bool) -> Self {
if value { Json::True } else { Json::False }
}
}
#[macro_export]
macro_rules! json {
( $lit:literal ) => {
$crate::Json::from( $lit )
};
( [ $( $e:tt ),* ] ) => {
$crate::Json::from(
vec![
$(
json!($e)
),*
]
)
};
( { $( $key:literal : $val:tt ),* } ) => {
{
let mut map = std::collections::HashMap::new();
$( map.insert($key .into(), json!($val) ); )*
$crate::Json::from ( map )
}
};
( null ) => {
$crate::Json::Null
}
}