//! 安装 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, 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(()) }