use std::collections::HashMap;
use std::sync::Arc;
use crate::selector::Situation;
use crate::types::{Decision, EvaluatorSource};
#[derive(Debug, thiserror::Error)]
pub enum ExternalError {
#[error("evaluator kind '{0}' not registered")]
NotRegistered(String),
#[error("source resolution failed: {0}")]
SourceResolution(String),
#[error("evaluator failed: {0}")]
Execution(String),
#[error(transparent)]
Other(#[from] Box<dyn std::error::Error + Send + Sync>),
}
pub trait ExternalEvaluator: Send + Sync {
fn kind(&self) -> &'static str;
fn evaluate(
&self,
source: &EvaluatorSource,
situation: &Situation,
action: &str,
agent_id: &str,
) -> Result<Decision, ExternalError>;
}
#[derive(Default)]
pub struct ExternalEvaluatorRegistry {
impls: HashMap<&'static str, Arc<dyn ExternalEvaluator>>,
}
impl ExternalEvaluatorRegistry {
pub fn new() -> Self {
Self {
impls: HashMap::new(),
}
}
pub fn register(&mut self, eval: Arc<dyn ExternalEvaluator>) {
self.impls.insert(eval.kind(), eval);
}
pub fn get(&self, kind: &str) -> Option<&Arc<dyn ExternalEvaluator>> {
self.impls.get(kind)
}
pub fn kinds(&self) -> Vec<&'static str> {
self.impls.keys().copied().collect()
}
pub fn len(&self) -> usize {
self.impls.len()
}
pub fn is_empty(&self) -> bool {
self.impls.is_empty()
}
}
impl std::fmt::Debug for ExternalEvaluatorRegistry {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ExternalEvaluatorRegistry")
.field("kinds", &self.kinds())
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct MockRunner;
impl ExternalEvaluator for MockRunner {
fn kind(&self) -> &'static str {
"mock"
}
fn evaluate(
&self,
_source: &EvaluatorSource,
_situation: &Situation,
_action: &str,
_agent_id: &str,
) -> Result<Decision, ExternalError> {
Ok(Decision::NoPolicyMatch)
}
}
#[test]
fn registry_register_and_get() {
let mut reg = ExternalEvaluatorRegistry::new();
assert!(reg.is_empty());
reg.register(Arc::new(MockRunner));
assert_eq!(reg.len(), 1);
assert!(reg.get("mock").is_some());
assert!(reg.get("missing").is_none());
assert_eq!(reg.kinds(), vec!["mock"]);
}
}