use arc_gc::gc::GC;
use crate::{
lambda::runnable::{Runnable, RuntimeError, StepResult},
types::{
lambda::launcher::OnionLambdaRunnableLauncher,
object::{OnionObject, OnionObjectCell, OnionStaticObject},
tuple::OnionTuple,
},
utils::format_object_summary,
};
#[derive(Clone)]
pub struct Mapping {
pub(crate) container: OnionStaticObject,
pub(crate) mapper: OnionStaticObject,
pub(crate) collected: Vec<OnionStaticObject>,
pub(crate) current_index: usize,
}
impl Runnable for Mapping {
fn receive(
&mut self,
step_result: &StepResult,
_gc: &mut GC<OnionObjectCell>,
) -> Result<(), RuntimeError> {
match step_result {
StepResult::Return(result) => {
self.collected.push(result.as_ref().clone());
self.current_index += 1; Ok(())
}
_ => Err(RuntimeError::DetailedError(
"Unexpected step result in mapping".into(),
)),
}
}
fn step(&mut self, _gc: &mut GC<OnionObjectCell>) -> StepResult {
self.container
.weak()
.with_data(|container| match container {
OnionObject::Tuple(tuple) => {
if let Some(element) = tuple.get_elements().get(self.current_index) {
let element_clone = element.clone();
self.mapper.weak().with_data(|mapper_obj| match mapper_obj {
OnionObject::Lambda(_) => {
let runnable = Box::new(OnionLambdaRunnableLauncher::new_static(
mapper_obj,
element.stabilize(),
&|r| Ok(r),
)?);
Ok(StepResult::NewRunnable(runnable))
}
OnionObject::Boolean(false) => Ok(StepResult::Continue),
_ => {
self.collected.push(element_clone.stabilize());
Ok(StepResult::Continue)
}
})
} else {
Ok(StepResult::Return(
OnionTuple::new_static_no_ref(&self.collected).into(),
))
}
}
_ => Err(RuntimeError::InvalidType(
"Container must be a tuple".into(),
)),
})
.unwrap_or_else(|e| StepResult::Error(e))
}
fn format_context(&self) -> String {
format!(
"-> In 'map' operation:\n - Mapper: {}\n - Container: {}\n - Progress: Processing element {} / {}\n - Collected Items: {}",
format_object_summary(self.mapper.weak()),
format_object_summary(self.container.weak()),
self.current_index,
self.container
.weak()
.with_data(|c| {
Ok(if let OnionObject::Tuple(t) = c {
t.get_elements().len()
} else {
0 })
})
.unwrap_or(0), self.collected.len()
)
}
}