Skip to main content

assay_core/mcp/decision_next/
emitters.rs

1use super::event_types::DecisionEvent;
2use std::io::Write;
3
4/// Trait for emitting decision events.
5pub trait DecisionEmitter: Send + Sync {
6    /// Emit a decision event.
7    fn emit(&self, event: &DecisionEvent);
8}
9
10/// File-based decision emitter (NDJSON).
11pub struct FileDecisionEmitter {
12    file: std::sync::Mutex<std::fs::File>,
13}
14
15impl FileDecisionEmitter {
16    /// Create a new file emitter.
17    pub fn new(path: &std::path::Path) -> std::io::Result<Self> {
18        let file = std::fs::OpenOptions::new()
19            .create(true)
20            .append(true)
21            .open(path)?;
22        Ok(Self {
23            file: std::sync::Mutex::new(file),
24        })
25    }
26}
27
28impl DecisionEmitter for FileDecisionEmitter {
29    fn emit(&self, event: &DecisionEvent) {
30        if let Ok(json) = serde_json::to_string(event) {
31            if let Ok(mut f) = self.file.lock() {
32                let _ = writeln!(f, "{}", json);
33            }
34        }
35    }
36}
37
38/// Null emitter for testing.
39pub struct NullDecisionEmitter;
40
41impl DecisionEmitter for NullDecisionEmitter {
42    fn emit(&self, _event: &DecisionEvent) {}
43}