use crate::domain::analysis_data::{FunctionRecord, ModuleCouplingRecord};
use crate::domain::findings::{
ArchitectureFinding, ComplexityFinding, CouplingFinding, DryFinding, IospFinding,
OrphanSuppression, SrpFinding, TqFinding,
};
mod sealed {
pub trait Sealed: Send + Sync {}
}
pub trait Reporter: sealed::Sealed + Send + Sync {
type Output;
fn render(
&self,
findings: &crate::domain::AnalysisFindings,
data: &crate::domain::AnalysisData,
) -> Self::Output;
}
pub trait ReporterImpl: Sized + sealed::Sealed + Send + Sync {
type Output;
type IospView;
type ComplexityView;
type DryView;
type SrpView;
type CouplingView;
type TestQualityView;
type ArchitectureView;
type OrphanView;
type IospDataView;
type ComplexityDataView;
type CouplingDataView;
fn build_iosp(&self, findings: &[IospFinding]) -> Self::IospView;
fn build_complexity(&self, findings: &[ComplexityFinding]) -> Self::ComplexityView;
fn build_dry(&self, findings: &[DryFinding]) -> Self::DryView;
fn build_srp(&self, findings: &[SrpFinding]) -> Self::SrpView;
fn build_coupling(&self, findings: &[CouplingFinding]) -> Self::CouplingView;
fn build_test_quality(&self, findings: &[TqFinding]) -> Self::TestQualityView;
fn build_architecture(&self, findings: &[ArchitectureFinding]) -> Self::ArchitectureView;
fn build_orphans(&self, suppressions: &[OrphanSuppression]) -> Self::OrphanView;
fn build_iosp_data(&self, fns: &[FunctionRecord]) -> Self::IospDataView;
fn build_complexity_data(&self, fns: &[FunctionRecord]) -> Self::ComplexityDataView;
fn build_coupling_data(&self, mods: &[ModuleCouplingRecord]) -> Self::CouplingDataView;
fn publish(&self, snapshot: Snapshot<Self>) -> Self::Output;
}
pub struct Snapshot<R: ReporterImpl> {
pub(crate) iosp: R::IospView,
pub(crate) complexity: R::ComplexityView,
pub(crate) dry: R::DryView,
pub(crate) srp: R::SrpView,
pub(crate) coupling: R::CouplingView,
pub(crate) test_quality: R::TestQualityView,
pub(crate) architecture: R::ArchitectureView,
pub(crate) orphans: R::OrphanView,
pub(crate) iosp_data: R::IospDataView,
pub(crate) complexity_data: R::ComplexityDataView,
pub(crate) coupling_data: R::CouplingDataView,
}
impl<T: ReporterImpl> sealed::Sealed for T {}
impl<T: ReporterImpl> Reporter for T {
type Output = <T as ReporterImpl>::Output;
fn render(
&self,
findings: &crate::domain::AnalysisFindings,
data: &crate::domain::AnalysisData,
) -> Self::Output {
let snapshot = Snapshot {
iosp: self.build_iosp(&findings.iosp),
complexity: self.build_complexity(&findings.complexity),
dry: self.build_dry(&findings.dry),
srp: self.build_srp(&findings.srp),
coupling: self.build_coupling(&findings.coupling),
test_quality: self.build_test_quality(&findings.test_quality),
architecture: self.build_architecture(&findings.architecture),
orphans: self.build_orphans(&findings.orphan_suppressions),
iosp_data: self.build_iosp_data(&data.functions),
complexity_data: self.build_complexity_data(&data.functions),
coupling_data: self.build_coupling_data(&data.modules),
};
self.publish(snapshot)
}
}
#[derive(Debug, thiserror::Error)]
pub enum ReportError {
#[error("i/o error writing report: {0}")]
Io(String),
#[error("encoding error: {0}")]
Encoding(String),
}