use serde::de::{Deserializer, MapAccess, SeqAccess, Visitor};
use serde::Deserialize;
use std::fmt;
use std::fmt::Write as _;
#[derive(Debug, Clone, PartialEq)]
pub enum JsonValue {
Null,
Bool(bool),
Number(serde_json::Number),
String(String),
Array(Vec<JsonValue>),
Object(Vec<(String, JsonValue)>),
}
impl JsonValue {
pub fn parse(text: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(text)
}
pub fn get(&self, key: &str) -> Option<&JsonValue> {
match self {
JsonValue::Object(entries) => entries.iter().find(|(k, _)| k == key).map(|(_, v)| v),
_ => None,
}
}
pub fn contains_key(&self, key: &str) -> bool {
self.get(key).is_some()
}
pub fn as_object(&self) -> Option<&[(String, JsonValue)]> {
match self {
JsonValue::Object(entries) => Some(entries.as_slice()),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[JsonValue]> {
match self {
JsonValue::Array(items) => Some(items.as_slice()),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
JsonValue::String(s) => Some(s.as_str()),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
JsonValue::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
JsonValue::Number(n) => n.as_u64(),
_ => None,
}
}
pub fn kind(&self) -> &'static str {
match self {
JsonValue::Null => "null",
JsonValue::Bool(_) => "boolean",
JsonValue::Number(_) => "number",
JsonValue::String(_) => "string",
JsonValue::Array(_) => "array",
JsonValue::Object(_) => "object",
}
}
pub fn dump(&self) -> String {
let mut out = String::new();
self.dump_into(&mut out);
out
}
fn dump_into(&self, out: &mut String) {
match self {
JsonValue::Null => out.push_str("null"),
JsonValue::Bool(true) => out.push_str("true"),
JsonValue::Bool(false) => out.push_str("false"),
JsonValue::Number(n) => {
let _ = write!(out, "{n}");
}
JsonValue::String(s) => escape_json_string(s, out),
JsonValue::Array(items) => {
out.push('[');
for (i, item) in items.iter().enumerate() {
if i > 0 {
out.push(',');
}
item.dump_into(out);
}
out.push(']');
}
JsonValue::Object(entries) => {
out.push('{');
for (i, (k, v)) in entries.iter().enumerate() {
if i > 0 {
out.push(',');
}
escape_json_string(k, out);
out.push(':');
v.dump_into(out);
}
out.push('}');
}
}
}
}
fn escape_json_string(s: &str, out: &mut String) {
out.push('"');
for c in s.chars() {
match c {
'"' => out.push_str("\\\""),
'\\' => out.push_str("\\\\"),
'\u{08}' => out.push_str("\\b"),
'\u{0c}' => out.push_str("\\f"),
'\n' => out.push_str("\\n"),
'\r' => out.push_str("\\r"),
'\t' => out.push_str("\\t"),
c if (c as u32) < 0x20 => {
let _ = write!(out, "\\u{:04x}", c as u32);
}
c => out.push(c),
}
}
out.push('"');
}
impl From<&serde_json::Value> for JsonValue {
fn from(value: &serde_json::Value) -> Self {
match value {
serde_json::Value::Null => JsonValue::Null,
serde_json::Value::Bool(b) => JsonValue::Bool(*b),
serde_json::Value::Number(n) => JsonValue::Number(n.clone()),
serde_json::Value::String(s) => JsonValue::String(s.clone()),
serde_json::Value::Array(items) => {
JsonValue::Array(items.iter().map(JsonValue::from).collect())
}
serde_json::Value::Object(map) => JsonValue::Object(
map.iter()
.map(|(k, v)| (k.clone(), JsonValue::from(v)))
.collect(),
),
}
}
}
impl<'de> Deserialize<'de> for JsonValue {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_any(JsonValueVisitor)
}
}
struct JsonValueVisitor;
impl<'de> Visitor<'de> for JsonValueVisitor {
type Value = JsonValue;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("any JSON value")
}
fn visit_unit<E>(self) -> Result<JsonValue, E> {
Ok(JsonValue::Null)
}
fn visit_none<E>(self) -> Result<JsonValue, E> {
Ok(JsonValue::Null)
}
fn visit_some<D: Deserializer<'de>>(self, d: D) -> Result<JsonValue, D::Error> {
d.deserialize_any(self)
}
fn visit_bool<E>(self, v: bool) -> Result<JsonValue, E> {
Ok(JsonValue::Bool(v))
}
fn visit_i64<E>(self, v: i64) -> Result<JsonValue, E> {
Ok(JsonValue::Number(v.into()))
}
fn visit_u64<E>(self, v: u64) -> Result<JsonValue, E> {
Ok(JsonValue::Number(v.into()))
}
fn visit_f64<E: serde::de::Error>(self, v: f64) -> Result<JsonValue, E> {
Ok(match serde_json::Number::from_f64(v) {
Some(n) => JsonValue::Number(n),
None => JsonValue::Null,
})
}
fn visit_str<E>(self, v: &str) -> Result<JsonValue, E> {
Ok(JsonValue::String(v.to_string()))
}
fn visit_string<E>(self, v: String) -> Result<JsonValue, E> {
Ok(JsonValue::String(v))
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<JsonValue, A::Error> {
let mut items = Vec::new();
while let Some(item) = seq.next_element()? {
items.push(item);
}
Ok(JsonValue::Array(items))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<JsonValue, A::Error> {
let mut entries: Vec<(String, JsonValue)> = Vec::new();
while let Some((k, v)) = map.next_entry::<String, JsonValue>()? {
if !entries.iter().any(|(existing, _)| *existing == k) {
entries.push((k, v));
}
}
Ok(JsonValue::Object(entries))
}
}