use std::path::Path;
use crate::kind::KindId;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct DetectMatch {
pub kind: KindId,
pub signals: Vec<String>,
}
pub trait Detector: Send + Sync {
fn kind(&self) -> KindId;
fn detect(&self, dir: &Path) -> Option<DetectMatch>;
fn priority(&self) -> i32 {
0
}
}
pub struct DetectorRegistry {
detectors: Vec<Box<dyn Detector>>,
}
impl DetectorRegistry {
pub fn empty() -> Self {
Self { detectors: Vec::new() }
}
pub fn with_builtins() -> Self {
let mut r = Self::empty();
crate::builtin::register_all(&mut r);
r
}
pub fn add(&mut self, d: impl Detector + 'static) -> &mut Self {
self.detectors.push(Box::new(d));
self
}
pub fn remove(&mut self, kind: &KindId) -> bool {
let before = self.detectors.len();
self.detectors.retain(|d| d.kind() != *kind);
self.detectors.len() != before
}
pub fn kinds(&self) -> Vec<KindId> {
self.detectors.iter().map(|d| d.kind()).collect()
}
pub fn detect(&self, dir: &Path) -> Option<DetectMatch> {
if !dir.is_dir() {
return None;
}
let mut best: Option<(i32, DetectMatch)> = None;
for d in &self.detectors {
if let Some(m) = d.detect(dir) {
let p = d.priority();
if best.as_ref().map_or(true, |(bp, _)| p > *bp) {
best = Some((p, m));
}
}
}
best.map(|(_, m)| m)
}
}
impl Default for DetectorRegistry {
fn default() -> Self {
Self::with_builtins()
}
}