mirror of
https://github.com/motajs/template.git
synced 2026-09-30 07:20:18 +08:00
fix(07-03): #06-04-2 round-trip multi-byte and negative bigint parameters
- Encode bigint bytes by bit-shift mask instead of the broken accumulator - Decode the bigint length prefix and payload bytes unsigned - Encode negative bigint as dedicated type 8 with magnitude payload - Un-skip the multi-byte and heterogeneous bigint cases, add focused cases
This commit is contained in:
parent
528b8c91a5
commit
965e002476
@ -274,8 +274,8 @@ describe('ReplayArray param codec', () => {
|
||||
expect(firstParamToken(array)).toBe(7);
|
||||
});
|
||||
|
||||
// 疑似 bug:bigint 编码循环缺少按字节右移,多字节 bigint 只能还原最低字节,详见 06-TEST-FINDINGS.md #06-04-2,修复后取消 skip
|
||||
it.skip('round-trips a multi-byte bigint', () => {
|
||||
// 验证多字节 bigint 各幅值字节经 type 7 完整读回
|
||||
it('round-trips a multi-byte bigint', () => {
|
||||
const array = createArray();
|
||||
const value = 0x0102030405060708n;
|
||||
array.add(0, [value]);
|
||||
@ -283,6 +283,36 @@ describe('ReplayArray param codec', () => {
|
||||
expect(array.get(0).params).toEqual([value]);
|
||||
});
|
||||
|
||||
// 负 bigint 使用独立类型码 8,载荷为幅值 |n|,解码后取负(A9)
|
||||
it('round-trips negative bigint values through the dedicated type', () => {
|
||||
const negativeCases: readonly bigint[] = [
|
||||
-1n,
|
||||
-128n,
|
||||
-129n,
|
||||
-256n,
|
||||
-65537n
|
||||
];
|
||||
|
||||
for (const value of negativeCases) {
|
||||
const array = createArray();
|
||||
array.add(0, [value]);
|
||||
expectParamTyped(array.get(0).params[0], value);
|
||||
expect(firstParamToken(array)).toBe(8);
|
||||
}
|
||||
});
|
||||
|
||||
// 非负 bigint 仍为 type 7,单字节与多字节幅值逐字节不变
|
||||
it('round-trips non-negative bigint values through type 7', () => {
|
||||
const nonNegativeCases: readonly bigint[] = [100n, 0x0102030405060708n];
|
||||
|
||||
for (const value of nonNegativeCases) {
|
||||
const array = createArray();
|
||||
array.add(0, [value]);
|
||||
expectParamTyped(array.get(0).params[0], value);
|
||||
expect(firstParamToken(array)).toBe(7);
|
||||
}
|
||||
});
|
||||
|
||||
// 验证超过 int32 范围的非负 int64 参数经 type 4 精确读回
|
||||
it('round-trips int64 values above the int32 range', () => {
|
||||
const array = createArray();
|
||||
@ -320,8 +350,8 @@ describe('ReplayArray param codec', () => {
|
||||
}
|
||||
});
|
||||
|
||||
// 疑似 bug:多字节 bigint 与超 int32 的 int64 混在同一步时同样失真,详见 06-TEST-FINDINGS.md #06-04-1/#06-04-2,修复两个编码与解码缺陷后取消 skip
|
||||
it.skip('round-trips a heterogeneous step mixing a multi-byte bigint and an int64 value', () => {
|
||||
// 验证多字节 bigint 与超 int32 的 int64 混在同一步时逐参数精确读回
|
||||
it('round-trips a heterogeneous step mixing a multi-byte bigint and an int64 value', () => {
|
||||
const array = createArray();
|
||||
array.add(0, [true, 0x0102030405060708n, 2147483648, 'x']);
|
||||
|
||||
|
||||
@ -259,23 +259,20 @@ export class ReplayArray implements IReplayArray {
|
||||
byteLength: byte
|
||||
};
|
||||
} else if (typeof param === 'bigint') {
|
||||
// 7 - bigint
|
||||
// 7 - 非负 bigint / 8 - 负 bigint,均以幅值按字节写入
|
||||
const wall = 2n ** 2047n;
|
||||
if (param > wall - 1n || param < -wall) {
|
||||
logger.warn(152);
|
||||
}
|
||||
const bit = param.toString(2);
|
||||
const magnitude = param < 0n ? -param : param;
|
||||
const bit = magnitude.toString(2);
|
||||
const length = Math.ceil(bit.length / 8);
|
||||
const arr = new Uint8Array(length);
|
||||
let total = 0n;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const base = param - total;
|
||||
const remain = base % 256n;
|
||||
total += remain << (BigInt(i) * 8n);
|
||||
arr[i] = Number(remain);
|
||||
arr[i] = Number((magnitude >> (8n * BigInt(i))) & 0xffn);
|
||||
}
|
||||
return {
|
||||
paramType: 7,
|
||||
paramType: param < 0n ? 8 : 7,
|
||||
paramValue: arr,
|
||||
byteLength: arr.length + 2
|
||||
};
|
||||
@ -380,8 +377,8 @@ export class ReplayArray implements IReplayArray {
|
||||
} else if (param.paramType === 6) {
|
||||
// 6 - float
|
||||
this.paramView.setFloat64(index + 1, num);
|
||||
} else if (param.paramType === 7) {
|
||||
// 7 - bigint
|
||||
} else if (param.paramType === 7 || param.paramType === 8) {
|
||||
// 7 - 非负 bigint / 8 - 负 bigint,写入幅值字节
|
||||
this.paramArray[index + 1] = arr.length;
|
||||
this.paramArray.set(arr, index + 2);
|
||||
} else if (param.paramType === 9) {
|
||||
@ -636,16 +633,16 @@ export class ReplayArray implements IReplayArray {
|
||||
// 6 - float
|
||||
byte = 9;
|
||||
value = this.paramView.getFloat64(startIndex + 1);
|
||||
} else if (type === 7) {
|
||||
// 7 - bigint
|
||||
const length = this.paramView.getInt8(startIndex + 1);
|
||||
} else if (type === 7 || type === 8) {
|
||||
// 7 - 非负 bigint / 8 - 负 bigint,读回幅值后按类型码还原符号
|
||||
const length = this.paramView.getUint8(startIndex + 1);
|
||||
let base = 0n;
|
||||
for (let i = 0; i < length; i++) {
|
||||
const num = this.paramView.getInt8(startIndex + 2 + i);
|
||||
const num = this.paramView.getUint8(startIndex + 2 + i);
|
||||
base += BigInt(num) << (8n * BigInt(i));
|
||||
}
|
||||
byte = length + 2;
|
||||
value = base;
|
||||
value = type === 8 ? -base : base;
|
||||
} else if (type === 9) {
|
||||
// 9 - string
|
||||
const length = this.paramView.getInt32(startIndex + 1);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user