Files
Inbox/系统基座文件/2/2.5/2.5.5 序列化边界与映射策略 (Serialization Boundary & Mapping Strategy).md

139 lines
5.6 KiB
Markdown
Raw Permalink Normal View History

2025-12-11 07:24:36 +08:00
---
tags: []
date created: 星期一, 十一月 24日 2025, 11:25:58 晚上
date modified: 星期一, 十一月 24日 2025, 11:28:29 晚上
---
# 2.5.5 序列化边界与映射策略 (Serialization Boundary & Mapping Strategy)
**基线核心宗旨****“Strict Boundary, Explicit Mapping (严格边界,显式映射)”**。
严禁在核心计算流水线Signal/Data Processor中引入 Protobuf 或 JSON。序列化是 IO 密集型和 CPU 密集型的结合体,必须被隔离在系统的边缘。
-----
## 1\. 边界定义契约 (Boundary Contracts)
我们确立系统中仅有的两个**合法序列化边界 (Legal Serialization Boundaries)**
### 1.1 数据面边界:`DisplayController`
- **输入**`TrackDataPacket` (C++ Aligned Vector)。
- **输出**`TrackDataBatch` (Protobuf Binary)。
- **职责**:高频、批量、单向转换。
- **违规判定**:任何在 `SignalProcessor``DataProcessor` 中出现 `#include "track_data.pb.h"` 的代码均视为架构违规。
### 1.2 控制面边界:`ApiCommandService`
- **输入**:内部状态(如 `SystemStateMachine::State`)或配置对象。
- **输出**HTTP Response (JSON/Protobuf)。
- **职责**:低频、按需、双向转换。
-----
## 2\. 字段映射逻辑 (Mapping Logic)
这是将 **2.5.1 (Internal POD)** 转换为 **2.5.3 (External Proto)** 的具体法则。由于内部使用定长数组 (`float state[8]`) 而外部使用语义化字段 (`pos_x, vel_x`),这里需要显式的转换逻辑。
### 2.1 映射表 (Mapping Table)
| 内部字段 (C++ `TrackData`) | 外部字段 (Proto `TrackMessage`) | 转换逻辑 |
| :--- | :--- | :--- |
| `track_id` | `track_id` | 直接赋值 |
| `status` | `status` | Enum 转换 (C++ Enum -\> Proto Enum) |
| `state[0]` | `pos_x` | `state[0]` (单位转换:米 -\> 米) |
| `state[1]` | `pos_y` | `state[1]` |
| `state[2]` | `pos_z` | `state[2]` |
| `state[3]` | `vel_x` | `state[3]` |
| `state[4]` | `vel_y` | `state[4]` |
| `state[5]` | `vel_z` | `state[5]` |
| `state[6.]` (Padding) | **N/A** | **丢弃** (内部对齐填充不导出) |
| `covariance_diag[8]` | `covariance` (repeated) | 遍历数组赋值,截断填充部分 |
| `_reserved[5]` | **N/A** | **丢弃** (保留字段不导出) |
### 2.2 实现范式:转换器模式 (Converter Pattern)
建议实现一个静态的 `TypeConverter` 类,将转换逻辑集中管理,避免散落在 `DisplayController` 的业务逻辑中。
```cpp
// TypeConverter.h
class TypeConverter {
public:
// 单个对象转换In-Place 填充以减少内存分配
static void ToProto(const TrackData& src, radar::ipc::TrackMessage* dst) {
dst->set_track_id(src.track_id);
dst->set_status(static_cast<radar::ipc::TrackMessage_Status>(src.status));
// 展开定长数组
dst->set_pos_x(src.state[0]);
dst->set_pos_y(src.state[1]);
dst->set_pos_z(src.state[2]);
dst->set_vel_x(src.state[3]);
dst->set_vel_y(src.state[4]);
dst->set_vel_z(src.state[5]);
// 协方差:仅拷贝有效数据
for (int i = 0; i < 6; ++i) {
dst->add_covariance(src.covariance_diag[i]);
}
// 其他属性…
}
// 批量转换
static void ToProtoBatch(const std::vector<TrackData>& src_list,
radar::ipc::TrackDataBatch* dst_batch) {
// 预分配内存,避免 push_back 导致的扩容
dst_batch->mutable_tracks()->Reserve(src_list.size());
for (const auto& track : src_list) {
ToProto(track, dst_batch->add_tracks());
}
}
};
```
-----
## 3\. 数据清洗与脱敏规范 (Sanitization & Scrubbing)
并非所有内部数据都有资格通过“海关”。为了安全和带宽效率,必须执行清洗。
### 3.1 敏感数据清洗
- **内存地址**:内部调试用的 `void* user_data``debug_ptr` **绝对禁止**序列化。
- **原始标识符**:如果内部使用了哈希表索引或临时 Slot ID必须转换为全局唯一的 `UUID``TrackID`
### 3.2 精度截断 (Precision Truncation)
- **内部**:为了计算精度,内部可能使用 `double` 或高精度浮点。
- **外部**:若显控仅需显示到厘米级,且带宽紧张,可在转换时进行截断或转为 `float`Protobuf 中 `double` 占 8 字节,`float` 占 4 字节)。
- *基线决策*:目前 2.5.3 定义为 `double`,暂不截断,保持精度。
### 3.3 节流感知清洗 (Throttle-Aware Scrubbing)
- **机制**:结合 **2.4.4 热节流**,转换器应接受 `throttle_level` 参数。
- **逻辑**
```cpp
static void ToProtoBatch(…, int throttle_level) {
if (throttle_level >= 2) {
// Level 2: 仅导出确认航迹,且丢弃协方差矩阵以节省带宽
// 这是一个深度优化的例子:在序列化阶段就决定不拷贝某些字段
}
}
```
-----
## 总结2.5 章节整体基线图谱
至此,**2.5 数据结构定义与序列化规范** 已全部完成。我们构建了一套“内外有别、边界清晰”的数据模型。
| 领域 | 核心基线 | 关键技术点 |
| :--- | :--- | :--- |
| **2.5.1 内部对象** | **High-Perf POD** | `alignas(32)`, 定长数组SIMD 友好。 |
| **2.5.2 内部事件** | **BaseEvent 继承** | 强制 `TraceID`, 轻量级负载。 |
| **2.5.3 外部契约** | **Protobuf v3** | 语义化版本向后兼容StationID 支持。 |
| **2.5.4 数据容器** | **Move-Only Packet** | `DataPacket<T>`, `unique_ptr` 所有权管理。 |
| **2.5.5 转换边界** | **Explicit Converter** | 静态映射类,节流感知,边界清洗。 |