git_checks_config/
registry.rs

1// Copyright Kitware, Inc.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use std::error::Error;
10
11use erased_serde::Deserializer;
12use git_checks_core::{BranchCheck, Check, TopicCheck};
13use serde::de::DeserializeOwned;
14
15/// Trait for a deserialization structure of a check.
16///
17/// This trait should be implemented for any structure which can be deserialized and construct a
18/// check.
19pub trait IntoCheck: DeserializeOwned {
20    /// The check parsed by this configuration.
21    type Check;
22
23    /// Create a new instance of the check from the configuration.
24    fn into_check(self) -> Self::Check;
25}
26
27type CtorResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
28
29/// A constructor for a check from a deserialization structure.
30///
31/// This structure should only be created by the `register_checks` macro.
32#[doc(hidden)]
33pub struct CheckCtor<T> {
34    pub f: fn(&mut dyn Deserializer) -> CtorResult<T>,
35}
36
37/// Internal trait for use by the `register_checks` macro implementation.
38#[doc(hidden)]
39pub trait CheckConfig {
40    type CheckTrait: ?Sized;
41}
42
43/// Registry type for branch checks.
44///
45/// Query `inventory` using this type to find all branch checks.
46pub struct BranchCheckConfig {
47    name: &'static str,
48    ctor: CheckCtor<DynBranchCheck>,
49}
50
51/// Internal type for use by the `register_checks` macro implementation.
52#[doc(hidden)]
53pub struct DynBranchCheck(Box<dyn BranchCheck>);
54
55impl BranchCheckConfig {
56    /// This structure should only be created by the `register_checks` macro.
57    #[doc(hidden)]
58    pub const fn new(name: &'static str, ctor: CheckCtor<DynBranchCheck>) -> Self {
59        Self {
60            name,
61            ctor,
62        }
63    }
64
65    /// The name of the branch check.
66    pub fn name(&self) -> &'static str {
67        self.name
68    }
69
70    /// Create an instance of this check from a deserialization structure.
71    pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn BranchCheck>> {
72        Ok((self.ctor.f)(conf)?.0)
73    }
74
75    /// Internal function for use by the `register_checks` macro implementation.
76    #[doc(hidden)]
77    pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynBranchCheck>
78    where
79        C: IntoCheck,
80        C::Check: BranchCheck + 'static,
81    {
82        erased_serde::deserialize(conf)
83            .map(|c: C| DynBranchCheck(Box::new(c.into_check())))
84            .map_err(Into::into)
85    }
86}
87
88impl CheckConfig for BranchCheckConfig {
89    type CheckTrait = dyn BranchCheck;
90}
91
92/// Registry type for commit checks.
93///
94/// Query `inventory` using this type to find all commit checks.
95pub struct CommitCheckConfig {
96    name: &'static str,
97    ctor: CheckCtor<DynCheck>,
98}
99
100/// Internal type for use by the `register_checks` macro implementation.
101#[doc(hidden)]
102pub struct DynCheck(Box<dyn Check>);
103
104impl CommitCheckConfig {
105    /// This structure should only be created by the `register_checks` macro.
106    #[doc(hidden)]
107    pub const fn new(name: &'static str, ctor: CheckCtor<DynCheck>) -> Self {
108        Self {
109            name,
110            ctor,
111        }
112    }
113
114    /// The name of the commit check.
115    pub fn name(&self) -> &'static str {
116        self.name
117    }
118
119    /// Create an instance of this check from a deserialization structure.
120    pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn Check>> {
121        Ok((self.ctor.f)(conf)?.0)
122    }
123
124    /// Internal function for use by the `register_checks` macro implementation.
125    #[doc(hidden)]
126    pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynCheck>
127    where
128        C: IntoCheck,
129        C::Check: Check + 'static,
130    {
131        erased_serde::deserialize(conf)
132            .map(|c: C| DynCheck(Box::new(c.into_check())))
133            .map_err(Into::into)
134    }
135}
136
137impl CheckConfig for CommitCheckConfig {
138    type CheckTrait = dyn Check;
139}
140
141/// Registry type for topic checks.
142///
143/// Query `inventory` using this type to find all topic checks.
144pub struct TopicCheckConfig {
145    name: &'static str,
146    ctor: CheckCtor<DynTopicCheck>,
147}
148
149/// Internal type for use by the `register_checks` macro implementation.
150#[doc(hidden)]
151pub struct DynTopicCheck(Box<dyn TopicCheck>);
152
153impl TopicCheckConfig {
154    /// This structure should only be created by the `register_checks` macro.
155    #[doc(hidden)]
156    pub const fn new(name: &'static str, ctor: CheckCtor<DynTopicCheck>) -> Self {
157        Self {
158            name,
159            ctor,
160        }
161    }
162
163    /// The name of the topic check.
164    pub fn name(&self) -> &'static str {
165        self.name
166    }
167
168    /// Create an instance of this check from a deserialization structure.
169    pub fn create(&self, conf: &mut dyn Deserializer) -> CtorResult<Box<dyn TopicCheck>> {
170        Ok((self.ctor.f)(conf)?.0)
171    }
172
173    /// Internal function for use by the `register_checks` macro implementation.
174    #[doc(hidden)]
175    pub fn ctor<C>(conf: &mut dyn Deserializer) -> CtorResult<DynTopicCheck>
176    where
177        C: IntoCheck,
178        C::Check: TopicCheck + 'static,
179    {
180        erased_serde::deserialize(conf)
181            .map(|c: C| DynTopicCheck(Box::new(c.into_check())))
182            .map_err(Into::into)
183    }
184}
185
186impl CheckConfig for TopicCheckConfig {
187    type CheckTrait = dyn TopicCheck;
188}
189
190inventory::collect!(BranchCheckConfig);
191inventory::collect!(CommitCheckConfig);
192inventory::collect!(TopicCheckConfig);