use std::any::Any;
use std::sync::Arc;
use rtb_config::Config;
pub type ErasedConfig = Arc<dyn Any + Send + Sync>;
#[must_use]
pub fn erase<C>(config: Config<C>) -> ErasedConfig
where
C: serde::de::DeserializeOwned + Send + Sync + 'static,
{
Arc::new(config)
}
type RenderValueFn =
Box<dyn Fn(&(dyn Any + Send + Sync)) -> Option<serde_json::Value> + Send + Sync>;
pub struct TypedConfigOps {
pub schema: serde_json::Value,
render_value: RenderValueFn,
}
impl std::fmt::Debug for TypedConfigOps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TypedConfigOps")
.field("schema", &self.schema)
.field("render_value", &"<closure>")
.finish()
}
}
impl TypedConfigOps {
#[must_use]
pub fn new<C>() -> Self
where
C: serde::Serialize
+ serde::de::DeserializeOwned
+ schemars::JsonSchema
+ Send
+ Sync
+ 'static,
{
let mut generator = schemars::SchemaGenerator::default();
let schema = generator.root_schema_for::<C>();
let schema_value = serde_json::to_value(schema).unwrap_or(serde_json::Value::Null);
Self {
schema: schema_value,
render_value: Box::new(|any: &(dyn Any + Send + Sync)| -> Option<serde_json::Value> {
let typed = any.downcast_ref::<Config<C>>()?;
let value = typed.get();
serde_json::to_value(&*value).ok()
}),
}
}
#[must_use]
pub fn render(&self, erased: &ErasedConfig) -> Option<serde_json::Value> {
let any: &(dyn Any + Send + Sync) = erased.as_ref();
(self.render_value)(any)
}
}