1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//! Json parser
//!
//! # Example
//! ```
//! use json::Json;
//!
//! let j = Json::deserialize(r#"{
//! "array" : [ 1, 2, "3", null ],
//! "true" : true,
//! "nested" : {
//! "inner" : []
//! }
//! }"#).unwrap();
//!
//! let Json::Object(map) = j else { panic!() };
//! assert!(
//! matches!(
//! map.get("true"),
//! Some(Json::True)));
//! ```
use std::{borrow::Cow, collections::HashMap, fmt::{Display, Write}};
mod lexer;
mod parser;
#[cfg(feature = "bindings")]
pub mod export;
pub type Result<T> = std::result::Result<T,Cow<'static,str>>;
/// Represents a JSON object
#[derive(Debug)]
pub enum Json {
Array(Vec<Json>),
Object(HashMap<String,Json>),
String(String),
Number(f64),
True, False, Null,
}
/// Configures the JSON parser
pub struct JsonConfig {
/// Max depth for nested objects
pub max_depth: u32,
/// Recover from errors.
/// For example, trailing commas on objects
/// are not allowed, but this flag makes
/// the parser skip them.
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 {
/// Deserializes the given string into a [Json] object
pub fn deserialize(text: impl AsRef<str>) -> Result<Json> {
deserialize!(text, DEFAULT_CONFIG)
}
/// Deserializes the given string into a [Json] object
/// using the given [JsonConfig]
pub fn deserialize_with_config(text: impl AsRef<str>, conf: JsonConfig) -> Result<Json> {
deserialize!(text, conf)
}
/// Serializes the JSON object into a string
pub fn serialize(&self, out: &mut dyn Write) -> std::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(())
}
/// Attempts to get a value of the given json object.
/// If the json enum is not an Object variant, or if
/// it doesn't contain the key, returns None
pub fn get(&self, key: impl AsRef<str>) -> Option<&Json> {
if let Json::Object(o) = self {
o.get(key.as_ref())
} else {
None
}
}
/// Same as [get], but with a mutable reference
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
}
}
/// Attempts to get a value of the given json array.
/// If the json enum is not an Array variant, or if
/// it doesn't contain the key, returns None
pub fn nth(&self, i: usize) -> Option<&Json> {
if let Json::Array(arr) = self {
arr.get(i)
} else {
None
}
}
/// Same as [nth], but with a mutable reference
pub fn nth_mut(&mut self, i: usize) -> Option<&mut Json> {
if let Json::Array(arr) = self {
arr.get_mut(i)
} else {
None
}
}
/// Attempts to get the inner f64 of the json object, if
/// it is a Number variant
pub fn number(&self) -> Option<f64> {
if let Json::Number(n) = self {
Some(*n)
} else { None }
}
/// Attempts to get the inner String of the json object, if
/// it is a String variant
pub fn string(&self) -> Option<&str> {
if let Json::String(s) = self {
Some(s)
} else { None }
}
}
impl Display for Json {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut string = String::new();
self.serialize(&mut string).unwrap();
write!(f, "{}", string)
}
}
impl From<f64> for Json {
fn from(value: f64) -> Self {
Self::Number(value)
}
}
impl From<String> for Json {
fn from(value: String) -> Self {
Self::String(value)
}
}