/**
* UnknownFields.ets
*
* 未知字段存储 - SwiftProtobuf 兼容性设计
*
* 用途:
* 1. 前后兼容性 - 旧客户端接收新服务器的消息时,保留未知字段
* 2. 消息转发 - 中间服务器不需要理解所有字段也能转发消息
* 3. 版本演进 - 允许 proto 定义向前兼容
*
* 设计理念:
* - 存储原始二进制数据(不解析)
* - 在序列化时追加到消息末尾
* - 零拷贝设计,高效内存使用
*
* Version: 1.0.0
* ArkTS 2025 兼容
*/
/**
* 未知字段存储类
*
* 当解码消息时遇到未知的字段编号(field number),
* 会将该字段的原始二进制数据保存在此对象中。
* 重新编码消息时,这些未知字段会被追加到消息末尾。
*
* 示例场景:
* 1. 服务器升级了 proto 定义,新增了字段 3
* 2. 旧客户端(只认识字段 1, 2)接收到消息
* 3. 字段 3 的数据被保存到 unknownFields
* 4. 客户端转发消息时,字段 3 的数据被完整保留
*/
export class UnknownFields {
/**
* 原始二进制数据
*
* ArkTS 注意:使用 Uint8Array 而不是 Buffer
*/
private data: Uint8Array
/**
* 构造函数
*/
constructor() {
this.data = new Uint8Array(0)
}
/**
* 追加未知字段数据
*
* @param bytes 要追加的二进制数据
*
* 注意:此方法会创建新的 Uint8Array,
* 在频繁调用时可能有性能开销。
*/
append(bytes: Uint8Array): void {
if (bytes.length === 0) {
return
}
// 创建新数组,容量为现有数据 + 新数据
const newData = new Uint8Array(this.data.length + bytes.length)
// 复制现有数据
newData.set(this.data, 0)
// 追加新数据
newData.set(bytes, this.data.length)
// 更新引用
this.data = newData
}
/**
* 判断是否为空(无未知字段)
*
* @returns true 如果没有未知字段
*/
isEmpty(): boolean {
return this.data.length === 0
}
/**
* 获取原始二进制数据
*
* @returns 未知字段的原始数据
*
* 注意:返回的是内部数组的引用,不要修改!
* 如需修改,请先调用 slice() 复制。
*/
toBytes(): Uint8Array {
return this.data
}
/**
* 获取数据长度(字节数)
*
* @returns 未知字段数据的总字节数
*/
getLength(): number {
return this.data.length
}
/**
* 清空所有未知字段
*/
clear(): void {
this.data = new Uint8Array(0)
}
/**
* 克隆未知字段对象
*
* @returns 新的 UnknownFields 对象(深拷贝)
*/
clone(): UnknownFields {
const cloned = new UnknownFields()
if (this.data.length > 0) {
// 深拷贝数据
cloned.data = new Uint8Array(this.data)
}
return cloned
}
/**
* 合并另一个 UnknownFields 对象的数据
*
* @param other 要合并的 UnknownFields 对象
*/
mergeFrom(other: UnknownFields): void {
if (!other.isEmpty()) {
this.append(other.toBytes())
}
}
/**
* 判断两个 UnknownFields 是否相等
*
* @param other 要比较的对象
* @returns true 如果内容完全相同
*/
equals(other: UnknownFields): boolean {
if (this.data.length !== other.data.length) {
return false
}
for (let i = 0; i < this.data.length; i++) {
if (this.data[i] !== other.data[i]) {
return false
}
}
return true
}
/**
* 调试输出
*
* @returns 未知字段的十六进制表示
*/
toString(): string {
if (this.isEmpty()) {
return '[UnknownFields: empty]'
}
// 转换为十六进制字符串(最多显示前 32 字节)
const maxBytes = Math.min(32, this.data.length)
let hex = ''
for (let i = 0; i < maxBytes; i++) {
const byte = this.data[i]
hex += (byte < 16 ? '0' : '') + byte.toString(16)
if (i < maxBytes - 1) {
hex += ' '
}
}
if (this.data.length > maxBytes) {
hex += ` ... (${this.data.length} bytes total)`
}
return `[UnknownFields: ${hex}]`
}
}