myko/core/report/
registration.rs1use std::{any::Any, sync::Arc};
4
5use hyphae::{Cell, CellImmutable, MapExt};
6use serde_json::Value;
7
8use super::{
9 handler::{ReportContext, ReportHandler},
10 request::ReportRequest,
11 traits::{AnyReport, ReportParams},
12};
13use crate::{common::to_value::ToValue, request::RequestContext, server::CellServerCtx};
14
15pub trait AnyOutput: ToValue + std::fmt::Debug + Send + Sync + 'static {
22 fn as_any(&self) -> &dyn Any;
23 fn equals(&self, other: &dyn AnyOutput) -> bool;
24}
25
26impl<T: ToValue + std::fmt::Debug + PartialEq + Send + Sync + 'static> AnyOutput for T {
28 fn as_any(&self) -> &dyn Any {
29 self
30 }
31
32 fn equals(&self, other: &dyn AnyOutput) -> bool {
33 other
34 .as_any()
35 .downcast_ref::<Self>()
36 .map(|typed| self == typed)
37 .unwrap_or(false)
38 }
39}
40
41impl PartialEq for dyn AnyOutput {
42 fn eq(&self, other: &Self) -> bool {
43 self.equals(other)
44 }
45}
46
47pub type ReportParseFn = fn(Value) -> Result<Arc<dyn AnyReport>, anyhow::Error>;
53
54pub type ReportCellFactory = fn(
57 Arc<dyn AnyReport>,
58 Arc<RequestContext>,
59 Arc<CellServerCtx>,
60) -> Result<Cell<Arc<dyn AnyOutput>, CellImmutable>, String>;
61
62inventory::collect!(ReportRegistration);
67
68pub struct ReportRegistration {
71 pub report_id: &'static str,
73 pub crate_name: &'static str,
75 pub output_type: &'static str,
77 pub output_type_crate: &'static str,
79 pub parse: ReportParseFn,
81 pub cell_factory: ReportCellFactory,
83}
84
85pub trait ReportFactory: ReportParams {
94 fn parse(value: Value) -> Result<Arc<dyn AnyReport>, anyhow::Error>;
96
97 fn cell_factory(
99 report: Arc<dyn AnyReport>,
100 request_ctx: Arc<RequestContext>,
101 server_ctx: Arc<CellServerCtx>,
102 ) -> Result<Cell<Arc<dyn AnyOutput>, CellImmutable>, String>;
103}
104
105impl<R: ReportParams> ReportFactory for R {
106 fn parse(value: Value) -> Result<Arc<dyn AnyReport>, anyhow::Error> {
107 let report = serde_json::from_value::<ReportRequest<R>>(value)?;
108 Ok(Arc::new(report))
109 }
110
111 fn cell_factory(
112 any_report: Arc<dyn AnyReport>,
113 request_ctx: Arc<RequestContext>,
114 server_ctx: Arc<CellServerCtx>,
115 ) -> Result<Cell<Arc<dyn AnyOutput>, CellImmutable>, String> {
116 let any_ref: &dyn Any = any_report.as_ref();
118 let request: ReportRequest<R> = any_ref
119 .downcast_ref::<ReportRequest<R>>()
120 .cloned()
121 .ok_or_else(|| {
122 format!(
123 "Failed to downcast report to ReportRequest<{}>",
124 R::report_id_static()
125 )
126 })?;
127
128 let ctx = ReportContext::new(request_ctx, server_ctx);
130
131 let report_id = R::report_id_static();
133 let cell = <R as ReportHandler>::compute(&request.report, ctx);
134
135 let report_name = format!("report:{}", report_id);
137 Ok(cell
138 .map(|output| output.clone() as Arc<dyn AnyOutput>)
139 .with_name(report_name.as_str()))
140 }
141}