use super::RJson;
use core::ops;
use once_cell::sync::Lazy;
use std::collections::HashMap;
static RJSON_NULL: Lazy<RJson> = Lazy::new(|| RJson::new(Json::Null));
#[derive(Debug, Clone)]
pub enum Json {
Null,
Bool(bool),
Number(serde_json::Number),
String(String),
Array(Vec<RJson>),
Object(HashMap<String, RJson>),
}
impl From<serde_json::Value> for Json {
fn from(value: serde_json::Value) -> Self {
match value {
serde_json::Value::Null => Json::Null,
serde_json::Value::Bool(b) => Json::Bool(b),
serde_json::Value::Number(n) => Json::Number(n),
serde_json::Value::String(s) => Json::String(s),
serde_json::Value::Array(a) => Json::Array(a.into_iter().map(|v| RJson::new(v)).collect()),
serde_json::Value::Object(o) => Json::Object(o.into_iter().map(|(k, v)| (k, RJson::new(v))).collect()),
}
}
}
impl From<Json> for serde_json::Value {
fn from(value: Json) -> Self {
match &value {
Json::Null => serde_json::Value::Null,
Json::Bool(b) => serde_json::Value::Bool(*b),
Json::Number(n) => serde_json::Value::Number(n.clone()),
Json::String(s) => serde_json::Value::String(s.clone()),
Json::Array(a) => {
let vec = serde_json::Value::Array(
a.into_iter()
.map(|j| {
let j: Json = j.clone().into();
serde_json::Value::from(j)
})
.collect(),
);
vec
}
Json::Object(o) => serde_json::Value::Object(
o.into_iter()
.map(|(k, j)| {
let j: Json = j.clone().into();
let v = serde_json::Value::from(j);
(k.clone(), v)
})
.collect(),
),
}
}
}
pub trait Index {
#[doc(hidden)]
fn index_into<'v>(&self, v: &'v Json) -> Option<&'v RJson>;
#[doc(hidden)]
fn index_into_mut<'v>(&self, v: &'v mut Json) -> Option<&'v mut RJson>;
#[doc(hidden)]
fn index_or_insert<'v>(&self, v: &'v mut Json) -> &'v mut RJson;
}
impl Index for usize {
fn index_into<'v>(&self, v: &'v Json) -> Option<&'v RJson> {
match v {
Json::Array(vec) => vec.get(*self),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut Json) -> Option<&'v mut RJson> {
match v {
Json::Array(vec) => vec.get_mut(*self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Json) -> &'v mut RJson {
match v {
Json::Array(vec) => {
let len = vec.len();
vec.get_mut(*self).unwrap_or_else(|| panic!("cannot access index {} of JSON array of length {}", self, len))
}
_ => panic!("cannot access index {} of JSON {:?}", self, v),
}
}
}
impl Index for str {
fn index_into<'v>(&self, v: &'v Json) -> Option<&'v RJson> {
match v {
Json::Object(map) => map.get(self),
_ => None,
}
}
fn index_into_mut<'v>(&self, v: &'v mut Json) -> Option<&'v mut RJson> {
match v {
Json::Object(map) => map.get_mut(self),
_ => None,
}
}
fn index_or_insert<'v>(&self, v: &'v mut Json) -> &'v mut RJson {
if let Json::Null = v {
*v = Json::Object(HashMap::new());
}
match v {
Json::Object(map) => map.entry(self.to_owned()).or_insert(RJson::new(Json::Null)),
_ => panic!("cannot access key {:?} in JSON {:?}", self, v),
}
}
}
impl Index for String {
fn index_into<'v>(&self, v: &'v Json) -> Option<&'v RJson> {
self[..].index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut Json) -> Option<&'v mut RJson> {
self[..].index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Json) -> &'v mut RJson {
self[..].index_or_insert(v)
}
}
impl<T> Index for &T
where
T: ?Sized + Index,
{
fn index_into<'v>(&self, v: &'v Json) -> Option<&'v RJson> {
(**self).index_into(v)
}
fn index_into_mut<'v>(&self, v: &'v mut Json) -> Option<&'v mut RJson> {
(**self).index_into_mut(v)
}
fn index_or_insert<'v>(&self, v: &'v mut Json) -> &'v mut RJson {
(**self).index_or_insert(v)
}
}
impl<I> ops::Index<I> for Json
where
I: Index,
{
type Output = RJson;
fn index(&self, index: I) -> &Self::Output {
index.index_into(self).unwrap_or(&RJSON_NULL)
}
}
impl<I> ops::IndexMut<I> for Json
where
I: Index,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
index.index_or_insert(self)
}
}
impl Json {
pub fn get_ptr_address(&self) -> usize {
self as *const Json as usize
}
pub fn index<I: Index>(&self, index: &I) -> RJson {
self[index].clone()
}
pub fn get<I: Index>(&self, index: &I) -> RJson {
self.index(index)
}
pub fn set<I: Index, V: Into<RJson>>(&mut self, index: &I, value: V) {
let value: RJson = value.into();
let value_json_ptr = value.get_json_ptr_address();
let old_value_json_ptr = self.index(&index).get_json_ptr_address();
crate::syn::effect::Effect::replace_target_ptr(old_value_json_ptr, value_json_ptr);
self[index] = value;
}
}
impl Drop for Json {
fn drop(&mut self) {
log::trace!("drop inner json address {:?}", self.get_ptr_address());
crate::syn::effect::Effect::remove_target_ptr(self.get_ptr_address());
}
}