Documentation
pub mod json;

use json::Json;
use std::{
    fmt::Debug,
    ops::{Deref, DerefMut},
    sync::{Arc, Mutex},
};

#[derive(Debug, Clone)]
pub struct RJson(Arc<Mutex<Json>>);

impl From<RJson> for Json {
    fn from(value: RJson) -> Self {
        let json = value.0.lock().unwrap();
        (*json).clone()
    }
}
impl From<Json> for RJson {
    fn from(value: Json) -> Self {
        Self(Arc::new(Mutex::new(value)))
    }
}
impl From<serde_json::Value> for RJson {
    fn from(value: serde_json::Value) -> Self {
        let json: Json = value.into();
        json.into()
    }
}
impl From<RJson> for serde_json::Value {
    fn from(value: RJson) -> Self {
        let json: Json = value.into();
        json.into()
    }
}

impl Deref for RJson {
    type Target = Arc<Mutex<Json>>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
impl DerefMut for RJson {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl core::hash::Hash for RJson {
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
        self.get_json_ptr_address().hash(state);
    }
}
impl PartialEq for RJson {
    fn eq(&self, other: &Self) -> bool {
        self.get_json_ptr_address() == other.get_json_ptr_address()
    }
}
impl Eq for RJson {}

impl RJson {
    pub fn new<T: Into<Json>>(value: T) -> Self {
        let json: Json = value.into();
        Self(Arc::new(Mutex::new(json)))
    }
    pub fn get_json_ptr_address(&self) -> usize {
        let json = self.0.lock().unwrap();
        json.get_ptr_address()
    }
    pub fn index<I: json::Index>(&self, index: I) -> RJson {
        let json = self.0.lock().unwrap();
        json[index].clone()
    }
    pub fn get<I: json::Index + ToString + Clone>(&self, index: I) -> RJson {
        // track
        crate::effect::Effect::track(self.get_json_ptr_address(), &index);
        self.index(&index)
    }
    pub fn set<I: json::Index + ToString + Clone + Debug, V: Into<serde_json::Value>>(&self, index: I, value: V) {
        let value: serde_json::Value = value.into();
        let value: RJson = value.into();
        self.0.lock().unwrap().set(&index, value);
        crate::effect::Effect::trigger(self.get_json_ptr_address(), &index);
    }
}