Skip to main content

onion_vm/types/lambda/
launcher.rs

1//! Onion 虚拟机 Lambda 启动器(Launcher)。
2//!
3//! 该模块实现了 `OnionLambdaRunnableLauncher`,用于将 Lambda 对象与参数、约束、捕获等进行动态绑定,
4//! 并自动处理参数展开、约束检查、runnable 构造与映射等复杂流程。
5//!
6//! 主要特性:
7//! - 支持参数自动展开与类型检查
8//! - 支持参数约束(布尔/嵌套 Lambda)自动递归校验
9//! - 支持自定义 runnable_mapper 对生成的 runnable 进行包装或变换
10//! - 兼容原生与字节码 Lambda
11//! - 便于与异步/同步调度器集成
12
13use std::sync::Arc;
14
15use arc_gc::gc::GC;
16
17use crate::{
18    lambda::runnable::{Runnable, RuntimeError, StepResult},
19    types::{
20        lambda::definition::OnionLambdaDefinition,
21        object::{OnionObject, OnionObjectCell, OnionStaticObject},
22    },
23    unwrap_step_result,
24    utils::{
25        fastmap::{OnionFastMap, OnionKeyPool},
26        format_object_summary,
27    },
28};
29
30/// Lambda 启动器。
31///
32/// 负责将 Lambda 对象与参数、约束、捕获等进行动态绑定,
33/// 并自动处理参数展开、约束检查、runnable 构造与映射等复杂流程。
34///
35/// ## 字段说明
36/// - `lambda`:被调用的 Lambda 对象(OnionObject::Lambda)
37/// - `lambda_ref`:Lambda 定义的强引用
38/// - `lambda_self_object`:Lambda 的 self 对象
39/// - `argument`:原始参数对象(用于参数展开)
40/// - `flatten_argument`:展平后的参数列表
41/// - `string_pool`:参数名字符串池,保证参数名唯一性与高效查找
42/// - `current_argument_index`:当前参数处理进度
43/// - `runnable_mapper`:对生成的 runnable 进行包装/变换的回调
44#[allow(unused)]
45pub struct OnionLambdaRunnableLauncher {
46    /// 被调用的 Lambda 对象(OnionObject::Lambda)
47    lambda: OnionStaticObject,
48    /// Lambda 定义的强引用
49    lambda_ref: Arc<OnionLambdaDefinition>,
50    /// Lambda 的 self 对象
51    lambda_self_object: OnionStaticObject,
52
53    /// 原始参数对象(用于参数展开)
54    argument: OnionStaticObject,
55    /// 展平后的参数列表
56    flatten_argument: Vec<OnionObject>,
57
58    /// 参数名字符串池,保证参数名唯一性与高效查找
59    string_pool: OnionKeyPool<Box<str>>,
60    /// 当前参数处理进度
61    current_argument_index: usize,
62
63    /// 对生成的 runnable 进行包装/变换的回调
64    runnable_mapper:
65        Box<dyn Fn(Box<dyn Runnable>) -> Result<Box<dyn Runnable>, RuntimeError> + Sync + Send>,
66}
67
68impl OnionLambdaRunnableLauncher {
69    /// 构造新的 Lambda 启动器。
70    ///
71    /// # 参数
72    /// - `lambda`:被调用的 Lambda 对象(OnionObject::Lambda)
73    /// - `argument`:参数对象(可为元组、字典等)
74    /// - `runnable_mapper`:对生成的 runnable 进行包装/变换的回调
75    ///
76    /// # 返回值
77    /// 返回新的 OnionLambdaRunnableLauncher 实例,参数已自动展开,约束待校验
78    ///
79    /// # 细节说明
80    /// - string_pool 由被调用 Lambda 决定,保证参数名唯一性
81    /// - 参数展开失败或类型不符会直接返回错误
82    /// - runnable_mapper 可用于包装异步、同步等调度器
83    pub fn new<F: Sync + Send + 'static>(
84        lambda: &OnionObject,
85        argument: OnionStaticObject,
86        runnable_mapper: F,
87    ) -> Result<OnionLambdaRunnableLauncher, RuntimeError>
88    where
89        F: Fn(Box<dyn Runnable>) -> Result<Box<dyn Runnable>, RuntimeError> + Sync + Send + 'static,
90    {
91        let OnionObject::Lambda((lambda_ref, self_object)) = lambda else {
92            return Err(RuntimeError::InvalidType(
93                "Cannot launch non-lambda object".into(),
94            ));
95        };
96        let key_pool = lambda_ref.create_key_pool();
97
98        // 参数自动展开,支持元组/字典等多种形式
99        let flatten_argument = lambda_ref
100            .get_parameter()
101            .unpack_arguments(argument.weak())?;
102
103        Ok(Self {
104            lambda: lambda.stabilize(),
105            lambda_ref: lambda_ref.clone(),
106            lambda_self_object: self_object.stabilize(),
107            argument,
108            flatten_argument,
109            string_pool: key_pool.clone(),
110            current_argument_index: 0,
111            runnable_mapper: Box::new(runnable_mapper),
112        })
113    }
114}
115
116impl Runnable for OnionLambdaRunnableLauncher {
117    /// 接收子任务的执行结果。
118    ///
119    /// - StepResult::Continue:参数约束校验通过,继续
120    /// - StepResult::Return:布尔约束校验,false 则报错
121    /// - 其他类型(NewRunnable/ReplaceRunnable/SpawnRunnable):均为非法,直接报错
122    /// - StepResult::Error:直接转发错误
123    fn receive(
124        &mut self,
125        step_result: &StepResult,
126        _gc: &mut GC<OnionObjectCell>,
127    ) -> Result<(), RuntimeError> {
128        match step_result {
129            StepResult::Continue => Ok(()),
130            StepResult::NewRunnable(_) => Err(RuntimeError::DetailedError(
131                "OnionLambdaRunnableLauncher cannot yield new runnables"
132                    .to_string()
133                    .into(),
134            )),
135            StepResult::Return(constraint_result) => {
136                // 约束校验结果,必须为 true
137                if constraint_result.weak().to_boolean()? {
138                    Ok(())
139                } else {
140                    Err(RuntimeError::InvalidOperation(
141                        "Constraint check failed".into(),
142                    ))
143                }
144            }
145            StepResult::ReplaceRunnable(_) => Err(RuntimeError::DetailedError(
146                "OnionLambdaRunnableLauncher cannot replace runnables"
147                    .to_string()
148                    .into(),
149            )),
150            StepResult::Error(e) => Err(e.clone()),
151            StepResult::SpawnRunnable(_) => Err(RuntimeError::DetailedError(
152                "OnionLambdaRunnableLauncher cannot spawn new runnables"
153                    .to_string()
154                    .into(),
155            )),
156        }
157    }
158
159    /// 推进参数约束校验与 runnable 构造。
160    ///
161    /// - 首先依次校验所有参数约束(布尔/嵌套 Lambda)
162    ///   - 若为布尔约束且为 false,立即报错
163    ///   - 若为 Lambda 约束,递归生成新 Launcher 进行校验
164    ///   - 其他类型直接报错
165    /// - 所有约束校验通过后,收集参数,调用 lambda_ref.create_runnable 构造 runnable
166    /// - 通过 runnable_mapper 包装后,替换当前 runnable
167    fn step(&mut self, gc: &mut GC<OnionObjectCell>) -> StepResult {
168        if self.current_argument_index == self.lambda_ref.get_flatten_param_keys().len() {
169            // 所有参数约束校验通过,收集参数并构造 runnable
170            let mut collected_arguments = OnionFastMap::new(self.string_pool.clone());
171            for i in 0..self.current_argument_index {
172                collected_arguments.push(
173                    &self.lambda_ref.get_flatten_param_keys()[i],
174                    self.flatten_argument[i].stabilize(),
175                );
176            }
177
178            let runnable = unwrap_step_result!(self.lambda_ref.create_runnable(
179                &collected_arguments,
180                &self.lambda,
181                self.lambda_self_object.weak(),
182                gc,
183            ));
184
185            // 通过 runnable_mapper 包装(如异步/同步调度器)
186            let mapped = unwrap_step_result!((self.runnable_mapper)(runnable));
187            return StepResult::ReplaceRunnable(mapped);
188        }
189
190        // 依次校验参数约束
191        let mut index = self.current_argument_index;
192        while index < self.lambda_ref.get_flatten_param_keys().len() {
193            match &self.lambda_ref.get_flatten_param_constraints()[index] {
194                OnionObject::Boolean(v) => {
195                    if !*v {
196                        self.current_argument_index = index + 1;
197                        return StepResult::Error(RuntimeError::InvalidOperation(
198                            "Constraint check failed".into(),
199                        ));
200                    }
201                }
202                lambda @ OnionObject::Lambda(_) => {
203                    // 嵌套 Lambda 约束,递归生成新 Launcher
204                    self.current_argument_index = index + 1;
205                    return StepResult::NewRunnable(Box::new(unwrap_step_result!(
206                        OnionLambdaRunnableLauncher::new(
207                            lambda,
208                            self.flatten_argument[index].stabilize(),
209                            |r| Ok(r),
210                        )
211                    )));
212                }
213                v => {
214                    self.current_argument_index = index + 1;
215                    return StepResult::Error(
216                        RuntimeError::InvalidType(
217                            format!(
218                                "Expect boolean or lambda for constraint, but found: {:?}",
219                                v
220                            )
221                            .into(),
222                        )
223                        .into(),
224                    );
225                }
226            }
227            index += 1;
228        }
229        self.current_argument_index = index;
230        StepResult::Continue
231    }
232
233    /// 格式化当前 Launcher 的上下文信息。
234    ///
235    /// 输出当前参数处理进度、Lambda 信息等,便于调试。
236    fn format_context(&self) -> String {
237        "-> At lambda runnable launcher".to_string()
238            + &format!(
239                " (current index: {}, expected: {})",
240                self.current_argument_index,
241                self.lambda_ref.get_flatten_param_keys().len()
242            )
243            + &format!(", lambda: {}", format_object_summary(self.lambda.weak()))
244    }
245}