UNPKG

@ndn/tlv

Version:
142 lines (141 loc) 3.58 kB
import { asDataView, toHex } from "@ndn/util"; class Nni1 { n; constructor(n) { this.n = n; } encodeTo(encoder) { encoder.prependRoom(1)[0] = this.n; } } class Nni2 { n; constructor(n) { this.n = n; } encodeTo(encoder) { asDataView(encoder.prependRoom(2)).setUint16(0, this.n); } } class Nni4 { n; constructor(n) { this.n = n; } encodeTo(encoder) { asDataView(encoder.prependRoom(4)).setUint32(0, this.n); } } class Nni8Number { n; constructor(n) { this.n = n; } encodeTo(encoder) { const dv = asDataView(encoder.prependRoom(8)); dv.setUint32(0, this.n / 0x100000000); dv.setUint32(4, this.n); } } class Nni8Big { n; constructor(n) { this.n = n; } encodeTo(encoder) { asDataView(encoder.prependRoom(8)).setBigUint64(0, this.n); } } function decode32(dv) { switch (dv.byteLength) { case 1: { return dv.getUint8(0); } case 2: { return dv.getUint16(0); } case 4: { return dv.getUint32(0); } } throw new Error("incorrect TLV-LENGTH of NNI"); } const EncodeNniClass = { 1: Nni1, 2: Nni2, 4: Nni4, 8: Nni8Number, }; /** * Create Encodable from non-negative integer. * * @throws RangeError * Thrown if the number may lose precision and `unsafe` option is not set. */ export function NNI(n, { len, unsafe = false, } = {}) { if (len) { if (len === 8 && typeof n === "bigint") { return new Nni8Big(n); } return new EncodeNniClass[len](Number(n)); } if (typeof n === "bigint") { switch (true) { case n < 0x100000000n: { n = Number(n); break; } case n <= 0xffffffffffffffffn: { return new Nni8Big(n); } default: { throw new RangeError("NNI is too large"); } } } switch (true) { case n < 0: { throw new RangeError("NNI cannot be negative"); } case n < 0x100: { return new Nni1(n); } case n < 0x10000: { return new Nni2(n); } case n < 0x100000000: { return new Nni4(n); } case n <= (unsafe ? 0xFFFFFFFFFFFFFFFF : Number.MAX_SAFE_INTEGER): { // eslint-disable-line @typescript-eslint/no-loss-of-precision return new Nni8Number(n); } default: { throw new RangeError("NNI is too large"); } } } (function (NNI) { /** Determine if len is a valid length of encoded NNI. */ function isValidLength(len) { return !!EncodeNniClass[len]; } NNI.isValidLength = isValidLength; function decode(value, { len, big = false, unsafe = false, } = {}) { if (len && value.byteLength !== len) { throw new Error(`incorrect TLV-LENGTH of NNI${len}`); } const dv = asDataView(value); if (big) { return dv.byteLength === 8 ? dv.getBigUint64(0) : BigInt(decode32(dv)); } if (dv.byteLength === 8) { const n = dv.getUint32(0) * 0x100000000 + dv.getUint32(4); if (!unsafe && !Number.isSafeInteger(n)) { throw new RangeError(`NNI is too large ${toHex(value)}`); } return n; } return decode32(dv); } NNI.decode = decode; })(NNI || (NNI = {}));