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 = &parameter_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 = &parameter_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}