use std::collections::HashMap;
use std::sync::Arc;
use serde_json::{Map, Value};
#[derive(Default)]
pub(crate) struct Schemas {
tools: HashMap<String, Arc<Value>>,
verdicts: HashMap<String, Arc<Map<String, Value>>>,
checked: HashMap<usize, Option<Result<(), String>>>,
}
impl Schemas {
pub(super) fn tool(&mut self, schema: &Arc<Value>) -> Arc<Value> {
let kept = shared(&mut self.tools, schema);
self.checked.entry(address(&kept)).or_default();
kept
}
pub(super) fn verdict(&mut self, schema: &Arc<Map<String, Value>>) -> Arc<Map<String, Value>> {
let kept = shared(&mut self.verdicts, schema);
self.checked.entry(address(&kept)).or_default();
kept
}
pub(super) fn check<T>(
&mut self,
schema: &Arc<T>,
check: impl FnOnce(&T) -> Result<(), String>,
) -> Result<(), String> {
match self.checked.get_mut(&address(schema)) {
Some(checked) => checked.get_or_insert_with(|| check(schema)).clone(),
None => check(schema),
}
}
}
fn address<T>(schema: &Arc<T>) -> usize {
Arc::as_ptr(schema).cast::<()>() as usize
}
fn shared<T: serde::Serialize>(kept: &mut HashMap<String, Arc<T>>, schema: &Arc<T>) -> Arc<T> {
let text = serde_json::to_string(&**schema).expect("a schema is JSON");
kept.entry(text).or_insert_with(|| schema.clone()).clone()
}