onion_vm/lambda/scheduler/map_scheduler.rs
1//! Map 调度器实现:用于对容器(如元组)中的每个元素应用映射器函数,并收集结果。
2//!
3//! 该模块实现了 Mapping 结构体及其 Runnable trait,用于在 Onion 虚拟机中高效地进行 map 操作。
4//! 支持惰性调度、逐步执行和结果收集,适用于异步/协作式执行环境。
5use arc_gc::gc::GC;
6
7use crate::{
8 lambda::runnable::{Runnable, RuntimeError, StepResult},
9 types::{
10 lambda::launcher::OnionLambdaRunnableLauncher,
11 object::{OnionObject, OnionObjectCell, OnionStaticObject},
12 tuple::OnionTuple,
13 },
14 utils::format_object_summary,
15};
16
17/// 表示一次 map 操作的调度状态。
18///
19/// - `container`:待映射的容器对象(通常为元组)
20/// - `mapper`:映射器函数对象(lambda 或其他)
21/// - `collected`:已收集的映射结果
22/// - `current_index`:当前处理到的元素索引
23#[derive(Clone)]
24pub struct Mapping {
25 /// 待映射的容器对象(如元组)
26 container: OnionStaticObject,
27 /// 映射器函数对象
28 mapper: OnionStaticObject,
29 /// 已收集的结果
30 collected: Vec<OnionStaticObject>,
31 /// 当前处理的元素索引
32 current_index: usize,
33}
34
35impl Mapping {
36 /// 创建一个新的 Mapping 实例。
37 ///
38 /// # 参数
39 /// * `container` - 待映射的容器对象(通常为元组)
40 /// * `mapper` - 映射器函数对象(lambda 或其他)
41 ///
42 /// # 返回值
43 /// 返回新创建的 Mapping 实例,初始状态下未处理任何元素。
44 pub fn new(container: &OnionStaticObject, mapper: &OnionStaticObject) -> Self {
45 Mapping {
46 container: container.clone(),
47 mapper: mapper.clone(),
48 collected: vec![],
49 current_index: 0,
50 }
51 }
52}
53
54impl Runnable for Mapping {
55 /// 接收子任务的执行结果,并收集到结果列表。
56 ///
57 /// # 参数
58 /// * `step_result` - 子任务的执行结果,期望为 StepResult::Return
59 /// * `_gc` - 垃圾收集器引用(未使用)
60 ///
61 /// # 返回值
62 /// * Ok(()) - 成功收集结果并推进索引
63 /// * Err(RuntimeError) - 收到非预期结果类型
64 fn receive(
65 &mut self,
66 step_result: &StepResult,
67 _gc: &mut GC<OnionObjectCell>,
68 ) -> Result<(), RuntimeError> {
69 match step_result {
70 StepResult::Return(result) => {
71 self.collected.push(result.as_ref().clone());
72 self.current_index += 1; // 移动到下一个元素
73 Ok(())
74 }
75 _ => Err(RuntimeError::DetailedError(
76 "Unexpected step result in mapping".into(),
77 )),
78 }
79 }
80
81 /// 执行 map 操作的一个调度步骤。
82 ///
83 /// - 若当前元素存在,尝试用 mapper 处理之:
84 /// - 若 mapper 是 lambda,则生成新 Runnable 进行调用
85 /// - 若 mapper 为 false,跳过当前元素
86 /// - 其他情况直接收集元素
87 /// - 若所有元素处理完毕,返回收集到的新元组
88 ///
89 /// # 返回值
90 /// * StepResult::NewRunnable - 需要调度新任务
91 /// * StepResult::Continue - 继续下一个元素
92 /// * StepResult::Return - 所有元素处理完毕,返回结果
93 /// * StepResult::Error - 类型错误或其他异常
94 fn step(&mut self, _gc: &mut GC<OnionObjectCell>) -> StepResult {
95 self.container
96 .weak()
97 .with_data(|container| match container {
98 OnionObject::Tuple(tuple) => {
99 // 使用索引获取当前元素
100 if let Some(element) = tuple.get_elements().get(self.current_index) {
101 let element_clone = element.clone();
102 self.mapper.weak().with_data(|mapper_obj| match mapper_obj {
103 OnionObject::Lambda(_) => {
104 let runnable = Box::new(OnionLambdaRunnableLauncher::new(
105 mapper_obj,
106 element.stabilize(),
107 &|r| Ok(r),
108 )?);
109 Ok(StepResult::NewRunnable(runnable))
110 }
111 OnionObject::Boolean(false) => Ok(StepResult::Continue),
112 _ => {
113 self.collected.push(element_clone.stabilize());
114 Ok(StepResult::Continue)
115 }
116 })
117 } else {
118 // 所有元素都处理完了
119 Ok(StepResult::Return(
120 OnionTuple::new_static_no_ref(&self.collected).into(),
121 ))
122 }
123 }
124 _ => Err(RuntimeError::InvalidType(
125 "Container must be a tuple".into(),
126 )),
127 })
128 .unwrap_or_else(|e| StepResult::Error(e))
129 }
130
131 /// 格式化 map 调度器的当前上下文信息。
132 ///
133 /// 输出当前映射器、容器、进度和已收集结果数量,便于调试。
134 ///
135 /// # 返回值
136 /// 返回格式化的多行字符串,展示 map 操作的状态。
137 fn format_context(&self) -> String {
138 // 使用 format! 宏来构建一个多行的字符串
139 format!(
140 "-> In 'map' operation:\n - Mapper: {}\n - Container: {}\n - Progress: Processing element {} / {}\n - Collected Items: {}",
141 // 1. 映射器信息
142 // 使用对象的简略表示(比如 debug 格式)
143 format_object_summary(self.mapper.weak()),
144 // 2. 容器信息
145 format_object_summary(self.container.weak()),
146 // 3. 进度信息
147 self.current_index,
148 self.container
149 .weak()
150 .with_data(|c| {
151 Ok(if let OnionObject::Tuple(t) = c {
152 t.get_elements().len()
153 } else {
154 0 // Or some other placeholder like "N/A"
155 })
156 })
157 .unwrap_or(0), // Provide a default if weak link is dead
158 // 4. 已收集结果的数量
159 self.collected.len()
160 )
161 }
162}