use super::EvaluatorMessage;
use crate::ast::Expr;
use crate::diagnostics::{Result, Span};
use crate::eval::Value;
use crate::module_system::ImportSpec;
use crossbeam::channel::{self, Sender};
use std::collections::HashMap;
use std::thread::ThreadId;
type SendError = Box<crossbeam::channel::SendError<EvaluatorMessage>>;
#[derive(Debug)]
pub struct EvaluatorHandle {
pub thread_id: ThreadId,
pub sender: Sender<EvaluatorMessage>,
pub id: u64,
}
impl EvaluatorHandle {
pub fn new(thread_id: ThreadId, sender: Sender<EvaluatorMessage>, id: u64) -> Self {
Self {
thread_id,
sender,
id,
}
}
pub fn thread_id(&self) -> ThreadId {
self.thread_id
}
pub fn id(&self) -> u64 {
self.id
}
pub fn send(&self, message: EvaluatorMessage) -> std::result::Result<(), SendError> {
self.sender.send(message).map_err(Box::new)
}
pub async fn eval(&self, expr: Expr, span: Option<Span>) -> Result<Value> {
let (sender, receiver) = channel::bounded(1);
let message = EvaluatorMessage::Evaluate {
expr,
span,
sender,
};
self.sender.send(message).map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to send evaluation message: {e}"),
span,
)
})?;
receiver.recv().map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to receive evaluation result: {e}"),
span,
)
})?
}
pub fn define_global(&self, name: String, value: Value) -> Result<()> {
let message = EvaluatorMessage::DefineGlobal { name, value };
self.sender.send(message).map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to send define message: {e}"),
None,
).boxed()
})
}
pub async fn import_module(&self, import_spec: ImportSpec) -> Result<HashMap<String, Value>> {
let (sender, receiver) = channel::bounded(1);
let message = EvaluatorMessage::ImportModule {
import_spec,
sender,
};
self.sender.send(message).map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to send import message: {e}"),
None,
)
})?;
receiver.recv().map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to receive import result: {e}"),
None,
)
})?
}
pub fn shutdown(&self) -> Result<()> {
self.sender.send(EvaluatorMessage::Shutdown).map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to send shutdown message: {e}"),
None,
).boxed()
})
}
}