docs: explain Tessera modules and execution flows in Chinese

This commit is contained in:
2026-11-11 23:36:03 +08:00
parent 4c3fc8b5dd
commit 1fedd21d3c
77 changed files with 1418 additions and 0 deletions
+33
View File
@@ -1,3 +1,7 @@
//! 托管 Window 的页面所有权、原生命令与关闭生命周期。
//! 源码 resize/focus/setTitle 先产生纯数据命令;只有所属输入成功发布后,GUI 线程才应用它们。
//! 窗口 ID 和运行时 session 共同限定资源归属;切换 VM 或关闭窗口时不能让旧命令作用到新资源。
//!
//! Managed window resources and versioned, coalesced native projections.
//! The VM owns Page roots; only scalar commands cross to the GUI thread.
use crate::{native_visual, object_list, ui_bridge::desktop_type};
@@ -10,6 +14,7 @@ use std::sync::{Arc, Mutex};
pub const MAIN_WINDOW: u64 = 1;
pub const MAX_WINDOW_DIMENSION: f64 = 4096.0;
#[derive(Debug, Clone, PartialEq)]
/// 可投影到原生窗口的动作类别,如尺寸、标题、焦点与关闭。
pub enum Action {
Resize { width: f64, height: f64 },
SetTitle(String),
@@ -18,23 +23,27 @@ pub enum Action {
Close,
}
#[derive(Debug, Clone, PartialEq)]
/// 成功发布后由 GUI 执行的一条原生窗口请求,含资源身份和动作顺序。
pub struct Command {
pub window: u64,
pub sequence: u64,
pub action: Action,
}
impl Command {
/// 判断两条命令是否针对同一资源的同类动作,用于替换尚未执行的旧请求。
pub fn same_kind(&self, other: &Self) -> bool {
self.window == other.window
&& std::mem::discriminant(&self.action) == std::mem::discriminant(&other.action)
}
}
#[derive(Debug, Clone)]
/// 附带运行时 session 的命令,阻止旧域请求在新 VM 上生效。
pub struct Envelope {
pub session: u64,
pub command: Command,
}
#[derive(Debug, Clone)]
/// 托管窗口资源状态与页面拥有关系;本对象存在不等于 OS 窗口已创建。
pub struct ManagedWindow {
pub id: u64,
pub desktop: ObjectRef,
@@ -48,18 +57,23 @@ pub struct ManagedWindow {
outbox: Arc<Mutex<Vec<Command>>>,
}
impl ObjectPayload for ManagedWindow {
/// 提供受检查的 Any 下转型入口,让宿主按具体 payload 类型读取数据。
fn as_any(&self) -> &dyn std::any::Any {
self
}
/// 返回运行时诊断/类型检查使用的稳定 payload 名称。
fn kind_name(&self) -> &'static str {
"tessera-window"
}
/// 声明此 payload 是否允许使用托管属性存储,具体字段仍由类型与调用检查约束。
fn allows_attributes(&self) -> bool {
true
}
/// 声明此 payload 的赋值遵循引用身份语义,避免把内部宿主状态当作可复制值。
fn reference_assignment_only(&self) -> bool {
true
}
/// 枚举本对象真正拥有的托管强引用,供 Aster 引用追踪和循环回收使用。
fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) {
visit(self.desktop);
if let Some(tasks) = self.tasks {
@@ -71,9 +85,11 @@ impl ObjectPayload for ManagedWindow {
}
}
}
/// 统一构造本模块的参数错误,让调用方停止处理无效输入。
fn invalid(message: &'static str) -> VmError {
VmError::InvalidArgument(message)
}
/// 把源数值转换为有限屏幕坐标,拒绝越界或不可表示的值。
fn screen_coordinate(value: &Value) -> Result<i32, VmError> {
let Value::Number(value) = value else {
return Err(invalid("screen position requires integer coordinates"));
@@ -84,6 +100,7 @@ fn screen_coordinate(value: &Value) -> Result<i32, VmError> {
.and_then(|number| i32::try_from(number).ok())
.ok_or(invalid("screen position exceeds limits"))
}
/// 从源 Value 取得窗口操作需要的数值,保留错误类型诊断。
fn scalar(value: &Value) -> Result<f64, VmError> {
let Value::Number(value) = value else {
return Err(invalid("window size requires numbers"));
@@ -98,6 +115,7 @@ fn scalar(value: &Value) -> Result<f64, VmError> {
Ok(number)
}
#[derive(Debug, Clone, Copy)]
/// 当前宿主 API 的操作分类,分派代码负责参数校验与状态更新。
enum Operation {
Id,
Viewport,
@@ -108,15 +126,18 @@ enum Operation {
Focus,
}
#[derive(Debug)]
/// 保存 owner、签名或操作枚举的原生方法适配器,统一由 VM 调用。
struct Method {
signature: endor_core::CallSignature,
operation: Operation,
desktop: ObjectRef,
}
impl NativeCallable for Method {
/// 给出参数与返回值的托管类型契约;实际操作在 invoke 中执行。
fn signature(&self) -> Option<endor_core::CallSignature> {
Some(self.signature.clone())
}
/// 声明宿主可调用对象接受的参数个数,供 VM 在执行前检查。
fn arity(&self) -> Option<endor_core::CallArity> {
Some(endor_core::CallArity::exact(match self.operation {
Operation::Resize | Operation::MoveTo => 3,
@@ -125,6 +146,7 @@ impl NativeCallable for Method {
}))
}
/// VM 调入本宿主能力的入口;按所属操作解码参数并返回托管值或后续调用。
fn invoke(&self, cx: &mut NativeContext<'_>, args: &[Value]) -> Result<NativeResult, VmError> {
let Some(Value::Object(owner)) = args.first() else {
return Err(invalid("Window method requires a Window"));
@@ -196,6 +218,7 @@ impl NativeCallable for Method {
Ok(NativeResult::Return(result))
}
}
/// 把合法窗口操作追加到所属窗口的待发布命令,不能直接在 VM 线程操作 OS。
pub fn enqueue(
cx: &mut NativeContext<'_>,
owner: ObjectRef,
@@ -225,6 +248,7 @@ pub fn enqueue(
Ok(())
}
/// 将页面登记到其窗口,维护托管所有权与页面顺序。
pub fn register_page(
cx: &mut NativeContext<'_>,
window: ObjectRef,
@@ -253,6 +277,7 @@ pub fn register_page(
}
Ok(())
}
/// 从窗口的页面集合撤销指定页面,保持后续展示索引一致。
pub fn unregister_page(
cx: &mut NativeContext<'_>,
window: ObjectRef,
@@ -276,6 +301,7 @@ pub fn unregister_page(
Ok(())
}
/// Discard an unpublished Page registration without invoking guest callbacks.
/// 宿主收尾路径撤销页面登记,用于已经由外层决定的关闭/退役流程。
pub fn unregister_page_host(
vm: &mut Vm,
window: ObjectRef,
@@ -290,6 +316,7 @@ pub fn unregister_page_host(
Ok(())
}
/// 在窗口之间移动页面的所有权和登记顺序,保留同一业务页面身份。
pub fn move_page(
cx: &mut NativeContext<'_>,
window: ObjectRef,
@@ -323,9 +350,11 @@ pub fn move_page(
}
Ok(())
}
/// 借用一个有效托管窗口的已登记页面集合。
pub fn pages(store: &ObjectStore, window: ObjectRef) -> Result<&[ObjectRef], VmError> {
Ok(&store.payload::<ManagedWindow>(window, "Window")?.pages)
}
/// 取走当前窗口累积的命令,后续由成功发布结果携带到 GUI。
pub fn take_commands(vm: &Vm, window: ObjectRef) -> Result<Vec<Command>, VmError> {
let data = vm.payload::<ManagedWindow>(window, "Window")?;
let mut queue = data
@@ -336,6 +365,7 @@ pub fn take_commands(vm: &Vm, window: ObjectRef) -> Result<Vec<Command>, VmError
commands.sort_by_key(|command| command.sequence);
Ok(commands)
}
/// 把本模块的类型、方法或能力注册到所属运行时上下文。
pub fn install(
vm: &mut Vm,
roots: &mut Vec<ObjectRef>,
@@ -413,6 +443,7 @@ pub fn install(
/// Create a managed native-window resource. The GUI creates the OS resource only
/// after the owning candidate/input publishes its immutable projection.
/// 建立托管窗口、desktop 与页面容器;原生窗口通过命令发布后出现。
pub fn create(
cx: &mut NativeContext<'_>,
master: ObjectRef,
@@ -449,6 +480,7 @@ pub fn create(
Ok((window, desktop, tabs))
}
/// 发起窗口关闭和相应生命周期清理,拒绝重复或不再有效的操作。
pub fn close(cx: &mut NativeContext<'_>, window: ObjectRef) -> Result<(), VmError> {
if cx.store().is_read_only() {
return Err(invalid(
@@ -477,6 +509,7 @@ pub fn close(cx: &mut NativeContext<'_>, window: ObjectRef) -> Result<(), VmErro
}
/// Host teardown for a stopped VM: no binding, dispatch or source execution.
/// 撤销已失效窗口的托管资源关系,不重新执行源关闭请求。
pub fn retire(vm: &mut Vm, window: ObjectRef) -> Result<(), VmError> {
let mut data = vm.payload::<ManagedWindow>(window, "Window")?.clone();
vm.dict_clear(data.tabs)?;