checkleft 0.1.0-alpha.8

Experimental repository convention checker; API and behavior may change without notice
Documentation
use std::collections::BTreeMap;
use std::sync::Arc;

use anyhow::{Result, bail};
use async_trait::async_trait;

use crate::input::{ChangeSet, SourceTree};
use crate::output::CheckResult;

#[async_trait]
pub trait ConfiguredCheck: Send + Sync {
    async fn run(&self, changeset: &ChangeSet, tree: &dyn SourceTree) -> Result<CheckResult>;
}

#[async_trait]
pub trait Check: Send + Sync {
    fn id(&self) -> &str;

    fn description(&self) -> &str;

    fn configure(&self, config: &toml::Value) -> Result<Arc<dyn ConfiguredCheck>>;

    async fn run(
        &self,
        changeset: &ChangeSet,
        tree: &dyn SourceTree,
        config: &toml::Value,
    ) -> Result<CheckResult> {
        self.configure(config)?.run(changeset, tree).await
    }
}

#[derive(Default)]
pub struct CheckRegistry {
    checks: BTreeMap<String, Arc<dyn Check>>,
}

impl CheckRegistry {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn register<C>(&mut self, check: C) -> Result<()>
    where
        C: Check + 'static,
    {
        self.register_arc(Arc::new(check))
    }

    pub fn register_arc(&mut self, check: Arc<dyn Check>) -> Result<()> {
        let id = check.id().to_owned();
        if self.checks.contains_key(&id) {
            bail!("check already registered: {id}");
        }
        self.checks.insert(id, check);
        Ok(())
    }

    pub fn get(&self, id: &str) -> Option<Arc<dyn Check>> {
        self.checks.get(id).cloned()
    }

    pub fn list(&self) -> Vec<Arc<dyn Check>> {
        self.checks.values().cloned().collect()
    }
}