typescript JavaScript/类型脚本:将UUID从最高有效位(MSB)/最低有效位(LSB)表示转换为字符串

bvjveswy  于 2023-02-10  发布在  TypeScript
关注(0)|答案(1)|浏览(207)

为了在使用协议缓冲区传递UUID时保存空间,我们使用MSB/LSB表示法(两个64位long值)发送它们。

message Uuid {
  sfixed64 msb = 1;
  sfixed64 lsb = 2;
}

在Java中很容易进入和退出它们,

UUID id = UUID.fromString("eb66c416-4739-465b-9af3-9dc33ed8eef9");
long msb = id.getMostSignificantBits();
long lsb = id.getLeastSignificantBits();
System.out.println(msb + ", " + lsb);
  // -1484283427208739237, -7281302710629372167

System.out.println(new UUID(msb, lsb));
  // eb66c416-4739-465b-9af3-9dc33ed8eef9

但是,由于JavaScript的number最高只能达到253 - 1,我无法在TypeScript客户端中将MSB/LSB格式转换回string

rqmkfv5c

rqmkfv5c1#

从Javax 1 m0n1x的toString()方法中寻找灵感,

public String toString() {
  return (digits(mostSigBits >> 32, 8) + "-" +
    digits(mostSigBits >> 16, 4) + "-" +
    digits(mostSigBits, 4) + "-" +
    digits(leastSigBits >> 48, 4) + "-" +
    digits(leastSigBits, 12));
}

private static String digits(long val, int digits) {
  long hi = 1L << (digits * 4);
  return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}

我们可以使用BigInt执行相同的操作。这里假设节点为10.8+(使用18.14.0测试),TypeScript目标为ES 2020+,并且与此浏览器兼容。

注意:如果您得到“BigInt literals are not available...”,则将所有以n结尾的文字 Package 为BigInt(例如,使用BigInt(32)代替32n)。

function uuidSigBitsToStr({ lsb, msb }: { lsb: bigint; msb: bigint }): string {
  return `${digits(msb >> 32n, 8n)}-${digits(msb >> 16n, 4n)}-${digits(
    msb,
    4n
  )}-${digits(lsb >> 48n, 4n)}-${digits(lsb, 12n)}`;
}

function digits(val: bigint, ds: bigint): string {
  const hi = 1n << (ds * 4n);
  return (hi | (val & (hi - 1n))).toString(16).substring(1);
}

示例测试中,注意MSB/LSB作为string s传递到BigInt

it('converts UUID from msb/lsb to string', () => {
  expect(
    toUuidString(
      BigInt('-1160168401362026442'),
      BigInt('-6694969989912915968')
    )
  ).toEqual('a316b044-0157-1000-efe6-40fc5d2f0036');
});

最后一部分是协议缓冲区。默认情况下,google-protobuf使用number作为64位floatint值,这会导致溢出超过Number.MAX_VALUE或253 - 1。要避免这种情况,请在64位字段上使用jstype注解。

message Uuid {
    sfixed64 msb = 1 [jstype = JS_STRING];
    sfixed64 lsb = 2 [jstype = JS_STRING];
}

2023年更新:相反函数,从UUID字符串转换为有效位

function uuidStrToSigBits(uuid: string) {
  const invalidError = () => new Error(`Invalid UUID string: '${uuid}'`);
  if (uuid == null || typeof uuid !== "string") throw invalidError();

  const parts = uuid.split("-").map((p) => `0x${p}`);
  if (parts.length !== 5) throw invalidError();

  return {
    lsb: (hexStrToBigInt(parts[3]) << 48n) | hexStrToBigInt(parts[4]),
    msb:
      (hexStrToBigInt(parts[0]) << 32n) |
      (hexStrToBigInt(parts[1]) << 16n) |
      hexStrToBigInt(parts[2]),
  };
}

function hexStrToBigInt(hex: string): bigint {
  return BigInt(Number.parseInt(hex, 16));
}

这是一个往返测试

const uuidSigBits = uuidStrToSigBits("7680fc63-1f58-412a-9bde-c5a9de1e0ce9");
const uuidStr = uuidSigBitsToStr(uuidSigBits);
console.log(uuidStr);
  // => 7680fc63-1f58-412a-9bde-c5a9de1e0ce9

相关问题