@ndn/tlv
Version:
NDNts: TLV
138 lines (137 loc) • 4.06 kB
JavaScript
import { toHex, toUtf8 } from "@ndn/util";
import { Decoder } from "./decoder_browser.js";
import { Encoder } from "./encoder_browser.js";
import { NNI } from "./nni_browser.js";
export var StructFieldType;
(function (StructFieldType) {
/**
* Turn a TLV class into a field type, where the TLV directly appears as the field.
*
* @example
* Given this structure:
* ```abnf
* Outer = OUTER-TYPE TLV-LENGTH Inner
* Inner = INNER-TYPE TLV-LENGTH INNER-VALUE
* ```
*
* You can define the `Outer` builder:
* ```ts
* const buildOuter = new StructBuilder("Outer", TT.Outer)
* .add(TT.Inner, "inner", StructFieldType.wrap(Inner));
* ```
*
* `Inner` type must encode itself as a TLV, and its TLV-TYPE must equal field TLV-TYPE.
*/
function wrap(F, overrides = {}) {
return {
newValue: () => new F(),
encode: (value) => {
const d = new Decoder(Encoder.encode(value));
return d.read().value;
},
decode: ({ decoder }) => decoder.decode(F),
asString: (value) => value.toString(),
...overrides,
};
}
StructFieldType.wrap = wrap;
/**
* Turn a TLV class into a field type, where the TLV is nested inside the field.
*
* @example
* Given this structure:
* ```abnf
* Outer = OUTER-TYPE TLV-LENGTH Middle
* Middle = MIDDLE-TYPE TLV-LENGTH Inner
* Inner = INNER-TYPE TLV-LENGTH INNER-VALUE
* ```
*
* You can define the `Outer` builder:
* ```ts
* const buildOuter = new StructBuilder("Outer", TT.Outer)
* .add(TT.Middle, "inner", StructFieldType.nest(Inner));
* ```
*
* `Inner` type does not have to encode itself as a TLV. Its encoding result appears as
* the TLV-VALUE of the "middle" field TLV.
*/
function nest(F, overrides = {}) {
return {
newValue: () => new F(),
encode: (value) => value,
decode: ({ vd }) => vd.decode(F),
asString: (value) => value.toString(),
...overrides,
};
}
StructFieldType.nest = nest;
})(StructFieldType || (StructFieldType = {}));
export const StructFieldBool = {
newValue: () => false,
encode: (value) => value ? new Uint8Array(0) : Encoder.OmitEmpty,
decode: () => true,
};
/**
* StructBuilder field type of non-negative integer.
*
* @remarks
* The field is defined as number.
* If the field is required, it is initialized as zero.
*/
export const StructFieldNNI = {
newValue: () => 0,
encode: NNI,
decode: ({ nni }) => nni,
};
/**
* StructBuilder field type of non-negative integer.
*
* @remarks
* The field is defined as bigint.
* If the field is required, it is initialized as zero.
*/
export const StructFieldNNIBig = {
newValue: () => 0n,
encode: NNI,
decode: ({ nniBig }) => nniBig,
};
/**
* Declare a StructBuilder field type of non-negative integer from an enum.
* @param Enum - A flat (not OR'ed flags) enum type.
*
* @remarks
* The field is defined as a flat enum type.
* If the field is required, it is initialized as zero.
*/
export function StructFieldEnum(Enum) {
return {
...StructFieldNNI,
asString: (value) => `${value}(${Enum[value] ?? "unknown"})`,
};
}
/**
* StructBuilder field type of UTF-8 text.
*
* @remarks
* The field is defined as string.
* If the field is required, it is initialized as an empty string.
*/
export const StructFieldText = {
newValue: () => "",
encode: toUtf8,
decode: ({ text }) => text,
asString: (value) => JSON.stringify(value),
};
/**
* StructBuilder field type of raw bytes.
*
* @remarks
* The field is defined as Uint8Array.
* If the field is required, it is initialized as an empty Uint8Array.
*/
export const StructFieldBytes = {
newValue: () => new Uint8Array(),
encode: (value) => value,
decode: ({ value }) => value,
asString: (value) => toHex(value),
};