跳转至

启动文件协议

文件启动系统使用两个 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[].classrhythms[].typeresources[].type不含 :: 的短名自动补全 crate 前缀。

规则:

  • SourceNode(无 ::)+ default_crate: my_libmy_lib::SourceNode
  • other_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 — 子端口级连接
topology:
  - from: sensor              # 节点级
    to: filter
  - from: sensor.output.data  # 子端口级
    to: filter.input.raw

验证规则

ArchConfig::from_yaml() 解析时自动执行以下校验:

  1. 节点 ID 唯一 — 不允许重复
  2. 节律引用有效nodes[].rhythm 必须存在于 rhythms[]
  3. 资源引用有效nodes[].refs 的值必须存在于 resources[]
  4. 依赖引用有效depends_on 引用的节点必须存在
  5. 拓扑引用有效topology[].from/to 的根节点必须存在
  6. 无循环依赖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 传递给资源构造函数。

resources:
  shared_buf:
    capacity: 64

rhythms.<id>

节律域的初始化参数,传递给 Rhythm::from_launch_params()

rhythms:
  ticker:
    count: 5          # CountRhythm 的迭代次数
  fast_loop:
    interval_ms: 10   # SysTimer 的周期

nodes.<id>

节点的 #[param] 字段值。整个 map 经过 serde_yaml 反序列化为节点的 __Params 结构体,key 必须与 #[param] 字段名一致。

nodes:
  sensor:
    sample_rate: 1000
  filter:
    alpha: 0.5
    threshold: 2.0

类型匹配: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

rhythms:
  ticker:
    count: 5

nodes:
  source:
    start: 1
  double:
    factor: 2.0
  printer:
    prefix: "[结果]"

对应的节点定义

#[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
    └── ...

一个架构文件可搭配多个不同的参数文件运行(不触发重编译):

cargo roplat run launch/simulation/arch.yaml launch/simulation/params_indoor.yaml
cargo roplat run launch/simulation/arch.yaml launch/simulation/params_outdoor.yaml