539 lines
29 KiB
Rust
539 lines
29 KiB
Rust
//! 安装一次 VM 域需要的宿主类型、对象和方法。类型注册表是源代码调用原生能力的入口。
|
||
//! 先建立类型与桌面基础设施,再绑定构造器、视觉协议和开发工具工厂;返回的根负责保持这些对象存活。
|
||
//!
|
||
//! 调用链:`endor_host::compile` / `ReplSession::new` 创建候选 VM,
|
||
//! 随后调用本模块的 `install`;运行时再通过 install_globals 注入源程序使用的 UI 值。
|
||
//! 本文件只建立宿主环境。源程序稍后调用构造器或实例方法时,才会进入 `calls::Function::invoke`。
|
||
//! 安装返回的 UiBridge 由运行时保存;传入的 roots 由候选运行时持有,并在失败或退役时统一释放。
|
||
//! 安装顺序还承载 GC 关系:desktop.types 拥有类型,类型拥有工厂/方法,callable 再追踪签名和显式 captures。
|
||
//! 两阶段补签名保留原对象身份,因此 ui 属性和 TypeConstructor 不需要重新指向另一批函数。
|
||
use super::*;
|
||
|
||
/// 为一次候选程序/REPL 会话安装 Tessera 宿主环境,供运行时后续注入全局值和执行源程序。
|
||
///
|
||
/// 类型要先创建,签名才能引用它们;因此先分配没有签名的函数,再原地补齐 payload。
|
||
/// 所有 `?` 都把安装失败交还候选运行时,不会在这里把半成品替换成活跃程序。
|
||
/// `roots` 保存明确的 VM 拥有根;Rust 的 ObjectRef 数值和 Arc<Mutex<Session>> 均不能替代它们。
|
||
pub fn install(vm: &mut Vm, roots: &mut Vec<ObjectRef>) -> Result<UiBridge> {
|
||
// 先建立 desktop/ui/tabs 并加入显式 roots,后面初始化失败时由上层运行时统一释放,避免依赖 Rust 句柄保活。
|
||
// desktop 是此桥接域的类型注册表和窗口资源入口;它不是操作系统桌面或原生窗口。
|
||
let desktop = vm.new_object()?;
|
||
roots.push(desktop);
|
||
// 安装时尚无窗口尺寸;运行时收到 viewport 后再填充,避免在 VM 引导期间依赖 GUI 状态。
|
||
vm.set_attr(desktop, "viewport", Value::Nil)?;
|
||
// tabs 是主窗口的托管页面注册表,Presentation 和 window::install 会使用同一字典身份。
|
||
let tabs = vm.new_dict()?;
|
||
roots.push(tabs);
|
||
vm.set_attr(desktop, "tabs", Value::Object(tabs))?;
|
||
// ui 是对源代码公开的命名空间;desktop 保存内部记账,二者用途不能混同。
|
||
let ui = vm.new_object()?;
|
||
roots.push(ui);
|
||
// 原生 Session 借用托管身份,主窗口先拥有独立 Presentation;业务对象仍全部位于传入的单一 VM。
|
||
let session = Arc::new(Mutex::new(Session {
|
||
// 节点弱索引用来检查数量与回收失效记录,不应让已关闭的业务对象继续存活。
|
||
nodes: Vec::new(),
|
||
// 先登记主窗口上下文;后续窗口通过 create_window 建立各自的 Presentation。
|
||
presentations: std::collections::BTreeMap::from([(
|
||
crate::window::MAIN_WINDOW,
|
||
crate::presentation::Presentation::new(desktop, tabs),
|
||
)]),
|
||
// Session 的 Deref 按 current 选择布局/挂载状态;初始所有操作都落在主窗口。
|
||
current: crate::window::MAIN_WINDOW,
|
||
// master 始终指向主 desktop,副窗口仍借用同一 VM 的类型和资源域。
|
||
master: desktop,
|
||
// 分配器从现有最高窗口 ID 继续增长;Mount 则尚无任何已分配出现位置。
|
||
next_window: crate::window::MAIN_WINDOW,
|
||
next_mount: 0,
|
||
// 关闭后尚未交给 GUI 的原生命令暂存在这里,不能随 Presentation 删除而丢失。
|
||
retired_commands: Vec::new(),
|
||
// 累计诊断计数由刷新流程更新,供 ui.stats/开发工具观察本会话的实际工作量。
|
||
refresh_yields: 0,
|
||
refresh_restarts: 0,
|
||
layout_cancels: 0,
|
||
paint_cancels: 0,
|
||
paint_slices: 0,
|
||
binding_evaluations: 0,
|
||
// 清理阶段会置位,create_window 等操作据此拒绝在退出期间重新创建资源。
|
||
exiting: false,
|
||
}));
|
||
// 先分配函数占位再补签名,因为签名会引用尚未建立的名义类型;保存列表用于第二阶段替换 payload。
|
||
// 保存 ui.name 的函数身份及 Operation,等全部类型注册后再为这些函数补齐精确签名。
|
||
let mut public_functions = Vec::new();
|
||
// 另外记录 TypeConstructor 所用的工厂;它们多接收一个 Type 首参,不能套用自由函数签名。
|
||
let mut factories = Vec::new();
|
||
for (name, operation) in [
|
||
("implement", Operation::Implement),
|
||
("implements", Operation::Implements),
|
||
("supports", Operation::Supports),
|
||
("isInstance", Operation::IsInstance),
|
||
("isSubtype", Operation::IsSubtype),
|
||
("open", Operation::OpenValue),
|
||
("text", Operation::Text),
|
||
("rect", Operation::Rect),
|
||
("spacer", Operation::Spacer),
|
||
("row", Operation::Row),
|
||
("column", Operation::Column),
|
||
("overlay", Operation::Overlay),
|
||
("scene2D", Operation::Scene2D),
|
||
("canvasViewport", Operation::CanvasViewport),
|
||
("camera2D", Operation::Camera2D),
|
||
("button", Operation::Button),
|
||
("page", Operation::Page),
|
||
("present", Operation::Present),
|
||
("state", Operation::State),
|
||
("textOf", Operation::TextOf),
|
||
("stats", Operation::Stats),
|
||
("viewport", Operation::Viewport),
|
||
("window", Operation::Window),
|
||
] {
|
||
// 每个名字得到自己的 VM callable,实际操作由 Function 根据 operation 分派。
|
||
// desktop 放在 captures 中,确保函数仍可达时它所依赖的类型注册表也能被 GC 追踪。
|
||
let function = vm.allocate(ContextNativeFunction::new(
|
||
name,
|
||
Function {
|
||
signature: None,
|
||
operation,
|
||
owner: None,
|
||
session: session.clone(),
|
||
requested_type: None,
|
||
},
|
||
vec![desktop],
|
||
))?;
|
||
roots.push(function);
|
||
// 属性供源程序的 ui.text/ui.present 等查询;列表供本函数第二阶段补签名,职责不同。
|
||
vm.set_attr(ui, name, Value::Object(function))?;
|
||
public_functions.push((name, function, operation));
|
||
}
|
||
// Object/Type 来自 VM 类型引导,不能用普通类代替;之后所有宿主名义类型从此根体系建立。
|
||
let root_types = vm.bootstrap_types()?;
|
||
roots.extend([root_types.object, root_types.type_type]);
|
||
vm.set_attr(ui, "Object", Value::Object(root_types.object))?;
|
||
vm.set_attr(ui, "Type", Value::Object(root_types.type_type))?;
|
||
// definitions 汇集全部类型,稍后写入 desktop.types,供 desktop_type 按名称查精确身份。
|
||
let mut definitions = vec![
|
||
("Object", root_types.object),
|
||
("Type", root_types.type_type),
|
||
];
|
||
// 类型按基类先于子类的顺序创建。None 表示抽象能力/宿主结果类型,不开放普通源构造器。
|
||
for (name, base_name, constructor_name) in [
|
||
("Trait", "Object", None),
|
||
("Function", "Object", None),
|
||
("Block", "Object", None),
|
||
("ContainerBlock", "Block", None),
|
||
("TextBlock", "Block", Some("text")),
|
||
("RectBlock", "Block", Some("rect")),
|
||
("Spacer", "Block", Some("spacer")),
|
||
("ScrollBlock", "ContainerBlock", Some("scroll")),
|
||
("ScrollView", "ScrollBlock", Some("scroll")),
|
||
("Row", "ContainerBlock", Some("row")),
|
||
("Column", "ContainerBlock", Some("column")),
|
||
("Overlay", "ContainerBlock", Some("overlay")),
|
||
("Scene2D", "ContainerBlock", Some("scene2D")),
|
||
("CanvasViewport", "ContainerBlock", Some("canvasViewport")),
|
||
("Camera2D", "Object", Some("camera2D")),
|
||
("Vec3", "Object", Some("vec3")),
|
||
("Triangle3D", "Object", Some("triangle3D")),
|
||
("Geometry3D", "Object", Some("geometry3D")),
|
||
("Mesh3D", "Object", Some("mesh3D")),
|
||
("Box3D", "Mesh3D", Some("box3D")),
|
||
("Group3D", "Object", Some("group3D")),
|
||
("Scene3D", "Object", Some("scene3D")),
|
||
("DirectionalLight", "Object", Some("directionalLight")),
|
||
("PerspectiveCamera", "Object", Some("perspectiveCamera")),
|
||
("OrthographicCamera", "Object", Some("orthographicCamera")),
|
||
("OrbitController", "Object", Some("orbitController")),
|
||
("Viewport3D", "Block", Some("viewport3D")),
|
||
("Panel3D", "Object", Some("panel3D")),
|
||
("RayHit3D", "Object", None),
|
||
("Button", "ContainerBlock", Some("button")),
|
||
("Page", "ContainerBlock", Some("page")),
|
||
("Window", "Object", Some("window-create")),
|
||
("Mount", "Object", None),
|
||
("Event", "Object", Some("event")),
|
||
("Subscription", "Object", None),
|
||
("Task", "Object", None),
|
||
("ObjectList", "Object", Some("object-list")),
|
||
] {
|
||
// 依照表中基类名取得当前 VM 的真实类型,不能用另一个 VM 中的同名 Type 代替。
|
||
let base = object(Some(&vm.get_attr(ui, base_name)?))?;
|
||
// 根据构造规则选择专用工厂、通用工厂或抽象类型;这里只注册,不分配业务实例。
|
||
let constructor = match constructor_name {
|
||
// ObjectList 与 Event 有特殊的“类型首参+子类字段”构造规则,单独原生适配;其他类型共用 NativeFactory。
|
||
Some("object-list") => {
|
||
// ObjectList 构造要保持托管元素身份与字段规则,由 object_list::Constructor 处理。
|
||
let factory = vm.allocate(ContextNativeFunction::new(
|
||
"object-list",
|
||
crate::object_list::Constructor {
|
||
desktop,
|
||
signature: None,
|
||
},
|
||
vec![desktop],
|
||
))?;
|
||
roots.push(factory);
|
||
// 工厂本身也是语言中的 Function 实例,挂类型后才能通过名义函数检查。
|
||
let function_type = object(Some(&vm.get_attr(ui, "Function")?))?;
|
||
vm.attach_type(factory, function_type)?;
|
||
TypeConstructor::NativeTyped(factory)
|
||
}
|
||
Some("event") => {
|
||
// Event 另有必填事件名;其专用 Constructor 在真正调用时解析事件参数和子类字段。
|
||
let factory = vm.allocate(ContextNativeFunction::new(
|
||
"event",
|
||
crate::event_dispatch::Constructor { signature: None },
|
||
vec![],
|
||
))?;
|
||
roots.push(factory);
|
||
// 与列表工厂保持相同函数类型体系;无 desktop 捕获的分配器不额外引入桌面强边。
|
||
let function_type = object(Some(&vm.get_attr(ui, "Function")?))?;
|
||
vm.attach_type(factory, function_type)?;
|
||
TypeConstructor::NativeTyped(factory)
|
||
}
|
||
Some(constructor_name) => {
|
||
// 把构造标签映射到宿主 Operation;3D 族委托其元数据,未知标签立即失败,不静默创建错误类型。
|
||
let operation = match constructor_name {
|
||
"text" => Operation::Text,
|
||
"rect" => Operation::Rect,
|
||
"spacer" => Operation::Spacer,
|
||
"scroll" => Operation::Scroll,
|
||
"row" => Operation::Row,
|
||
"column" => Operation::Column,
|
||
"overlay" => Operation::Overlay,
|
||
"scene2D" => Operation::Scene2D,
|
||
"canvasViewport" => Operation::CanvasViewport,
|
||
"camera2D" => Operation::Camera2D,
|
||
"viewport3D" => Operation::Viewport3D,
|
||
"button" => Operation::Button,
|
||
"page" => Operation::Page,
|
||
"window-create" => Operation::NewWindow,
|
||
name => crate::scene3d_model::Constructor::from_function(name)
|
||
.map(Operation::SceneObject)
|
||
.ok_or(invalid("unknown native type allocator"))?,
|
||
};
|
||
// 通用 NativeFactory 在调用时区分原生参数与源子类字段,并保留 requested Type。
|
||
let factory = vm.allocate(ContextNativeFunction::new(
|
||
constructor_name,
|
||
NativeFactory {
|
||
signature: None,
|
||
options: None,
|
||
operation,
|
||
session: session.clone(),
|
||
},
|
||
vec![desktop],
|
||
))?;
|
||
roots.push(factory);
|
||
// 这个函数属于构造器元数据,不直接放在 ui.name;但仍需标为 Function 实例。
|
||
let function_type = object(Some(&vm.get_attr(ui, "Function")?))?;
|
||
vm.attach_type(factory, function_type)?;
|
||
TypeConstructor::NativeTyped(factory)
|
||
}
|
||
// 没有公开分配规则的类型仍可用于类型检查/协议;直接把它当构造器调用会由 VM 拒绝。
|
||
None => TypeConstructor::Abstract,
|
||
};
|
||
// 记住实际工厂身份,类型构建完成后原地补签名,避免替换类型内指向的构造函数对象。
|
||
if let (Some(tag), TypeConstructor::NativeTyped(factory)) = (constructor_name, constructor)
|
||
{
|
||
factories.push((tag, factory));
|
||
}
|
||
// 生成新 Type 后同时公开到 ui,并加入待提交注册表,两个入口必须指向同一对象。
|
||
let definition = vm.new_type(name, base, constructor)?;
|
||
roots.push(definition);
|
||
vm.set_attr(ui, name, Value::Object(definition))?;
|
||
definitions.push((name, definition));
|
||
}
|
||
// 协议值采用普通托管类:Constraints/Bounds/Point 等字段有类型注解,PaintCommand/CameraGesture 后续再初始化属性。
|
||
for (name, fields) in [
|
||
(
|
||
"Constraints",
|
||
vec!["minWidth", "minHeight", "maxWidth", "maxHeight"],
|
||
),
|
||
("MeasureResult", vec!["width", "height"]),
|
||
("Bounds", vec!["x", "y", "width", "height"]),
|
||
("Point", vec!["x", "y"]),
|
||
("Arrangement", vec!["children"]),
|
||
("DisplayList", vec!["commands"]),
|
||
("PaintCommand", vec![]),
|
||
("CameraGesture", vec![]),
|
||
] {
|
||
// 表里的字段名转成 VM 可检查的字段声明;map 的每次调用只描述一个字段,不执行布局。
|
||
let fields = fields
|
||
.into_iter()
|
||
.map(|name| endor_core::ClassField {
|
||
name: name.into(),
|
||
// children/commands 先声明 Object 接口,后续各协议解码器再要求受控列表;几何字段统一为 Number。
|
||
type_name: if matches!(name, "children" | "commands") {
|
||
"Object"
|
||
} else {
|
||
// 余下字段都是测量/几何数值,让 VM 在实例化时先拒绝非数字实参。
|
||
"Number"
|
||
}
|
||
.into(),
|
||
})
|
||
.collect();
|
||
// 这些协议值只携带源字段,使用普通 class 分配;不需要 Block 的原生 payload。
|
||
let definition = vm.new_class(
|
||
name,
|
||
root_types.object,
|
||
fields,
|
||
std::collections::BTreeMap::new(),
|
||
)?;
|
||
roots.push(definition);
|
||
vm.set_attr(ui, name, Value::Object(definition))?;
|
||
definitions.push((name, definition));
|
||
}
|
||
// The desktop owns the registry through ordinary traced attributes. The
|
||
// Rust session only borrows handles and adds no hidden lifetime roots.
|
||
// 桌面通过普通属性拥有类型字典;后续 nominal 查询必须使用同一 desktop 中注册的精确类型身份。
|
||
// 类型字典由 desktop 属性托管持有;后续桥接调用可从其查找 Block、Event 等精确类型。
|
||
let types = vm.new_dict()?;
|
||
roots.push(types);
|
||
for (name, definition) in definitions {
|
||
// 字符串键是宿主查询约定,值才是参与 is_instance/is_subtype 的真实名义身份。
|
||
vm.dict_set(types, Value::Text(name.into()), Value::Object(definition))?;
|
||
}
|
||
vm.set_attr(desktop, "types", Value::Object(types))?;
|
||
vm.attach_type(desktop, root_types.object)?;
|
||
vm.attach_type(ui, root_types.object)?;
|
||
// 安装后续编译函数的默认类型,也用于下方所有方法 wrapper 的 attach_type。
|
||
let function_type = object(Some(&vm.get_attr(ui, "Function")?))?;
|
||
// 让后续 VM 创建的函数使用宿主 Function 名义类型,并打开源类型检查,再安装完整本机签名。
|
||
vm.set_function_type(function_type)?;
|
||
vm.set_source_type_checks(true)?;
|
||
// 以同一函数身份补完 operation_signature,不改变先前 ui 属性引用的函数对象。
|
||
for (name, function, operation) in public_functions {
|
||
vm.replace_payload(
|
||
function,
|
||
ContextNativeFunction::new(
|
||
name,
|
||
Function {
|
||
signature: Some(operation_signature(vm.object_store(), desktop, operation)?),
|
||
operation,
|
||
owner: None,
|
||
session: session.clone(),
|
||
requested_type: None,
|
||
},
|
||
vec![desktop],
|
||
),
|
||
)?;
|
||
}
|
||
for (name, function) in factories {
|
||
// 恢复第一阶段记录的分配器类别;Event/ObjectList 不走 NativeFactory,需要单独补外壳。
|
||
let operation = match name {
|
||
"text" => Some(Operation::Text),
|
||
"rect" => Some(Operation::Rect),
|
||
"spacer" => Some(Operation::Spacer),
|
||
"scroll" => Some(Operation::Scroll),
|
||
"row" => Some(Operation::Row),
|
||
"column" => Some(Operation::Column),
|
||
"overlay" => Some(Operation::Overlay),
|
||
"scene2D" => Some(Operation::Scene2D),
|
||
"canvasViewport" => Some(Operation::CanvasViewport),
|
||
"camera2D" => Some(Operation::Camera2D),
|
||
"viewport3D" => Some(Operation::Viewport3D),
|
||
"button" => Some(Operation::Button),
|
||
"page" => Some(Operation::Page),
|
||
"window-create" => Some(Operation::NewWindow),
|
||
// None 在本轮只表示专用构造器,不表示前一阶段的 Abstract 类型。
|
||
"event" | "object-list" => None,
|
||
name => Some(
|
||
crate::scene3d_model::Constructor::from_function(name)
|
||
.map(Operation::SceneObject)
|
||
.ok_or(invalid("unknown deferred factory"))?,
|
||
),
|
||
};
|
||
if let Some(operation) = operation {
|
||
// options 只描述原生构造选项,调用时由 NativeFactory 在切掉 Type 和子类字段后校验。
|
||
let options = operation_signature(vm.object_store(), desktop, operation)?;
|
||
// 外层 NativeTyped 工厂接收 Type 首参和任意候选尾参,允许子类字段;NativeFactory 用 options 再核对基构造参数。
|
||
let envelope = CallSignature {
|
||
arity: endor_core::CallArity::range(options.arity.required + 1, usize::MAX),
|
||
parameters: vec![AnnotationType::Type.into()],
|
||
variadic: Some(AnnotationType::Any.into()),
|
||
returns: options.returns.clone(),
|
||
effect: options.effect,
|
||
};
|
||
// 初始强边是注册表;随后追加签名引用的类型,供 ContextNativeFunction::trace 使用。
|
||
let mut captures = vec![desktop];
|
||
// ContextNativeFunction 自动追踪外壳 signature,但内部 options 不对它暴露;窄参数中的名义类型要额外加入 captures。
|
||
// 即使 desktop.types 当前也能保活它们,仍显式枚举 options 真正使用的引用,不把内部签名藏在不可见的 Rust 拥有图中。
|
||
captures.extend(options.references());
|
||
vm.replace_payload(
|
||
function,
|
||
ContextNativeFunction::new(
|
||
name,
|
||
NativeFactory {
|
||
signature: Some(envelope),
|
||
options: Some(options),
|
||
operation,
|
||
session: session.clone(),
|
||
},
|
||
captures,
|
||
),
|
||
)?;
|
||
} else {
|
||
// 特殊构造器保留宽变参外壳,再由对应 Constructor 按类型字段数拆实参,返回准确 Event/ObjectList 名义类型。
|
||
// 为返回值选取专用名义类型,避免宽变参外壳同时放宽了返回值检查。
|
||
let kind = if name == "event" {
|
||
// 前面已穷举通用工厂,此分支只剩 Event 和 ObjectList;这里的名字决定返回契约而不是业务实例类型。
|
||
"Event"
|
||
} else {
|
||
"ObjectList"
|
||
};
|
||
// Event 的 Type 之后还有必填字符串事件名;ObjectList 只有 Type 为必填,其余由实现解释。
|
||
let signature = CallSignature {
|
||
arity: endor_core::CallArity::range(
|
||
// 这里包含 Type 首参;源子类字段由构造器验证,所以最大个数保留开放。
|
||
if name == "event" { 2 } else { 1 },
|
||
usize::MAX,
|
||
),
|
||
// 固定前缀与 required 数量保持一致,额外实参由 variadic 和字段验证共同约束。
|
||
parameters: if name == "event" {
|
||
// Event 的事件名在外壳阶段就要求 String;随后专用构造器再拆出其余子类字段。
|
||
vec![AnnotationType::Type.into(), AnnotationType::String.into()]
|
||
} else {
|
||
// ObjectList 元素和子类字段都在开放尾参中,由构造器按 requested Type 的字段声明分界。
|
||
vec![AnnotationType::Type.into()]
|
||
},
|
||
variadic: Some(AnnotationType::Any.into()),
|
||
returns: AnnotationType::Nominal(desktop_type(vm.object_store(), kind, desktop)?)
|
||
.into(),
|
||
effect: CallEffect::ReadOnly,
|
||
};
|
||
if name == "event" {
|
||
// 原地更新 Event 工厂,TypeConstructor 中已保存的对象引用继续有效。
|
||
vm.replace_payload(
|
||
function,
|
||
ContextNativeFunction::new(
|
||
name,
|
||
crate::event_dispatch::Constructor {
|
||
signature: Some(signature),
|
||
},
|
||
vec![],
|
||
),
|
||
)?;
|
||
} else {
|
||
// 这里只有 ObjectList;保留 desktop 捕获,以便专用分配器给结果附加列表类型。
|
||
vm.replace_payload(
|
||
function,
|
||
ContextNativeFunction::new(
|
||
name,
|
||
crate::object_list::Constructor {
|
||
desktop,
|
||
signature: Some(signature),
|
||
},
|
||
vec![desktop],
|
||
),
|
||
)?;
|
||
}
|
||
}
|
||
}
|
||
// 对这批公开入口补 Function 类型身份;不重新分配 callable,ui 属性仍指向原对象。
|
||
for name in [
|
||
"open",
|
||
"text",
|
||
"rect",
|
||
"spacer",
|
||
"row",
|
||
"column",
|
||
"button",
|
||
"page",
|
||
"present",
|
||
"state",
|
||
"textOf",
|
||
"stats",
|
||
"viewport",
|
||
"window",
|
||
"isInstance",
|
||
"isSubtype",
|
||
"implement",
|
||
"implements",
|
||
"supports",
|
||
] {
|
||
// 从 ui 取回前面已补完签名的函数;名称表与安装表不一致会在这里报错而非静默漏装。
|
||
let function = object(Some(&vm.get_attr(ui, name)?))?;
|
||
vm.attach_type(function, function_type)?;
|
||
}
|
||
// 实例方法安装到对应名义类型;继承复用基类方法,TypeMethod 会验证实际接收者及参数契约。
|
||
for (type_name, name, operation) in [
|
||
("Block", "bind", Operation::Bind),
|
||
("OrbitController", "update", Operation::CameraControl),
|
||
("Mesh3D", "translate", Operation::Translate3D),
|
||
("Group3D", "translate", Operation::Translate3D),
|
||
("Panel3D", "translate", Operation::Translate3D),
|
||
("PerspectiveCamera", "translate", Operation::Translate3D),
|
||
("OrthographicCamera", "translate", Operation::Translate3D),
|
||
("Mesh3D", "rotate", Operation::Rotate3D),
|
||
("Group3D", "rotate", Operation::Rotate3D),
|
||
("Panel3D", "rotate", Operation::Rotate3D),
|
||
("Block", "mounts", Operation::Mounts),
|
||
("Block", "invalidate", Operation::Invalidate),
|
||
("Block", "onClick", Operation::OnClick),
|
||
("Block", "on", Operation::On),
|
||
("Block", "dispatch", Operation::Dispatch),
|
||
("Block", "onEvent", Operation::OnEvent),
|
||
("Block", "onMount", Operation::OnMount),
|
||
("Block", "onUnmount", Operation::OnUnmount),
|
||
("Block", "click", Operation::Click),
|
||
("TextBlock", "setText", Operation::SetText),
|
||
("TextBlock", "setColor", Operation::SetColor),
|
||
("RectBlock", "setColor", Operation::SetColor),
|
||
("ContainerBlock", "append", Operation::Append),
|
||
("ContainerBlock", "insert", Operation::Insert),
|
||
("ContainerBlock", "remove", Operation::Remove),
|
||
("ContainerBlock", "replace", Operation::Replace),
|
||
("ContainerBlock", "move", Operation::Move),
|
||
("ContainerBlock", "children", Operation::Children),
|
||
("Window", "close", Operation::CloseWindow),
|
||
("Page", "moveToWindow", Operation::MoveWindow),
|
||
("Page", "moveTab", Operation::MoveTab),
|
||
("Page", "detachToWindow", Operation::Detach),
|
||
("Page", "render", Operation::Render),
|
||
("Page", "unmount", Operation::Unmount),
|
||
("Page", "open", Operation::Open),
|
||
("Page", "window", Operation::PageWindow),
|
||
("Page", "close", Operation::Close),
|
||
("Page", "activate", Operation::Activate),
|
||
("Page", "navigate", Operation::Navigate),
|
||
("Page", "back", Operation::Back),
|
||
("Page", "forward", Operation::Forward),
|
||
] {
|
||
// expected 同时用于方法所属类型、receiver 校验和签名中的名义参数身份。
|
||
let expected = object(Some(&vm.get_attr(ui, type_name)?))?;
|
||
// VM 的方法分派负责绑定 receiver;TypeMethod 再验证它并转交 Function 执行业务操作。
|
||
let method = vm.allocate(ContextNativeFunction::new(
|
||
name,
|
||
TypeMethod {
|
||
signature: method_signature(vm.object_store(), desktop, expected, operation)?,
|
||
operation,
|
||
expected,
|
||
session: session.clone(),
|
||
},
|
||
// 方法 wrapper 捕获所属类型与桌面,保证分发和签名引用在方法仍存活时有效。
|
||
vec![expected, desktop],
|
||
))?;
|
||
roots.push(method);
|
||
vm.attach_type(method, function_type)?;
|
||
// 写到类型方法表而非每个实例的属性,实例与源子类可共享同一个原生实现。
|
||
vm.define_method(expected, name, method)?;
|
||
}
|
||
// 类型与基础方法就绪后再装窗口、默认视觉、事件方法和能力契约,顺序满足各模块查类型/方法的前提。
|
||
crate::window::install(vm, roots, desktop, tabs)?;
|
||
// 默认 measure/arrange/paint 安装到 Block 体系;源代码之后可按协议覆盖它们。
|
||
let block_type = object(Some(&vm.get_attr(ui, "Block")?))?;
|
||
crate::native_visual::install(vm, roots, desktop, block_type, function_type)?;
|
||
// 事件方法需要识别 Event 实例;订阅返回值则使用 Subscription 身份管理取消连接。
|
||
let event_type = object(Some(&vm.get_attr(ui, "Event")?))?;
|
||
// token_type 传给事件安装器,不能拿 Event 类型代替,否则取消令牌会违反返回契约。
|
||
let token_type = object(Some(&vm.get_attr(ui, "Subscription")?))?;
|
||
crate::event_dispatch::install(vm, roots, event_type, token_type, function_type)?;
|
||
crate::protocols::install(vm, roots, desktop, ui)?;
|
||
// 每个桥接域配套自己的任务 Scheduler,再接工具入口及托管起始页工厂,最后返回可使用的 UiBridge。
|
||
// Scheduler 随 UiBridge 交还运行时;它还未开始执行用户任务,只完成 ui 异步 API 注册。
|
||
let tasks = crate::tasks::install(vm, roots, ui, desktop)?;
|
||
crate::bridge::graphics::install(vm, roots, ui, desktop)?;
|
||
developer_pages::install(vm, ui, &session)?;
|
||
// 将语言命名空间、展示会话与任务调度打包,运行时随后通过同一 bridge 推进刷新与回调。
|
||
let bridge = UiBridge { ui, session, tasks };
|
||
developer_pages::install_start_page(vm, &bridge)?;
|
||
Ok(bridge)
|
||
}
|