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