@ndn/tlv
Version:
NDNts: TLV
142 lines (141 loc) • 3.58 kB
JavaScript
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 = {}));