Files
endorphin-tessera-gui/src/model/protocols.rs
T

123 lines
6.8 KiB
Rust

//! 安装 Visual、EventTarget、Children 和 Presentable 等能力契约。
//! 契约描述对象能响应什么源方法;具体测量、绘制、事件执行仍在各自协议驱动器中完成。
//!
//! 调用路径:ui_bridge::bootstrap 先创建名义类型/原生方法,再调用 install,把能力同时公开到 ui 和 desktop.types。
//! Aster 在 implement 注册、覆写和调用边界使用 TypedMethodRequirement 检查契约;安装期间不执行用户方法体。
//!
//! Host capability definitions over Aster's explicit managed trait relations.
use endor_core::{
AnnotationType, CallArity, CallEffect, CallSignature, ObjectRef, TypedMethodRequirement, Value,
Vm, VmError,
};
/// 把本模块的类型、方法或能力注册到所属运行时上下文。
pub fn install(
vm: &mut Vm,
roots: &mut Vec<ObjectRef>,
desktop: ObjectRef,
ui: ObjectRef,
) -> Result<(), VmError> {
// 安装前要求桥接已经创建 Trait 类型与 desktop.types 注册表;缺失时立即失败,不能安装半定义能力。
let Value::Object(trait_type) = vm.get_attr(ui, "Trait")? else {
return Err(VmError::InvalidArgument("missing Trait type"));
};
// 使用当前桌面的真实类型字典,能力与其 Window/Block 注解必须来自同一运行时。
let Value::Object(types) = vm.get_attr(desktop, "types")? else {
return Err(VmError::InvalidArgument("missing type registry"));
};
// 每组声明能力名、方法及显式参数数目、提供默认签名的原生类型。
// 签名还含接收者参数,下面会把总 arity 调整为 parameters+1。
for (name, methods, owner) in [
(
// 测量/布局/绘制/命中能力,签名取自 Block 的原生协议实现,保证效果约束与具体方法一致。
"Visual",
vec![("measure", 2), ("arrange", 2), ("paint", 2), ("hitTest", 2)],
Some("Block"),
),
(
// 事件能力同时约束订阅、源码派发和目标默认方法,原生签名来自 Block。
"EventTarget",
vec![("on", 3), ("dispatch", 2), ("onEvent", 1)],
Some("Block"),
),
(
// 组成编辑能力属于 ContainerBlock,普通叶 Block 不因此获得追加或重排孩子的方法。
"Children",
vec![
("append", 1),
("insert", 2),
("remove", 1),
("replace", 2),
("move", 2),
("children", 0),
],
Some("ContainerBlock"),
),
// Presentable 显式声明展示能力,不能仅因对象有同名 present 就隐式启用。
("Presentable", vec![("present", 1)], None),
] {
// 从当前 ui 模块查名义类型身份,不靠字符串名称把另一个运行时的类型误接进来。
let owner_definition = if let Some(owner) = owner {
// 有默认提供者时要求 ui 上的名义类型存在,避免装入缺少方法基线的能力。
let Value::Object(definition) = vm.get_attr(ui, owner)? else {
return Err(VmError::InvalidArgument("missing protocol owner"));
};
Some(definition)
} else {
None
};
// 本能力的每项方法要求在此收集,全部契约可构造后才分配 trait 对象。
let mut requirements = Vec::new();
// 逐方法复用原生参数/返回/效果,再统一将 receiver 放宽为 Any。
for (method, parameters) in methods {
// 优先复用原生方法参数/返回注解和调用效果,缺少原生签名元数据时拒绝安装。
let mut signature = if let Some(owner) = owner_definition {
// 按名义 owner 的方法表查真实函数,不从实例字段借用一个碰巧同名的 callable。
let function = vm
.object_store()
.lookup_method(owner, method)?
.ok_or(VmError::InvalidArgument("missing protocol method"))?;
vm.object_store()
.native_signature(function)?
.ok_or(VmError::InvalidArgument(
"protocol method lacks native types",
))?
} else {
// Presentable 没有默认 owner,手工声明 present(receiver, Window) -> Block,调用效果为 External。
// Presentable 的窗口参数绑定当前桌面 Window 名义类型,不使用宽泛 Object 替代要求。
let window = crate::ui_bridge::desktop_type(vm.object_store(), "Window", desktop)?;
// 返回必须满足当前桌面 Block 契约,具体实现可返回更具体的视觉子类。
let block = crate::ui_bridge::desktop_type(vm.object_store(), "Block", desktop)?;
CallSignature::exact(
vec![AnnotationType::Any, AnnotationType::Nominal(window)],
AnnotationType::Nominal(block),
CallEffect::External,
)
};
// Aster typed trait 要求固定的规范调用形状;例如 on 以 receiver+事件名+回调+阶段四参描述。
// 这只修改 trait 的签名副本,不收紧原生 on/dispatch 方法本身允许省略尾参的 arity。
signature.arity = CallArity::exact(parameters + 1);
// 接收者类型改为 Any,使能力可由其他符合方法契约的名义类型实现,不把契约绑定死在 Block。
signature.parameters[0] = AnnotationType::Any.into();
requirements.push(TypedMethodRequirement {
name: method.into(),
signature,
});
}
// VM 创建受类型约束的 trait;后面保活、附 Trait 名义类型并公开两个查询入口。
// EndorTraitObject.trace 会追踪签名中的名义类型,requirements 不是只供显示的无拥有关系文本。
let capability = vm.new_typed_trait(name, requirements)?;
// 新能力放入宿主 roots 管理生命周期,再同时暴露于 ui 属性与 desktop 类型注册表。
roots.push(capability);
vm.attach_type(capability, trait_type)?;
vm.set_attr(ui, name, Value::Object(capability))?;
vm.dict_set(types, Value::Text(name.into()), Value::Object(capability))?;
// 默认 owner 显式 implement;没有 owner 的 Presentable 不能自动授予全部类型。
if let Some(owner) = owner_definition {
// 有默认提供者时显式登记 implements 关系;Presentable 留待具体类型声明,不自动给所有 Block 安装。
vm.implement_trait(owner, capability)?;
}
}
Ok(())
}