UNPKG

typia

Version:

Superfast runtime validators with only one line

189 lines (146 loc) 4.87 kB
import { ProtobufWire } from "../programmers/helpers/ProtobufWire"; import { Singleton } from "../utils/Singleton"; /// @reference https://github.com/piotr-oles/as-proto/blob/main/packages/as-proto/assembly/internal/FixedReader.ts export class _ProtobufReader { /** Read buffer */ private buf: Uint8Array; /** Read buffer pointer. */ private ptr: number; /** DataView for buffer. */ private view: DataView; public constructor(buf: Uint8Array) { this.buf = buf; this.ptr = 0; this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength); } public index(): number { return this.ptr; } public size(): number { return this.buf.length; } public uint32(): number { return this.varint32(); } public int32(): number { return this.varint32(); } public sint32(): number { const value: number = this.varint32(); return (value >>> 1) ^ -(value & 1); } public uint64(): bigint { return this.varint64(); } public int64(): bigint { return this.varint64(); } public sint64(): bigint { const value = this.varint64(); return (value >> BigInt(0x01)) ^ -(value & BigInt(0x01)); } public bool(): boolean { return this.varint32() !== 0; } public float(): number { const value: number = this.view.getFloat32(this.ptr, true); this.ptr += 4; return value; } public double(): number { const value: number = this.view.getFloat64(this.ptr, true); this.ptr += 8; return value; } public bytes(): Uint8Array { const length: number = this.uint32(); const from: number = this.ptr; this.ptr += length; return this.buf.subarray(from, from + length); } public string(): string { return utf8.get().decode(this.bytes()); } public skip(length: number): void { if (length === 0) while (this.u8() & 0x80); else { if (this.index() + length > this.size()) throw new Error("Error on typia.protobuf.decode(): buffer overflow."); this.ptr += length; } } public skipType(wireType: ProtobufWire): void { switch (wireType) { case ProtobufWire.VARIANT: this.skip(0); break; case ProtobufWire.I64: this.skip(8); break; case ProtobufWire.LEN: this.skip(this.uint32()); break; case ProtobufWire.START_GROUP: while ((wireType = this.uint32() & 0x07) !== ProtobufWire.END_GROUP) this.skipType(wireType); break; case ProtobufWire.I32: this.skip(4); break; default: throw new Error(`Invalid wire type ${wireType} at offset ${this.ptr}.`); } } private varint32(): number { let loaded: number; let value: number; value = (loaded = this.u8()) & 0x7f; if (loaded < 0x80) return value; value |= ((loaded = this.u8()) & 0x7f) << 7; if (loaded < 0x80) return value; value |= ((loaded = this.u8()) & 0x7f) << 14; if (loaded < 0x80) return value; value |= ((loaded = this.u8()) & 0x7f) << 21; if (loaded < 0x80) return value; value |= ((loaded = this.u8()) & 0xf) << 28; if (loaded < 0x80) return value; // increment position until there is no continuation bit or until we read 10 bytes if (this.u8() < 0x80) return value; if (this.u8() < 0x80) return value; if (this.u8() < 0x80) return value; if (this.u8() < 0x80) return value; if (this.u8() < 0x80) return value; return value; } private varint64(): bigint { let loaded: bigint; let value: bigint; value = (loaded = this.u8n()) & BigInt(0x7f); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(7); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(14); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(21); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(28); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(35); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(42); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(49); if (loaded < BigInt(0x80)) return value; value |= ((loaded = this.u8n()) & BigInt(0x7f)) << BigInt(56); if (loaded < BigInt(0x80)) return value; value |= (this.u8n() & BigInt(0x01)) << BigInt(63); return BigInt.asIntN(64, value); } private u8(): number { return this.view.getUint8(this.ptr++); } private u8n(): bigint { return BigInt(this.u8()); } } const utf8 = /** @__PURE__ */ new Singleton(() => new TextDecoder("utf-8"));