use std::sync::Arc;
use serde::Serialize;
use tokio::process::ChildStdin;
use tokio::sync::Mutex;
use super::{Notification, Output};
#[derive(Clone)]
pub enum Handle {
Stdout,
Stdin(Arc<Mutex<ChildStdin>>),
Collect(Arc<Mutex<Vec<Output<serde_json::Value>>>>),
}
impl Default for Handle {
fn default() -> Self {
Handle::Stdout
}
}
impl Handle {
pub async fn emit<T: Serialize>(&self, output: &Output<T>) {
match self {
Handle::Stdout => {
let json = serde_json::to_string(output)
.expect("Output<T> serializes when T: Serialize");
println!("{json}");
if matches!(output, Output::Error(e) if e.fatal) {
eprintln!("{json}");
}
}
Handle::Stdin(stdin) => {
let json = serde_json::to_string(output)
.expect("Output<T> serializes when T: Serialize");
use tokio::io::AsyncWriteExt;
let mut guard = stdin.lock().await;
guard
.write_all(json.as_bytes())
.await
.expect("emit to child stdin failed");
guard
.write_all(b"\n")
.await
.expect("emit to child stdin failed");
}
Handle::Collect(vec) => {
let typed = match output {
Output::Error(e) => Output::Error(e.clone()),
Output::Notification(n) => Output::Notification(Notification {
value: serde_json::to_value(&n.value)
.expect("T serializes when T: Serialize"),
}),
Output::Begin => Output::Begin,
Output::End => Output::End,
};
vec.lock().await.push(typed);
}
}
}
}