use arc_gc::gc::GC;
use crate::{
lambda::runnable::{Runnable, RuntimeError, StepResult},
types::{
object::{OnionObject, OnionObjectCell},
pair::OnionPair,
},
unwrap_step_result,
};
pub struct AsyncScheduler {
pub(crate) runnables: Vec<Box<dyn Runnable>>,
}
impl AsyncScheduler {
pub fn new(runnables: Vec<Box<dyn Runnable>>) -> Self {
AsyncScheduler { runnables }
}
}
impl Runnable for AsyncScheduler {
fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
if self.runnables.is_empty() {
return StepResult::Return(
OnionPair::new_static(
&OnionObject::Boolean(true).stabilize(),
&OnionObject::Undefined(Some("All runnables completed".to_string().into()))
.stabilize(),
)
.into(),
);
}
let mut i = 0;
while i < self.runnables.len() {
match self.runnables[i].step(gc) {
StepResult::Continue => {
i += 1; }
StepResult::NewRunnable(new_runnable) => {
self.runnables.push(new_runnable);
unwrap_step_result!(self.runnables[i].receive(
&StepResult::Return(
OnionObject::Undefined(Some("Task Launched".to_string().into()))
.stabilize()
.into(),
),
gc,
));
i += 1; }
StepResult::ReplaceRunnable(new_runnable) => {
self.runnables[i] = new_runnable;
i += 1; }
StepResult::Return(_) => {
self.runnables.remove(i);
}
e => return e,
}
}
StepResult::Continue
}
fn receive(
&mut self,
_step_result: &StepResult,
_gc: &mut GC<OnionObjectCell>,
) -> Result<(), RuntimeError> {
Err(RuntimeError::DetailedError(
"AsyncScheduler does not support receive".to_string().into(),
))
}
fn copy(&self) -> Box<dyn Runnable> {
Box::new(AsyncScheduler {
runnables: self.runnables.iter().map(|r| r.copy()).collect(),
})
}
fn format_context(&self) -> Result<serde_json::Value, RuntimeError> {
let mut tasks_json_array = serde_json::Value::Array(vec![]);
for runnable in &self.runnables {
let frame_json = runnable.format_context()?;
tasks_json_array.as_array_mut().unwrap().push(frame_json);
}
Ok(serde_json::json!({
"type": "AsyncScheduler",
"tasks": tasks_json_array
}))
}
}