@ndn/packet
Version:
NDNts: Network Layer Packets
201 lines (200 loc) • 6.46 kB
JavaScript
import { Decoder, Encoder } from "@ndn/tlv";
import { toHex } from "@ndn/util";
import { TT } from "../an_browser.js";
import { Component } from "./component_browser.js";
/**
* Name.
*
* @remarks
* This type is immutable.
*/
export class Name {
static decodeFrom(decoder) {
const { value } = decoder.read();
return new Name(value);
}
/**
* Create Name from Name or Name URI.
*
* @remarks
* This is more efficient than `new Name(input)` if input is already a Name.
*/
static from(input) {
return input instanceof Name ? input : new Name(input);
}
constructor(arg1, parseComponent = Component.from) {
if (arg1 === undefined) {
this.valueEncoderBufSize = 0;
}
else if (arg1 instanceof Name) {
this.comps = arg1.comps;
this.value_ = arg1.value_;
this.uri_ = arg1.uri_;
this.hex_ = arg1.hex_;
}
else if (typeof arg1 === "string") {
for (const comp of arg1.replace(/^(?:ndn:)?\/*/, "").split("/")) {
if (comp !== "") {
this.comps.push(parseComponent(comp));
}
}
this.valueEncoderBufSize = arg1.length + 4 * this.comps.length;
}
else if (Array.isArray(arg1)) {
this.comps = Array.from(arg1, Component.from);
}
else if (arg1 instanceof Uint8Array) {
this.value_ = arg1;
const decoder = new Decoder(this.value_);
while (!decoder.eof) {
this.comps.push(decoder.decode(Component));
}
}
}
/** List of name components. */
comps = [];
valueEncoderBufSize;
value_;
uri_;
hex_;
/** Number of name components. */
get length() {
return this.comps.length;
}
/** Name TLV-VALUE. */
get value() {
this.value_ ??= Encoder.encode(this.comps, this.valueEncoderBufSize ?? 256);
return this.value_;
}
/** Name TLV-VALUE hexadecimal representation, good for map keys. */
get valueHex() {
this.hex_ ??= toHex(this.value);
return this.hex_;
}
/**
* Retrieve i-th component.
* @param i - Component index. Negative number counts from the end.
* @returns i-th component, or `undefined` if it does not exist.
*/
get(i) {
return this.comps.at(i);
}
/**
* Retrieve i-th component.
* @param i - Component index. Negative number counts from the end.
* @returns i-th component.
*
* @throws RangeError
* Thrown if i-th component does not exist.
*/
at(i) {
const comp = this.get(i);
if (!comp) {
throw new RangeError(`component ${i} out of range`);
}
return comp;
}
/** Get URI string. */
toString() {
this.uri_ ??= `/${this.comps.map((comp) => comp.toString()).join("/")}`;
return this.uri_;
}
/** Get sub name `[begin,end)`. */
slice(begin, end) {
return new Name(this.comps.slice(begin, end));
}
/** Get prefix of `n` components. */
getPrefix(n) {
return this.slice(0, n);
}
append(...args) {
let suffix;
if (args.length === 2 &&
typeof args[0].create === "function") {
suffix = [args[0].create(args[1])];
}
else {
suffix = args;
}
return new Name([...this.comps, ...suffix]);
}
/** Return a copy of Name with i-th component replaced with `comp`. */
replaceAt(i, comp) {
return new Name(this.comps.toSpliced(i, 1, comp));
}
/** Compare with other name. */
compare(other) {
return Name.compare(this, Name.from(other));
}
/** Determine if this name equals other. */
equals(other) {
other = Name.from(other);
if (this.hex_ !== undefined && other.hex_ !== undefined) {
return this.hex_ === other.hex_;
}
return this.length === other.length && comparePrefix(this, other, this.length) === Name.CompareResult.EQUAL;
}
/** Determine if this name is a prefix of other. */
isPrefixOf(other) {
other = Name.from(other);
if (this.hex_ !== undefined && other.hex_ !== undefined) {
return other.hex_.startsWith(this.hex_);
}
return this.length <= other.length && comparePrefix(this, other, this.length) === Name.CompareResult.EQUAL;
}
encodeTo(encoder) {
if (this.value_) {
encoder.prependTlv(TT.Name, this.value_);
}
else {
encoder.prependTlv(TT.Name, ...this.comps);
}
}
}
(function (Name) {
/** Determine if obj is Name or Name URI. */
function isNameLike(obj) {
return obj instanceof Name || typeof obj === "string";
}
Name.isNameLike = isNameLike;
/** Name compare result. */
let CompareResult;
(function (CompareResult) {
/** lhs is less than, but not a prefix of rhs */
CompareResult[CompareResult["LT"] = -2] = "LT";
/** lhs is a prefix of rhs */
CompareResult[CompareResult["LPREFIX"] = -1] = "LPREFIX";
/** lhs and rhs are equal */
CompareResult[CompareResult["EQUAL"] = 0] = "EQUAL";
/** rhs is a prefix of lhs */
CompareResult[CompareResult["RPREFIX"] = 1] = "RPREFIX";
/** rhs is less than, but not a prefix of lhs */
CompareResult[CompareResult["GT"] = 2] = "GT";
})(CompareResult = Name.CompareResult || (Name.CompareResult = {}));
/** Compare two names. */
function compare(lhs, rhs) {
const commonSize = Math.min(lhs.length, rhs.length);
const cmp = comparePrefix(lhs, rhs, commonSize);
if (cmp !== CompareResult.EQUAL) {
return cmp;
}
if (lhs.length > commonSize) {
return CompareResult.RPREFIX;
}
if (rhs.length > commonSize) {
return CompareResult.LPREFIX;
}
return CompareResult.EQUAL;
}
Name.compare = compare;
})(Name || (Name = {}));
/** Compare first n components between two names. */
function comparePrefix(lhs, rhs, n) {
for (let i = 0; i < n; ++i) {
const cmp = lhs.comps[i].compare(rhs.comps[i]);
if (cmp !== Component.CompareResult.EQUAL) {
return cmp;
}
}
return Name.CompareResult.EQUAL;
}