onion_vm/types/lambda/launcher.rs
1use std::sync::Arc;
2
3use arc_gc::{arc::GCArc, gc::GC};
4
5use crate::{
6 lambda::{
7 runnable::{Runnable, RuntimeError, StepResult},
8 scheduler::scheduler::Scheduler,
9 },
10 types::{
11 named::OnionNamed,
12 object::{OnionObject, OnionObjectCell, OnionStaticObject},
13 tuple::OnionTuple,
14 },
15 unwrap_step_result,
16};
17
18#[derive(Clone)]
19enum ArgumentProcessingPhase {
20 NamedArguments,
21 PositionalArguments,
22 Done,
23}
24
25pub struct OnionLambdaRunnableLauncher {
26 lambda: OnionStaticObject, // The OnionObject::Lambda itself
27
28 parameter_tuple: Arc<OnionTuple>, // The parameter tuple from the lambda definition
29 #[allow(unused_attributes)]
30 parameter_arcs: Vec<GCArc<OnionObjectCell>>, // The parameter arcs from the lambda definition
31
32 argument_tuple: Arc<OnionTuple>, // The provided argument tuple object
33 #[allow(unused_attributes)]
34 argument_arcs: Vec<GCArc<OnionObjectCell>>, // The provided argument arcs from the argument tuple
35
36 collected_arguments: Vec<OnionStaticObject>, // Arguments collected during processing
37 assigned: Vec<bool>, // Tracks assignment for parameter slots, then for appended args
38 current_argument_index: usize, // Index into argument_elements for current phase
39
40 phase: ArgumentProcessingPhase,
41
42 runnable_mapper: &'static (dyn Fn(Box<dyn Runnable>) -> Result<Box<dyn Runnable>, RuntimeError> + Sync + Send),
43 constrain_runnable: Option<Box<dyn Runnable>>,
44}
45
46impl OnionLambdaRunnableLauncher {
47 pub fn new_static<F: 'static + Sync + Send>(
48 lambda_obj: &OnionStaticObject,
49 argument_tuple_obj: &OnionStaticObject,
50 runnable_mapper: &'static F,
51 ) -> Result<OnionLambdaRunnableLauncher, RuntimeError>
52 where
53 F: Fn(Box<dyn Runnable>) -> Result<Box<dyn Runnable>, RuntimeError> + Sync + Send,
54 {
55 // Initialize collected_arguments based on parameter count
56 let mut collected_arguments = Vec::new();
57 let mut assigned = Vec::new();
58
59 let (parameter_tuple, parameter_arcs) = lambda_obj.weak().with_data(|obj_ref| {
60 if let OnionObject::Lambda(definition) = obj_ref {
61 definition.get_parameter().with_data(|p_obj| {
62 if let OnionObject::Tuple(tuple) = p_obj {
63 // Initialize collected_arguments and assigned based on parameter count
64 for param in tuple.get_elements() {
65 param.with_data(|param_obj| {
66 match param_obj {
67 OnionObject::LazySet(lazy_set) => {
68 // If the parameter is a LazySet, we collect its container.
69 collected_arguments
70 .push(lazy_set.get_container().stabilize());
71 }
72 _ => {
73 // For other types, we just clone the parameter as is.
74 collected_arguments.push(param.stabilize());
75 }
76 }
77 Ok(())
78 })?;
79 }
80 assigned = vec![false; tuple.get_elements().len()];
81
82 let parameter_tuple = tuple.clone();
83 let mut arcs = vec![];
84 tuple.upgrade(&mut arcs);
85
86 Ok((parameter_tuple, arcs))
87 } else {
88 Err(RuntimeError::DetailedError(
89 "Lambda parameters must be a Tuple".to_string().into(),
90 ))
91 }
92 })
93 } else {
94 Err(RuntimeError::DetailedError(
95 "Expected a Lambda definition object".to_string().into(),
96 ))
97 }
98 })?;
99
100 let (argument_tuple, argument_arcs) = argument_tuple_obj.weak().with_data(|arg_obj| {
101 if let OnionObject::Tuple(tuple) = arg_obj {
102 // Initialize argument_tuple and its arcs(simulate `stabilize` behavior)
103 let argument_tuple = tuple.clone();
104 let mut arcs = vec![];
105 tuple.upgrade(&mut arcs);
106 Ok((argument_tuple, arcs))
107 } else {
108 Err(RuntimeError::DetailedError(
109 "Lambda arguments must be a Tuple".to_string().into(),
110 ))
111 }
112 })?;
113
114 Ok(OnionLambdaRunnableLauncher {
115 lambda: lambda_obj.clone(),
116 parameter_tuple: parameter_tuple,
117 parameter_arcs: parameter_arcs,
118 argument_tuple: argument_tuple,
119 argument_arcs: argument_arcs,
120 collected_arguments,
121 assigned,
122 phase: ArgumentProcessingPhase::NamedArguments,
123 current_argument_index: 0,
124 runnable_mapper: runnable_mapper,
125 constrain_runnable: None,
126 })
127 }
128}
129
130impl Runnable for OnionLambdaRunnableLauncher {
131 fn copy(&self) -> Box<dyn Runnable> {
132 Box::new(OnionLambdaRunnableLauncher {
133 lambda: self.lambda.clone(),
134 parameter_tuple: self.parameter_tuple.clone(),
135 parameter_arcs: self.parameter_arcs.clone(),
136 argument_tuple: self.argument_tuple.clone(),
137 argument_arcs: self.argument_arcs.clone(),
138 collected_arguments: self.collected_arguments.clone(),
139 assigned: self.assigned.clone(),
140 phase: self.phase.clone(),
141 current_argument_index: self.current_argument_index,
142 runnable_mapper: self.runnable_mapper,
143 constrain_runnable: match &self.constrain_runnable {
144 Some(runnable) => Some(runnable.copy()),
145 None => None,
146 },
147 })
148 }
149
150 fn receive(
151 &mut self,
152 step_result: &StepResult,
153 _gc: &mut GC<OnionObjectCell>,
154 ) -> Result<(), RuntimeError> {
155 match step_result {
156 StepResult::Continue => Ok(()),
157 StepResult::NewRunnable(_) => {
158 // This should not happen, as this launcher is not designed to yield new runnables.
159 Err(RuntimeError::DetailedError(
160 "OnionLambdaRunnableLauncher cannot yield new runnables"
161 .to_string()
162 .into(),
163 ))
164 }
165 StepResult::Return(_) => {
166 // This should not happen, as this launcher is not designed to return values.
167 Err(RuntimeError::DetailedError(
168 "OnionLambdaRunnableLauncher cannot return values"
169 .to_string()
170 .into(),
171 ))
172 }
173 StepResult::ReplaceRunnable(_) => {
174 // This should not happen, as this launcher is not designed to replace runnables.
175 Err(RuntimeError::DetailedError(
176 "OnionLambdaRunnableLauncher cannot replace runnables"
177 .to_string()
178 .into(),
179 ))
180 }
181 StepResult::Error(e) => {
182 // Propagate any errors received from the runnable.
183 Err(e.clone())
184 }
185 StepResult::SetSelfObject(_) => {
186 // This should not happen, as this launcher is not designed to set self objects.
187 Err(RuntimeError::DetailedError(
188 "OnionLambdaRunnableLauncher cannot set self objects"
189 .to_string()
190 .into(),
191 ))
192 }
193 }
194 }
195 /// 执行 Lambda 启动器的下一步操作。
196 ///
197 /// 此方法通过一个状态机来处理参数的收集、验证(通过约束)并最终启动 Lambda。
198 /// 它的主要职责是:
199 /// 1. 如果存在参数约束 (`constrain_runnable`),则先执行约束。
200 /// 2. 根据当前的 `phase`(命名参数、位置参数、完成)处理传入的参数。
201 /// 3. 收集和整理参数,直到所有参数处理完毕。
202 /// 4. 创建并返回目标 Lambda 的可运行实例。
203 ///
204 /// # 参数
205 /// * `gc`: 垃圾收集器的可变引用,用于内存管理。
206 ///
207 /// # 返回
208 /// * `Ok(StepResult)`: 表示操作成功,并指示调度器下一步应该做什么。
209 /// - `StepResult::Continue`: 表示启动器需要更多步骤来完成参数处理或约束执行。
210 /// - `StepResult::ReplaceRunnable`: 表示参数处理完成,启动器应被新的 Lambda 可运行实例替换。
211 /// * `Err(RuntimeError)`: 表示在执行过程中发生错误。
212 fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
213 // 阶段一:执行参数约束 (如果存在)
214 // 如果 `constrain_runnable` (通常是一个由 LazySet 的 filter 创建的 Lambda 启动器) 存在,
215 // 意味着当前正在处理的参数有一个关联的约束需要被满足。
216 if let Some(constrain_runnable) = self.constrain_runnable.as_mut() {
217 // 执行约束可运行对象的 `step` 方法
218 match constrain_runnable.step(gc) {
219 // 约束尚未完成,需要继续执行。启动器也返回 Continue。
220 StepResult::Continue => {
221 return StepResult::Continue;
222 }
223 // 约束执行过程中不应该产生新的可运行对象或替换自身。
224 StepResult::NewRunnable(_) => {
225 return StepResult::Error(RuntimeError::DetailedError(
226 "OnionLambdaRunnableLauncher's constrain_runnable cannot yield new runnables".to_string().into(),
227 ));
228 }
229 StepResult::ReplaceRunnable(_) => {
230 return StepResult::Error(RuntimeError::DetailedError(
231 "OnionLambdaRunnableLauncher's constrain_runnable cannot replace runnables"
232 .to_string()
233 .into(),
234 ));
235 }
236 StepResult::Error(e) => {
237 // 如果约束执行过程中发生错误,直接返回该错误。
238 return StepResult::Error(e.clone());
239 }
240 // 约束执行完成并返回了一个值。
241 // 约束的返回值约定为一个 Pair:(布尔值表示是否panic, 布尔值表示约束是否通过)
242 StepResult::Return(ref v) => {
243 // 解析约束的返回值
244 unwrap_step_result!(v.weak().with_data(|v_obj| {
245 // 约束的返回值必须是一个 Pair 对象
246 let OnionObject::Pair(constrain_result_pair) = v_obj else {
247 // 如果不是 Pair,则认为约束失败(或者约束实现有误)
248 return Err(RuntimeError::DetailedError(
249 "Constrain runnable did not return a Pair object"
250 .to_string()
251 .into(),
252 ));
253 };
254
255 // 第一个元素 (key) 表示约束执行是否 panic
256 match constrain_result_pair.get_key().to_boolean() {
257 Ok(true) => {
258 // true 表示约束执行没有 panic
259 // 第二个元素 (value) 表示约束是否通过
260 if constrain_result_pair.get_value().to_boolean()? {
261 // 约束通过,清除 `constrain_runnable`,准备处理下一个参数或阶段。
262 self.constrain_runnable = None;
263 // 注意:这里原代码是 `return Ok(())`,这不符合 `step` 的签名。
264 // 应该返回 `Ok(StepResult::Continue)` 以便继续处理参数。
265 // 假设这是期望的行为,即约束成功后,继续当前 `step` 的后续逻辑。
266 // 如果这里直接返回,则当前 `step` 的参数处理逻辑会被跳过。
267 // 为了与原逻辑最接近(即清除约束后继续本轮 step 的后续参数处理),
268 // 我们不在这里 `return`,而是让代码流继续到下面的 `match self.phase`。
269 // 如果期望的是约束成功后立即开始下一轮 `step`,則應 `return Ok(StepResult::Continue)`。
270 // 鉴于后续代码会继续处理参数,这里不返回是合理的。
271 Ok(()) // 标记约束已处理,但不立即返回,让后续的 phase match 执行
272 } else {
273 // 约束未通过 (返回 false)
274 return Err(RuntimeError::DetailedError(
275 "Argument constraint failed".to_string().into(),
276 ));
277 }
278 }
279 Ok(false) => {
280 // false 表示约束执行过程中发生了 panic
281 return Err(RuntimeError::CustomValue(Box::new(
282 constrain_result_pair.get_value().stabilize(),
283 )));
284 }
285 Err(err) => return Err(err), // 转换布尔值失败
286 }
287 }))
288
289 // 如果约束成功并通过 (上面返回 Ok(()) 但没有实际 return),则会继续到下面的 phase 处理。
290 // 如果约束失败或 panic (上面返回 Err),则整个 step 会在这里结束。
291 }
292 StepResult::SetSelfObject(_) => {
293 // 这个启动器不支持设置 self 对象,因此返回错误。
294 return StepResult::Error(RuntimeError::DetailedError(
295 "OnionLambdaRunnableLauncher does not support setting self object"
296 .to_string()
297 .into(),
298 ));
299 }
300 }
301 } // 结束 `if let Some(constrain_runnable)`
302
303 // 阶段二:根据当前处理阶段 (phase) 处理参数
304 match self.phase {
305 // 阶段 2.1: 处理命名参数
306 ArgumentProcessingPhase::NamedArguments => {
307 // 直接使用 self.argument_tuple 获取参数元素
308 let argument_elements = &self.argument_tuple.get_elements();
309 let argument_count = argument_elements.len();
310
311 // 如果当前参数索引超出了提供的参数列表的范围,
312 // 说明所有提供的参数都已在命名参数阶段被初步检查过。
313 // 切换到位置参数处理阶段。
314 if self.current_argument_index >= argument_count {
315 self.phase = ArgumentProcessingPhase::PositionalArguments;
316 self.current_argument_index = 0; // 重置索引以供位置参数阶段使用
317 return StepResult::Continue; // 请求调度器再次调用 step
318 }
319
320 // 获取当前正在处理的由调用者提供的参数
321 let current_arg_index = self.current_argument_index;
322 self.current_argument_index += 1; // 移动到下一个提供的参数
323
324 let arg_obj_view = &argument_elements[current_arg_index];
325 // 检查当前提供的参数是否是命名参数 (`OnionObject::Named`)
326 if let OnionObject::Named(named_arg) = arg_obj_view {
327 let key_to_match = &named_arg.get_key(); // 获取命名参数的名称
328
329 // 遍历 Lambda 定义中的参数,直接使用 self.parameter_tuple
330 let parameter_elements = &self.parameter_tuple.get_elements();
331 let parameter_count = parameter_elements.len();
332
333 for param_idx in 0..parameter_count {
334 // 直接访问参数定义
335 let param_element = ¶meter_elements[param_idx];
336 let matched = match param_element {
337 // 情况 A: Lambda 定义的参数也是一个命名参数 (`name: Type`)
338 OnionObject::Named(param_named_def) => {
339 if unwrap_step_result!(param_named_def
340 .get_key()
341 .equals(key_to_match))
342 {
343 // 名称匹配成功!
344 self.collected_arguments[param_idx] = arg_obj_view.stabilize();
345 self.assigned[param_idx] = true;
346 true
347 } else {
348 false
349 }
350 }
351 // 情况 B: Lambda 定义的参数是一个 LazySet (`name: {constraint}`)
352 OnionObject::LazySet(lazy_set) => {
353 if let OnionObject::Named(container_named) =
354 lazy_set.get_container()
355 {
356 if unwrap_step_result!(container_named
357 .get_key()
358 .equals(key_to_match))
359 {
360 // 名称匹配成功!
361 self.collected_arguments[param_idx] =
362 arg_obj_view.stabilize();
363 self.assigned[param_idx] = true;
364
365 // 设置约束
366 let argument_for_filter = OnionObject::Tuple(
367 OnionTuple::new(vec![named_arg.get_value().clone()])
368 .into(),
369 )
370 .consume_and_stabilize();
371
372 let runnable = Box::new(unwrap_step_result!(
373 OnionLambdaRunnableLauncher::new_static(
374 &lazy_set.get_filter().stabilize(),
375 &argument_for_filter,
376 &|r| Ok(r),
377 )
378 ));
379 self.constrain_runnable =
380 Some(Box::new(Scheduler::new(vec![runnable])));
381 true
382 } else {
383 false
384 }
385 } else {
386 false
387 }
388 }
389 _ => false,
390 };
391
392 if matched {
393 return StepResult::Continue;
394 }
395 }
396
397 // 如果遍历完所有 Lambda 定义的参数后,没有找到匹配的名称,
398 // 说明这是一个额外的命名参数。
399 self.collected_arguments.push(arg_obj_view.stabilize());
400 self.assigned.push(true);
401 };
402
403 // 如果当前提供的参数不是 OnionObject::Named,则在命名参数阶段被忽略。
404 StepResult::Continue
405 }
406 // 阶段 2.2: 处理位置参数
407 ArgumentProcessingPhase::PositionalArguments => {
408 // 直接使用 self.argument_tuple 获取参数数量
409 let argument_count = self.argument_tuple.get_elements().len();
410
411 // 如果当前参数索引超出了提供的参数列表的范围,
412 // 说明所有提供的参数都已在位置参数阶段被处理。
413 // 切换到完成阶段。
414 if self.current_argument_index >= argument_count {
415 self.phase = ArgumentProcessingPhase::Done;
416 return StepResult::Continue; // 请求调度器再次调用 step
417 }
418
419 // 获取当前正在处理的由调用者提供的参数
420 let current_processing_arg_idx = self.current_argument_index;
421 self.current_argument_index += 1; // 移动到下一个提供的参数
422
423 // 直接从 self.argument_tuple 获取参数元素
424 let argument_elements = &self.argument_tuple.get_elements();
425
426 if current_processing_arg_idx >= argument_elements.len() {
427 return StepResult::Error(RuntimeError::DetailedError(
428 "Argument index out of bounds during positional processing"
429 .to_string()
430 .into(),
431 ));
432 }
433
434 let current_provided_arg_view = &argument_elements[current_processing_arg_idx];
435
436 // 如果当前提供的参数是命名参数,则在位置参数阶段跳过。
437 if let OnionObject::Named(_) = current_provided_arg_view {
438 // Skip named arguments in this phase.
439 } else {
440 // This is a positional argument.
441 let current_provided_arg_static = current_provided_arg_view.stabilize();
442
443 // 尝试找到第一个尚未被赋值的 Lambda 定义参数槽。
444 if let Some(param_idx) = self.assigned.iter().position(|&assigned| !assigned) {
445 // 找到了一个未分配的参数槽。直接从 self.parameter_tuple 访问参数定义
446 let parameter_elements = &self.parameter_tuple.get_elements();
447
448 if param_idx >= parameter_elements.len() {
449 return StepResult::Error(RuntimeError::DetailedError(
450 "Parameter index out of bounds for assignment"
451 .to_string()
452 .into(),
453 ));
454 }
455
456 let param_def = ¶meter_elements[param_idx];
457 match param_def {
458 // 情况 A: Lambda 定义的参数是 `name: Type` (Named)
459 OnionObject::Named(original_named_def) => {
460 // 将位置参数包装成一个新的 Named 对象,使用原始定义的名称。
461 let new_value_for_slot = OnionObject::Named(
462 OnionNamed::new(
463 original_named_def.get_key().clone(),
464 current_provided_arg_view.clone(),
465 )
466 .into(),
467 )
468 .consume_and_stabilize();
469 self.collected_arguments[param_idx] = new_value_for_slot;
470 self.assigned[param_idx] = true;
471 }
472 // 情况 B: Lambda 定义的参数是 `name: {constraint}` (LazySet)
473 OnionObject::LazySet(lazy_set_def) => {
474 if let OnionObject::Named(container_named_def) =
475 lazy_set_def.get_container()
476 {
477 // 将位置参数包装成 Named 对象
478 let new_value_for_slot = OnionObject::Named(
479 OnionNamed::new(
480 container_named_def.get_key().clone(),
481 current_provided_arg_view.clone(),
482 )
483 .into(),
484 )
485 .consume_and_stabilize();
486 self.collected_arguments[param_idx] = new_value_for_slot;
487 self.assigned[param_idx] = true;
488
489 // 设置约束
490 // The argument to the filter lambda is the provided argument itself.
491 let argument_for_filter = OnionObject::Tuple(
492 OnionTuple::new(vec![current_provided_arg_view.clone()])
493 .into(),
494 )
495 .consume_and_stabilize();
496
497 let runnable = Box::new(unwrap_step_result!(
498 OnionLambdaRunnableLauncher::new_static(
499 &lazy_set_def.get_filter().stabilize(),
500 &argument_for_filter,
501 &|r| Ok(r),
502 )
503 ));
504 self.constrain_runnable =
505 Some(Box::new(Scheduler::new(vec![runnable])));
506 } else {
507 return StepResult::Error(RuntimeError::DetailedError(
508 "LazySet's container must be a Named object for positional assignment".to_string().into(),
509 ));
510 }
511 }
512 // 情况 C: Lambda 定义的参数是普通类型
513 _ => {
514 self.collected_arguments[param_idx] = current_provided_arg_static;
515 self.assigned[param_idx] = true;
516 }
517 }
518 } else {
519 // 所有 Lambda 定义的参数槽都已被填充。 This is an extra positional argument.
520 self.collected_arguments.push(current_provided_arg_static);
521 self.assigned.push(true);
522 }
523 }
524
525 StepResult::Continue
526 }
527
528 // 阶段 2.3: 完成参数处理,准备启动 Lambda
529 ArgumentProcessingPhase::Done => {
530 // 检查是否仍有未完成的约束。如果 `constrain_runnable` 仍然是 `Some`,
531 // 这意味着上一个参数的约束还没有执行完毕或返回结果。
532 // 此时应该等待约束完成,而不是直接创建 Lambda。
533 if self.constrain_runnable.is_some() {
534 // 理论上,如果约束存在,应该在 `step` 的开头被处理。
535 // 如果执行到 `Done` 阶段约束仍在,说明之前的约束处理逻辑可能需要返回 `Continue`
536 // 直到约束被清除。或者,这是一个不期望的状态。
537 // 为安全起见,如果还有约束,则继续等待。
538 return StepResult::Continue;
539 }
540
541 // 所有参数都已收集完毕,并且所有约束(如果有的话)都已满足。
542 // 使用 `collected_arguments` 创建最终的参数元组。
543 let final_args_static = OnionTuple::new_static_no_ref(&self.collected_arguments);
544
545 // 获取原始 Lambda 定义对象。
546 unwrap_step_result!(self.lambda.weak().with_data(|obj| {
547 if let OnionObject::Lambda(lambda_def) = obj {
548 // 使用最终的参数元组和 Lambda 定义来创建实际的 Lambda 可运行实例。
549 let runnable = lambda_def
550 .create_runnable(final_args_static, &self.lambda, gc)
551 .map_err(|e| {
552 RuntimeError::InvalidType(
553 format!("Failed to create runnable from lambda: {}", e).into(),
554 )
555 })?;
556 // 应用 mapper。
557 // 成功映射,返回 ReplaceRunnable
558 (self.runnable_mapper)(runnable)
559 .map(|result_runnable| StepResult::ReplaceRunnable(result_runnable))
560 } else {
561 // 这是一个内部错误,启动器持有的 lambda 对象不是 Lambda 类型。
562 Err(RuntimeError::DetailedError(
563 "Launcher's lambda object is not OnionObject::Lambda"
564 .to_string()
565 .into(),
566 ))
567 }
568 }))
569 }
570 }
571 }
572
573 fn format_context(&self) -> Result<serde_json::Value, RuntimeError> {
574 // 此启动器不提供上下文格式化功能。
575 Err(RuntimeError::DetailedError(
576 "OnionLambdaRunnableLauncher does not support context formatting"
577 .to_string()
578 .into(),
579 ))
580 }
581}