diff --git a/packages/linejs/base/thrift/readwrite/tmc.test.ts b/packages/linejs/base/thrift/readwrite/tmc.test.ts new file mode 100644 index 0000000..d7dc96e --- /dev/null +++ b/packages/linejs/base/thrift/readwrite/tmc.test.ts @@ -0,0 +1,30 @@ +import { assertEquals } from "@std/assert"; +import { TMoreCompactProtocol } from "./tmc.ts"; + +Deno.test("decodeZigZag matches standard thrift zigzag for positive values", () => { + const tmc = new TMoreCompactProtocol(); + assertEquals(tmc.decodeZigZag(0), 0); + assertEquals(tmc.decodeZigZag(2), 1); + assertEquals(tmc.decodeZigZag(4), 2); + assertEquals(tmc.decodeZigZag(100), 50); + assertEquals(tmc.decodeZigZag(200), 100); +}); + +Deno.test("decodeZigZag matches standard thrift zigzag for negative values", () => { + const tmc = new TMoreCompactProtocol(); + assertEquals(tmc.decodeZigZag(1), -1); + assertEquals(tmc.decodeZigZag(3), -2); + assertEquals(tmc.decodeZigZag(5), -3); + assertEquals(tmc.decodeZigZag(7), -4); + assertEquals(tmc.decodeZigZag(199), -100); +}); + +Deno.test("decodeZigZag round-trips with standard zigzag encode", () => { + const tmc = new TMoreCompactProtocol(); + function zigzagEncode(n: number): number { + return (n << 1) ^ (n >> 31); + } + for (const v of [-1000, -100, -3, -2, -1, 0, 1, 2, 3, 100, 1000]) { + assertEquals(tmc.decodeZigZag(zigzagEncode(v)), v); + } +}); diff --git a/packages/linejs/base/thrift/readwrite/tmc.ts b/packages/linejs/base/thrift/readwrite/tmc.ts index fd4df2e..a22b921 100644 --- a/packages/linejs/base/thrift/readwrite/tmc.ts +++ b/packages/linejs/base/thrift/readwrite/tmc.ts @@ -122,7 +122,8 @@ export class TMoreCompactProtocol { // ZigZag decode decodeZigZag(encoded: number): number { - return Number((BigInt(encoded) >> 1n) * ((encoded & 1) ? -1n : 1n)); + const n = BigInt(encoded); + return Number((n >> 1n) ^ -(n & 1n)); } // Read data by type @@ -216,8 +217,8 @@ export class TMoreCompactProtocol { } } else if (typeId === 16) { // STRING (string ID delta) - const temp = BigInt(this.readVarint()); - const delta = (temp % 2n ? -1n : 1n) * (temp / 2n); + const raw = BigInt(this.readVarint()); + const delta = (raw >> 1n) ^ -(raw & 1n); const stringId = delta + this.lastStringId; this.lastStringId = stringId; value = String(stringId);