core 设计
设计目标
根包是大多数程序导入的门面。它应当让程序通过一次导入就能构建策略、计划和工作流,运行内核并提交工作流,并提供合理的默认值,而真正的定义留在拥有它们的包中。后端也是在这里选择的,因此它是除 backend/native 之外唯一依赖 C 运行时的包。
数学背景
门面没有引入新概念;它是其函数与底层包函数之间的一组等式。记 为默认策略 :
其他每个函数也是如此。门面特有的事实只有它的默认值。对内核而言默认值为 ,原生的覆盖条件 就变成
因此使用默认参数时,内核只接受长度为一的输入。
设计决策
带默认值的自由函数
门面暴露的是 map、workflow、spawn_task 这样的自由函数,而不是导入类型上的方法,因为这些类型属于其他包,无法在这里添加方法。可选参数承载默认值,所以常见的调用很短:@luna_thread.map("double", @luna_thread.i32_type(), 16) 就是一个完整且有效的计划。能力辅助函数把每种能力绑定到唯一有效的访问模式(channel_capability 对应 MoveOnly,mutex_capability 对应 SynchronizeOnly,shared_read_capability 对应 ReadOnly),从而消除了一整类 InvalidCapabilityAccess 问题。
在一处进行后端路由
submit_workflow 按后端分派:Native 交给 @native.submit_workflow,其他交给 @workflow.submit。两者如今产生相同的经过验证的提交,但通过后端包路由正是将来接入执行的位置。直接执行和异步函数无条件调用 backend/native,因为它是唯一能执行的后端。
门面只支持原生目标
由于它导入了 backend/native,而后者的外部函数只存在于原生目标上,门面声明了 supported_targets = "native"。必须在所有目标上构建的代码直接导入 plan、shared 和 workflow;除执行之外,它们提供了一切。
沿用原有接口的内核默认值
内核默认值 是最小的有效策略值,与 make_policy 一致,但如上文推导,它们只在只有一个元素时满足覆盖条件。改变它们会改变现有调用的含义;API 和教程页面会提醒用户把两个参数都传上。
正确性 / 不变量
- 忠实转发。 对同样的参数和默认值,每个门面函数返回的正是底层函数返回的结果;门面不持有状态。
- 默认值是有效策略。
default_policy()属于 v1 策略子集;不带参数调用make_policy返回Ok(default_policy())。 - 对 C 的单一依赖。 只有
execute_*、submit_workflow_async、poll_workflow、wait_workflow和drop_workflow会触及 C 运行时。
被否决的方案
- 重新导出整个包。 重新导出
plan、shared和workflow的每个名称会重复它们的 API 页面;门面只保留典型程序需要的入口,而那些包仍然可以直接导入。 - 在编译时按目标选择后端。 这会让门面能在所有目标上构建,却会随目标悄悄改变行为;v1 改为把原生要求明确写出来。
边界
门面不定义类型,自身不验证任何东西,不执行计划,不管理线程池,也不支持 JavaScript 后端;它只转发给已经或将要做这些事的包。