1.2 架构总览

> **本节目标**:用一张图讲清 RML 的三层架构、五个 crates 的职责划分,以及 MVVM 数据流如何在 `.rml` 与 `.rml.rs` 之间流动。

1.2.1 三层架构

RML 把整个开发栈分为三层:表现层、框架层、编译层。三者通过清晰的契约协作。

mindmap
  root((RML 三层架构))
    表现层<br/>Presentation Layer
      .rml 视图标记
        控件树
        布局属性
        数据绑定
        事件绑定
      .rml.rs 业务逻辑
        状态字段 Model
        事件处理器
        计算属性
        生命周期回调
    编译层<br/>Compiler Layer
      RML Compiler
        build.rs / 过程宏
      四阶段流水线
        .rml 解析
        AST 转换
        语义验证
        GPUI 代码生成
    框架层<br/>Framework Layer
      GPUI 渲染引擎
      gpui-component 组件库
      RML Runtime
        绑定系统
        热重载

> 💡 **如何阅读这张思维导图**:根节点是 RML 架构整体,三大主干分支对应三层。表现层是开发者直接编辑的文件;编译层在 `build.rs` 阶段对开发者透明;框架层是运行时支撑。箭头方向(编译层)表示表现层的 `.rml` 经编译层生成 GPUI 代码后,最终落在框架层运行。

表现层(Presentation Layer)

开发者直接编辑的层,由两类文件组成:

- **`.rml`**:UI 标记文件,描述控件树、布局属性、数据绑定、事件绑定。设计师友好。 - **`.rml.rs`**:Code-Behind 文件,承载 ViewModel 角色,包含状态字段、事件处理器、计算属性、生命周期回调。工程师友好。

编译层(Compiler Layer)

由 `build.rs` 调用,对开发者透明:

1. **解析**:把 `.rml` 解析为 AST 2. **转换**:把 AST 转换为语义模型 3. **验证**:检查绑定路径、类型匹配、指令合法性 4. **生成**:输出 `.rml.generated.rs`,包含 `Render` trait 的实现

框架层(Framework Layer)

运行时支撑:

- **GPUI**:底层渲染引擎,提供 `div`、`Label`、`Entity`、`ViewContext` 等原语 - **gpui-component**:组件库,提供 `Button`、`Input`、`Dialog` 等高层组件 - **RML Runtime**:绑定系统、热重载、生命周期回调的运行时支持

1.2.2 Workspace 结构

RML 框架本身由 5 个独立 crates 组成,模块化设计便于单独复用或替换:

rml-framework/
├── Cargo.toml                          # Workspace 根配置
├── crates/
│   ├── core/                           # RML 框架核心
│   │   └── src/
│   │       ├── lib.rs                  # 核心 trait 导出
│   │       ├── view_model.rs           # ViewModel trait 定义
│   │       ├── binding.rs              # 绑定引擎
│   │       ├── command.rs              # 命令系统 (ICommand)
│   │       ├── converter.rs            # 值转换器 trait
│   │       └── lifecycle.rs            # 视图生命周期回调
│   │
│   ├── rml/                            # RML 解析引擎
│   │   └── src/
│   │       ├── parser/                 # 语法解析器
│   │       │   ├── tokenizer.rs        # HTML/XML 词法分析
│   │       │   └── ast.rs              # 抽象语法树
│   │       ├── compiler/               # 编译器 (.rml → Rust)
│   │       │   ├── codegen.rs          # 代码生成器
│   │       │   └── validator.rs        # 语义验证
│   │       └── runtime/                # 运行时支持
│   │           └── watcher.rs          # 热重载文件监听
│   │
│   ├── macros/                         # 过程宏定义
│   │   └── src/
│   │   │       ├── window.rs                 # #[window] 窗口宏
│   │       ├── component.rs            # #[component] 组件宏
│   │       ├── command.rs              # #[command] 命令宏
│   │       └── computed.rs             # #[computed] 计算属性宏
│   │
│   └── app/                            # RML 应用框架
│       └── src/
│           ├── application.rs          # 应用启动器
│           ├── window.rs               # 窗口管理
│           └── resources.rs            # 资源加载
│
├── demo/                               # 示例项目
│   ├── build.rs                        # 构建脚本
│   └── src/
│       ├── main.rs
│       ├── views/
│       │   ├── counter.rml
│       │   └── counter.rml.rs
│       ├── components/
│       │   └── button.rml
│       └── styles/
│           └── theme.rml
│
└── target/
    └── generated/                      # .rml 编译生成的 .rs 文件

