use std::borrow::Cow;
use std::cell::Ref;
use jsonschema::json::{Array, Json, JsonNumber, Node, NodeIdentity, Object};
use jsonschema::JsonType;
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use self_cell::self_cell;
use serde_json::Value;
use typed_arena::Arena;
use zen_types::variable::{MapIter, RcCell, Variable, VariableMap};
pub struct VariableJson;
type MapRef<'a> = Ref<'a, VariableMap>;
type VecRef<'a> = Ref<'a, Vec<Variable>>;
self_cell!(
struct MapGuard {
owner: RcCell<VariableMap>,
#[covariant]
dependent: MapRef,
}
);
self_cell!(
struct VecGuard {
owner: RcCell<Vec<Variable>>,
#[covariant]
dependent: VecRef,
}
);
pub struct Guards {
objects: Arena<MapGuard>,
arrays: Arena<VecGuard>,
}
impl Default for Guards {
fn default() -> Self {
Self {
objects: Arena::new(),
arrays: Arena::new(),
}
}
}
#[derive(Clone, Copy)]
pub struct VariableNode<'a> {
var: &'a Variable,
guards: &'a Guards,
}
impl<'a> VariableNode<'a> {
pub fn new(var: &'a Variable, guards: &'a Guards) -> Self {
Self { var, guards }
}
}
impl Json for VariableJson {
type Node<'a> = VariableNode<'a>;
type PreparedKey = Box<str>;
type StringBuffer = Variable;
fn prepare_key(key: &str) -> Box<str> {
Box::from(key)
}
fn with_string_node<T>(
buffer: &mut Variable,
string: &str,
f: impl FnOnce(VariableNode<'_>) -> T,
) -> T {
*buffer = Variable::String((string).into());
let guards = Guards::default();
f(VariableNode::new(buffer, &guards))
}
}
pub struct VariableNumber(Decimal);
impl JsonNumber for VariableNumber {
fn as_u64(&self) -> Option<u64> {
self.0.is_integer().then(|| self.0.to_u64()).flatten()
}
fn as_i64(&self) -> Option<i64> {
self.0.is_integer().then(|| self.0.to_i64()).flatten()
}
fn as_f64(&self) -> Option<f64> {
self.0.to_f64()
}
fn as_str(&self) -> Cow<'_, str> {
Cow::Owned(self.0.normalize().to_string())
}
fn to_number(&self) -> Cow<'_, serde_json::Number> {
let normalized = self.0.normalize().to_string();
#[cfg(feature = "arbitrary_precision")]
let number = serde_json::Number::from_string_unchecked(normalized);
#[cfg(not(feature = "arbitrary_precision"))]
let number = normalized
.parse()
.ok()
.or_else(|| self.0.to_f64().and_then(serde_json::Number::from_f64))
.unwrap_or_else(|| serde_json::Number::from(0));
Cow::Owned(number)
}
}
impl<'a> Node<'a, VariableJson> for VariableNode<'a> {
type Object = ObjectNode<'a>;
type Array = ArrayNode<'a>;
type Number = VariableNumber;
fn as_object(&self) -> Option<ObjectNode<'a>> {
let Variable::Object(cell) = self.var else {
return None;
};
let guard = self
.guards
.objects
.alloc(MapGuard::new(cell.clone(), |cell| cell.borrow()));
Some(ObjectNode {
map: guard.borrow_dependent(),
guards: self.guards,
})
}
fn as_array(&self) -> Option<ArrayNode<'a>> {
let Variable::Array(cell) = self.var else {
return None;
};
let guard = self
.guards
.arrays
.alloc(VecGuard::new(cell.clone(), |cell| cell.borrow()));
Some(ArrayNode {
items: guard.borrow_dependent().as_slice(),
guards: self.guards,
})
}
fn as_string(&self) -> Option<Cow<'a, str>> {
match self.var {
Variable::String(string) => Some(Cow::Borrowed(string.as_str())),
Variable::Dynamic(dynamic) => Some(Cow::Owned(dynamic.to_string())),
_ => None,
}
}
fn as_number(&self) -> Option<VariableNumber> {
match self.var {
Variable::Number(number) => Some(VariableNumber(*number)),
_ => None,
}
}
fn as_boolean(&self) -> Option<bool> {
match self.var {
Variable::Bool(boolean) => Some(*boolean),
_ => None,
}
}
fn is_null(&self) -> bool {
matches!(self.var, Variable::Null)
}
fn json_type(&self) -> JsonType {
match self.var {
Variable::Null => JsonType::Null,
Variable::Bool(_) => JsonType::Boolean,
Variable::Number(_) => JsonType::Number,
Variable::String(_) => JsonType::String,
Variable::Array(_) => JsonType::Array,
Variable::Object(_) => JsonType::Object,
Variable::Dynamic(_) => JsonType::String,
}
}
fn to_value(&self) -> Cow<'a, Value> {
Cow::Owned(Variable::to_value(self.var))
}
fn identity(&self) -> Option<NodeIdentity> {
Some(NodeIdentity::new(
std::ptr::from_ref::<Variable>(self.var) as usize
))
}
}
pub struct ObjectNode<'a> {
map: &'a VariableMap,
guards: &'a Guards,
}
impl<'a> Object<'a, VariableJson> for ObjectNode<'a> {
type Node = VariableNode<'a>;
type MemberName = &'a str;
type MembersIter = VariableMembersIter<'a>;
fn len(&self) -> usize {
self.map.len()
}
fn get(&self, key: &Box<str>) -> Option<VariableNode<'a>> {
self.map
.get_str(key)
.map(|var| VariableNode::new(var, self.guards))
}
fn members(&self) -> VariableMembersIter<'a> {
VariableMembersIter {
iter: self.map.iter(),
guards: self.guards,
}
}
}
pub struct VariableMembersIter<'a> {
iter: MapIter<'a>,
guards: &'a Guards,
}
impl<'a> Iterator for VariableMembersIter<'a> {
type Item = (&'a str, VariableNode<'a>);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|(name, value)| (name.as_str(), VariableNode::new(value, self.guards)))
}
}
pub struct ArrayNode<'a> {
items: &'a [Variable],
guards: &'a Guards,
}
impl<'a> Array<'a, VariableJson> for ArrayNode<'a> {
type Node = VariableNode<'a>;
type ElementsIter = VariableElementsIter<'a>;
fn len(&self) -> usize {
self.items.len()
}
fn elements(&self) -> VariableElementsIter<'a> {
VariableElementsIter {
iter: self.items.iter(),
guards: self.guards,
}
}
}
pub struct VariableElementsIter<'a> {
iter: std::slice::Iter<'a, Variable>,
guards: &'a Guards,
}
impl<'a> Iterator for VariableElementsIter<'a> {
type Item = VariableNode<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
.map(|var| VariableNode::new(var, self.guards))
}
}