use std::cell::RefCell;
pub use serde_json::Value;
use serde_json::{Map, json};
thread_local! {
static DERIVING: RefCell<Vec<&'static str>> = const { RefCell::new(Vec::new()) };
}
#[must_use]
pub fn derive(type_name: &'static str, describe: impl FnOnce() -> Value) -> Value {
struct Deriving;
impl Drop for Deriving {
fn drop(&mut self) {
DERIVING.with_borrow_mut(|stack| {
let _ = stack.pop();
});
}
}
let is_recursive = DERIVING.with_borrow_mut(|stack| {
if stack.contains(&type_name) {
return true;
}
stack.push(type_name);
false
});
assert!(
!is_recursive,
"architecturekit: {type_name} is recursive, so its schema can not be derived; implement Schema for it by hand",
);
let _deriving = Deriving;
describe()
}
#[must_use]
pub fn object(type_name: &'static str, fields: Vec<(&'static str, Value, bool)>) -> Value {
let mut properties = Map::new();
let mut required = Vec::new();
for (name, schema, is_optional) in fields {
assert!(
properties.insert(name.to_owned(), schema).is_none(),
"architecturekit: {type_name} writes the field {name} more than once, so its schema can not be derived",
);
if !is_optional {
required.push(Value::from(name));
}
}
let mut schema = json!({
"type": "object",
"properties": properties,
"additionalProperties": false,
});
if !required.is_empty() {
schema["required"] = Value::Array(required);
}
schema
}