各 crate 的职责

| Crate | 职责 | 依赖方向 | | ----------------- | ----------------------------------- | ----------------- | | `rml-core` | 定义 `RmlView`、`BindingContext` 等基础 trait | 被所有其他 crate 依赖 | | `rml` | 解析 `.rml`、生成 Rust 代码 | 依赖 `rml-core` | | `rml-macros` | 提供 `#[component]`、`#[window]` 等过程宏 | 依赖 `rml-core` | | `rml-app` | 应用启动器、窗口管理、资源加载 | 依赖 `rml-core`、GPUI | | `gpui-component` | 高层组件库(Button、Input、Dialog 等) | 依赖 GPUI |

💡 **设计要点**:`rml-core` 不依赖 GPUI,这意味着未来可以把 RML 编译到其他后端(如 Web、SwiftUI),只需替换 `rml` 编译器的代码生成目标。

1.2.3 MVVM 数据流

RML 完全对标 WPF 的 MVVM 模式。理解数据流是理解 RML 的关键。

┌──────────┐    数据绑定     ┌──────────┐    渲染     ┌──────────┐
│  Model   │ ◀────────────▶ │ ViewModel │ ─────────▶ │   View   │
│ (数据)   │    (双向/单向)  │  (状态)   │   (GPUI)   │  (.rml)  │
└──────────┘                └──────────┘            └──────────┘
      │                            │                       │
      ▼                            ▼                       ▼
  业务逻辑                     命令/事件                用户交互
  (Rust)                      (Rust)                  (点击/输入)

三层的职责契约

| 层级 | 文件 | 职责 | 禁止事项 | | ----------- | ------------------- | --------------------------- | --------------- | | **Model** | 任意 `.rs` | 纯数据结构、业务规则 | 不含 UI 逻辑、不依赖 GPUI | | **ViewModel** | `.rml.rs` | 持有状态、响应命令、暴露计算属性、生命周期回调 | 不构造 UI 元素 | | **View** | `.rml` | 描述结构、样式、绑定、事件 | 不含业务逻辑 |

数据流的方向

1. **用户交互** → View 触发事件 → ViewModel 的 `#[command]` 方法 2. **命令执行** → ViewModel 修改状态 → 调用 `cx.notify()` 3. **状态变更** → 绑定系统通知 View → 重新渲染受影响的部分 4. **双向绑定** → `value={field}` 自动把输入回写到 ViewModel 字段

// ViewModel 修改状态后必须调用 cx.notify() 触发重绘
#[command]
pub fn increment(&mut self, _: &ClickEvent, cx: &mut ViewContext<Self>) {
    self.count += 1;
    cx.notify();  // ← 关键:通知 View 重新读取绑定
}

⚠️ **常见错误**:忘记调用 `cx.notify()` 会导致 UI 不更新。这是 RML 开发中最常见的"为什么我的界面没反应"问题的根因。详见 [第 8 章 · 状态生命周期](../08-lifecycle/state-lifecycle.md)。

1.2.4 编译时 vs 运行时

RML 的一个核心设计决策是:**所有绑定路径检查和代码生成都在编译期完成**。

| 阶段 | 发生什么 | 开发者感知 | | ---- | --------------------------------------- | ------------- | | 编译期 | `.rml` → AST → 语义验证 → `.rml.generated.rs` | `cargo build` 时间略增 | | 运行时 | 加载生成的代码、绑定订阅、热重载监听 | 零反射、零解析开销 |

这意味着:

- ✅ 绑定路径错误在编译期暴露,不会带到运行时 - ✅ 生成的代码是原生 GPUI 调用,性能与手写一致 - ✅ IDE 可以基于生成的代码提供完整的 Rust-analyzer 补全 - ⚠️ `.rml` 修改需要重新编译(开发模式下热重载可缓解)

1.2.5 小结

RML 的架构可以用三句话概括:

1. **表现层**:`.rml` 描述 View,`.rml.rs` 承载 ViewModel,文件级分离。 2. **编译层**:`build.rs` 在编译期把 `.rml` 转为原生 GPUI 代码,零运行时开销。 3. **框架层**:GPUI 负责渲染,gpui-component 提供组件,RML Runtime 提供绑定与热重载。

掌握这张架构图,你就掌握了 RML 的"地图"。后续章节会逐层深入每一层的细节。

下一节 → [1.3 快速开始](./quick-start.md)