use std::{any::Any, sync::Arc};
use serde::de::DeserializeOwned;
use serde_json::Value;
use super::{
cell::{FilteredViewCellMap, erase_typed_view_map},
context::{ViewCellContext, ViewContext},
request::ViewRequest,
traits::{
AnyView, ViewBuildCellCtx, ViewHandler, ViewId, ViewIdStatic, ViewItemType, ViewParams,
},
};
use crate::{
common::with_id::WithId, item::Eventable, request::RequestContext, server::CellServerCtx,
store::StoreRegistry,
};
pub type ViewParseFn = fn(Value) -> Result<Arc<dyn AnyView>, anyhow::Error>;
pub type ViewCellFactory = fn(
Arc<dyn AnyView>,
Arc<StoreRegistry>,
Arc<RequestContext>,
Arc<CellServerCtx>,
) -> Result<FilteredViewCellMap, String>;
pub struct ViewRegistration {
pub view_id: &'static str,
pub view_item_type: &'static str,
pub crate_name: &'static str,
pub parse: ViewParseFn,
pub cell_factory: ViewCellFactory,
}
inventory::collect!(ViewRegistration);
pub trait ViewFactory: ViewParams {
fn parse(value: Value) -> Result<Arc<dyn AnyView>, anyhow::Error>;
fn cell_factory(
view: Arc<dyn AnyView>,
registry: Arc<StoreRegistry>,
request_ctx: Arc<RequestContext>,
server_ctx: Arc<CellServerCtx>,
) -> Result<FilteredViewCellMap, String>;
}
impl<V> ViewFactory for V
where
V: ViewParams
+ ViewId
+ ViewIdStatic
+ ViewItemType
+ ViewHandler
+ std::fmt::Debug
+ DeserializeOwned,
<V as ViewItemType>::Item:
Eventable + WithId + DeserializeOwned + Clone + std::fmt::Debug + Send + Sync + 'static,
{
fn parse(value: Value) -> Result<Arc<dyn AnyView>, anyhow::Error> {
log::trace!("ViewFactory::parse view_id={}", V::view_id_static());
let view = serde_json::from_value::<ViewRequest<V>>(value)?;
Ok(Arc::new(view))
}
fn cell_factory(
any_view: Arc<dyn AnyView>,
registry: Arc<StoreRegistry>,
request_ctx: Arc<RequestContext>,
server_ctx: Arc<CellServerCtx>,
) -> Result<FilteredViewCellMap, String> {
log::trace!(
"ViewFactory::cell_factory start view_id={}",
V::view_id_static()
);
let any_ref: &dyn Any = any_view.as_ref();
let request: ViewRequest<V> = any_ref
.downcast_ref::<ViewRequest<V>>()
.cloned()
.ok_or_else(|| "Failed to downcast view payload".to_string())?;
let view: Arc<V> = Arc::new(request.view);
let view_ctx = Arc::new(ViewContext::new(
request_ctx.clone(),
registry.clone(),
server_ctx.clone(),
));
let view_cell_ctx =
ViewCellContext::new(request_ctx, view_ctx, registry.clone(), server_ctx);
let built = V::build_cell(ViewBuildCellCtx {
view: view.clone(),
view_context: view_cell_ctx.clone(),
});
log::trace!(
"ViewFactory::cell_factory using build_cell view_id={}",
V::view_id_static()
);
Ok(erase_typed_view_map(built))
}
}