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
//! 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)?;
parser::parse(&mut tokens, $conf)
}
};
}
impl Json {
/// Deserializes the given string into a [Json] object
pub fn deserialize(text: &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: &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;
out.write_str(k)?;
out.write_char(':')?;
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(())
}
}
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)
}
}