启动文件协议
文件启动系统使用两个 YAML 文件描述一个完整的 roplat 系统。本文档定义这两个文件的格式规范。
架构文件(Architecture YAML)
读取时机:编译期(#[system(file = "...")] 或 cargo roplat generate)
修改影响:需要重新编译
完整 Schema
# 协议版本(可选,默认 "0.1")
version: "0.1"
# 默认 crate 前缀(可选)
# 不含 :: 的短类名自动拼接此前缀
# 例:default_crate: my_lib → SourceNode 解析为 my_lib::SourceNode
default_crate: <crate_name>
# 共享资源声明
resources:
- id: <resource_id> # 唯一标识
type: <rust_type_path> # 完整 Rust 类型路径
# 节律域声明
rhythms:
- id: <rhythm_id> # 唯一标识
type: <rust_type_path> # 节律驱动类型路径
# 节点声明
nodes:
- id: <node_id> # 唯一标识
class: <rust_type_path> # 类型路径(受 default_crate 影响)
rhythm: <rhythm_id> # 可选,所属节律域
depends_on: [<node_id>] # 可选,初始化依赖
refs: # 可选,资源引用映射
<field_name>: <resource_id>
hard: true # 可选,默认 false,重计算标记
# 数据流拓扑
topology:
- from: <endpoint> # node_id 或 node_id.port.subport
to: <endpoint>
字段详解
version
| 属性 | 值 |
|---|---|
| 类型 | string |
| 必填 | 否 |
| 默认 | "0.1" |
协议版本号,用于向后兼容。
default_crate
| 属性 | 值 |
|---|---|
| 类型 | string |
| 必填 | 否 |
| 默认 | 无 |
为 nodes[].class、rhythms[].type、resources[].type 中不含 :: 的短名自动补全 crate 前缀。
规则:
SourceNode(无::)+default_crate: my_lib→my_lib::SourceNodeother_lib::Foo(有::)→ 保持原样- 未设置
default_crate→ 短名保持原样(适用于同 crate 场景)
resources[]
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string |
是 | 资源唯一标识,被 nodes[].refs 引用 |
type |
string |
是 | Rust 类型完整路径,如 roplat::comm::RingBuffer<SensorData> |
资源在运行时通过 ResourceRegistry 注册和获取。
rhythms[]
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string |
是 | 节律域唯一标识,被 nodes[].rhythm 引用 |
type |
string |
是 | 节律驱动类型路径,如 roplat::rhythm::CountRhythm |
节律类型必须实现 Rhythm trait 和 from_launch_params(&serde_yaml::Value) 方法。
nodes[]
| 字段 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
id |
string |
是 | — | 节点实例唯一标识 |
class |
string |
是 | — | 节点类型路径(#[node] 标注的 struct) |
rhythm |
string |
否 | 无 | 所属节律域 ID |
depends_on |
[string] |
否 | [] |
初始化依赖的节点 ID 列表 |
refs |
map<string, string> |
否 | {} |
资源引用映射:struct 字段名 → resources[].id |
hard |
bool |
否 | false |
重计算标记(对应 #[hard]) |
类型要求:class 指向的 struct 必须使用 #[roplat::node] 标注,宏会自动生成 __system_new_from_launch 方法。
refs 映射:将节点中 #[resource] 字段绑定到 resources 中的共享资源实例。
nodes:
- id: sensor
class: SensorNode
refs:
buffer: shared_buf # SensorNode.buffer ← resources 中 id=shared_buf 的资源
depends_on:声明初始化顺序约束(非数据流依赖),用于拓扑排序。不允许循环依赖。
topology[]
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
from |
string |
是 | 数据发送端 |
to |
string |
是 | 数据接收端 |
端点格式支持多级:
node_id— 节点级连接(单输入单输出时)node_id.port— 端口级连接node_id.port.subport— 子端口级连接
验证规则
ArchConfig::from_yaml() 解析时自动执行以下校验:
- 节点 ID 唯一 — 不允许重复
- 节律引用有效 —
nodes[].rhythm必须存在于rhythms[] - 资源引用有效 —
nodes[].refs的值必须存在于resources[] - 依赖引用有效 —
depends_on引用的节点必须存在 - 拓扑引用有效 —
topology[].from/to的根节点必须存在 - 无循环依赖 —
depends_on构成的有向图必须是 DAG(Kahn 算法检测)
参数文件(Parameters YAML)
读取时机:运行时(程序启动时加载或作为命令行参数传入) 修改影响:仅需重启程序,不触发重编译
完整 Schema
# 资源参数
resources:
<resource_id>:
<key>: <value>
# 节律域参数
rhythms:
<rhythm_id>:
<key>: <value>
# 节点参数
nodes:
<node_id>:
<key>: <value>
字段详解
三个顶层 section 均为 map<string, any>,key 对应架构文件中的 id。
resources.<id>
资源的初始化参数,作为 serde_yaml::Value 传递给资源构造函数。
rhythms.<id>
节律域的初始化参数,传递给 Rhythm::from_launch_params()。
nodes.<id>
节点的 #[param] 字段值。整个 map 经过 serde_yaml 反序列化为节点的 __Params 结构体,key 必须与 #[param] 字段名一致。
类型匹配:YAML 值的类型必须与 Rust #[param] 字段类型兼容。例如 f64 字段需要提供数字值,String 字段提供字符串值。
缺省行为:未在参数文件中出现的节点/资源/节律,其参数为空 mapping({})。对应的 #[param] 字段需有默认值,否则反序列化会失败。
完整示例
arch.yaml
default_crate: file_launch
rhythms:
- id: ticker
type: roplat::rhythm::CountRhythm
nodes:
- id: source
class: SourceNode
rhythm: ticker
- id: double
class: DoubleNode
rhythm: ticker
depends_on: [source]
- id: printer
class: PrinterNode
rhythm: ticker
depends_on: [double]
topology:
- from: source
to: double
- from: double
to: printer
params.yaml
对应的节点定义
#[roplat::node]
pub struct SourceNode {
#[param]
start: i64, // ← nodes.source.start
#[state(default = "0")]
seq: i64, // ← 不在参数文件中,使用默认值
}
#[roplat::node]
pub struct DoubleNode {
#[param]
factor: f64, // ← nodes.double.factor
}
#[roplat::node]
pub struct PrinterNode {
#[param]
prefix: String, // ← nodes.printer.prefix
}
目录建议
建议将启动文件存放在 launch/ 目录下,按配置名组织:
project/
├── src/lib.rs
├── launch/
│ ├── default/
│ │ ├── arch.yaml
│ │ └── params.yaml
│ ├── simulation/
│ │ ├── arch.yaml
│ │ ├── params_indoor.yaml
│ │ └── params_outdoor.yaml
│ └── debug/
│ ├── arch.yaml
│ └── params.yaml
└── roplat/ # 生成的 bin 入口
├── arch.yaml.rs
└── ...
一个架构文件可搭配多个不同的参数文件运行(不触发重编译):