use std::error::Error;
use erased_serde::Deserializer;
use git_checks_core::{BranchCheck, Check, TopicCheck};
use serde::de::DeserializeOwned;
pub trait IntoCheck: DeserializeOwned {
type Check;
fn into_check(self) -> Self::Check;
}
type CtorResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
#[doc(hidden)]
pub struct CheckCtor<T> {
pub f: fn(&mut dyn Deserializer) -> CtorResult<T>,
}
#[doc(hidden)]
pub trait CheckConfig {
type CheckTrait: ?Sized;
}
pub struct BranchCheckConfig {
name: &'static str,
ctor: CheckCtor<DynBranchCheck>,
}
#[doc(hidden)]
pub struct DynBranchCheck(Box<dyn BranchCheck>);
impl BranchCheckConfig {
#[doc(hidden)]
pub const fn new(name: &'static str, ctor: CheckCtor<DynBranchCheck>) -> Self {
Self {
name,
ctor,
}
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn BranchCheck>> {
Ok((self.ctor.f)(conf)?.0)
}
#[doc(hidden)]
pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynBranchCheck>
where
C: IntoCheck,
C::Check: BranchCheck + 'static,
{
erased_serde::deserialize(conf)
.map(|c: C| DynBranchCheck(Box::new(c.into_check())))
.map_err(Into::into)
}
}
impl CheckConfig for BranchCheckConfig {
type CheckTrait = dyn BranchCheck;
}
pub struct CommitCheckConfig {
name: &'static str,
ctor: CheckCtor<DynCheck>,
}
#[doc(hidden)]
pub struct DynCheck(Box<dyn Check>);
impl CommitCheckConfig {
#[doc(hidden)]
pub const fn new(name: &'static str, ctor: CheckCtor<DynCheck>) -> Self {
Self {
name,
ctor,
}
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn Check>> {
Ok((self.ctor.f)(conf)?.0)
}
#[doc(hidden)]
pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynCheck>
where
C: IntoCheck,
C::Check: Check + 'static,
{
erased_serde::deserialize(conf)
.map(|c: C| DynCheck(Box::new(c.into_check())))
.map_err(Into::into)
}
}
impl CheckConfig for CommitCheckConfig {
type CheckTrait = dyn Check;
}
pub struct TopicCheckConfig {
name: &'static str,
ctor: CheckCtor<DynTopicCheck>,
}
#[doc(hidden)]
pub struct DynTopicCheck(Box<dyn TopicCheck>);
impl TopicCheckConfig {
#[doc(hidden)]
pub const fn new(name: &'static str, ctor: CheckCtor<DynTopicCheck>) -> Self {
Self {
name,
ctor,
}
}
pub fn name(&self) -> &'static str {
self.name
}
pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn TopicCheck>> {
Ok((self.ctor.f)(conf)?.0)
}
#[doc(hidden)]
pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynTopicCheck>
where
C: IntoCheck,
C::Check: TopicCheck + 'static,
{
erased_serde::deserialize(conf)
.map(|c: C| DynTopicCheck(Box::new(c.into_check())))
.map_err(Into::into)
}
}
impl CheckConfig for TopicCheckConfig {
type CheckTrait = dyn TopicCheck;
}
inventory::collect!(BranchCheckConfig);
inventory::collect!(CommitCheckConfig);
inventory::collect!(TopicCheckConfig);