/** * Module definition of {@link Controller} property decorators. * * {@link Controller} decorators modify the behavior of the parser during * the reading process. These decorators are applied to properties within * a class, enabling dynamic and flexible parsing scenarios of the child * {@link Primitive.Relation} based on runtime data and conditions. * * ```mermaid * flowchart TB * subgraph s1[For each properties] * direction TB * PreOperation[__Pre__ property reading operations] --> Condition * click PreOperation "/binspector/modules/PrePost.html" "Documentation for 'Pre' type decorators" * Condition[__Condition__ get the definitive subtype to read based on current state] --> s2 * click Condition "/binspector/modules/Condition.html" "Documentation for 'Condtion' type decorators" * subgraph s2[Reading subtype] * Controller[__Controller__ decides when to stop reading the subtype based on a set of arbitrary conditions] --> TypeReading[Read __Relation__ or __Primitive__] * click Controller "/binspector/modules/Controller.html" "Documentation for 'Controller' type decorators" * click TypeReading "/binspector/modules/Primitive.html" "Documentation for 'Primitive' type decorators" * end * TypeReading --> Controller * s2 --> Transform[__Transform__ the value we read into something else] * click Transform "/binspector/modules/Transformer.html" "Documentation for 'Transformer' type decorators" * Transform --> Validate[__Validate__ the final value] * click Validate "/binspector/modules/Validator.html" "Documentation for 'Validator' type decorators" * Validate --> PostOperation[__Post__ property reading operations] * click PostOperation "/binspector/modules/PrePost.html" "Documentation for 'Post' type decorators" * end * PostOperation --> A@{ shape: framed-circle, label: "Stop" } * style Controller fill:blue,stroke:#f66,stroke-width:2px,color:#fff,stroke-dasharray: 5 5 * ``` * * The {@link Controller} decorators defines various mechanisms to provide * control over the data reading process and handling dynamic data that depends * on the parsing context. * * - **Fixed-Length Arrays**: Define arrays with a statically set or * dynamically determined by another property using the {@link Count} * decorator. * * - **Variable-Length Arrays**: Read arrays until a specific condition or * EOF marker is encountered using the {@link Until} decorator. * * - **Byte-Sized Arrays**: Read arrays until the size in byte is met * using the {@link Size} decorator. * * - **Matrix**: Use {@link Matrix} to process two-dimensional arrays * with dynamic dimensions. * * @module Controller */ import { NumberOrRecursiveKey, type PropertyMetaDescriptor, StringFormattedRecursiveKeyOf } from './common.ts'; import { type Cursor } from '../cursor.ts'; import { EOF, type DecoratorType } from '../types.ts'; export declare const ControllerSymbol: unique symbol; /** * ControllerReader */ export type ControllerReader = (arg?: any) => any; /** * ControllerOptions. * * @category Options */ export interface ControllerOptions { /** * Ensures that a relation exists before defining the Controller decorator. */ primitiveCheck: boolean; /** * Move the cursor back to its previous position when the controller condition is met. */ peek: boolean; } /** * @category Options */ export declare const ControllerOptionsDefault: { primitiveCheck: boolean; peek: boolean; }; /** * ControllerFunction. */ export type ControllerFunction = (targetInstance: This, cursor: Cursor, read: ControllerReader, opt: ControllerOptions) => any; export type OptionlessControllerFunction = (targetInstance: any, cursor: Cursor, read: ControllerReader) => any; /** * Controller type interface structure definition. * * @extends {PropertyMetaDescriptor} */ export interface Controller extends PropertyMetaDescriptor { /** * Options for controller decorator */ options: ControllerOptions; /** * Function to control the flow of execution of the binary reader */ controller: OptionlessControllerFunction; } /** * controllerDecoratorFactory. * * `controllerDecoratorFactory` is a utility function used to create `Controller` * type property decorators, used to control the execution flow of a parser in * a binary data processing context. * * * @remarks * * Use this factory function to design custom 'Controller' type decorators * tailored to specific data format requirements that are not supported by the * library yet. * * @param {string} name The name of the 'controller' type decorator. * @param {ControllerFunction} func Function to control the flow of execution of the parser. * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @category Advanced Use */ export declare function controllerDecoratorFactory(name: string, func: ControllerFunction, opt?: Partial): DecoratorType; /** * ControllerWhileFunction. */ export type ControllerWhileFunction = (curr: any, count: number, targetInstance: This, offset: number, startOffset: number) => boolean; /** * `@While` decorator continues the execution flow while the condition passed * as a parameter is met. * * By default, if the condition is not met by a value, it will be included in * the result, and the cursor will move forward. * This is the default behavior because it's the most common use case. However, * you can modify this behavior using the `peek` option. * * @example * * In the following example, the `@While` decorator is used to reads * variable-length array from binary stream until a the condition based on the * object currently read is no longer met. * * ```typescript * class BinObject { * @Uint8 * type: number * * @Uint8 * len: number * * @Count('len') * @Uint8 * blob: number[] * } * * class Protocol { * @While((obj) => obj.type !== 0x00) * @Relation(BinObject) * objs: BinObject[] * } * ``` * * You can also use the `peek` option to exclude the elements that don't meet * the condition and prevent them from being included in the result. * With this option the cursor will then be set back before the element was * read. * * ```typescript * class Protocol { * @While((elem) => elem !== 0x00, { peek: true }) * @Uint8 * array: number[] * * @Match(0x00) * @Uint8 * end_elem: number * } * ``` * * @remarks * * Don't use this decorator to compare the current value to EOF. Use {@link Until} instead. * * @typeParam This The type of the class the decorator is applied to. * @typeParam Value The type of the decorated property. * * @param {ControllerWhileFunction} func A function that returns a boolean and receives multiple arguments: * - The currently read relation * - The count * - A reference to the target instance * - The current offset * - The offset before that relation * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @category Decorators */ export declare function While(func: ControllerWhileFunction, opt?: Partial): DecoratorType; /** * `@Until` decorator reads variable-length array from binary stream until a * specified terminating character or magic number is encountered. * * The main difference between `@Until` and `@Count` is that `@Until` supports * reading data of an undefined length, terminating when a specific character * is met. This makes it useful for reading data that ends with a special * character or an EOF symbol. * * @example * * You can use this decorator to read relation or primitive until the EOF. * * ```typescript * class BinProtocol { * @Until(EOF) * @Uint8 * array: number[] * } * ``` * * @remarks * * This decorator does not accept a function as argument. * If you need to use a function to verify an equality based on the currently read value * use the {@link While} decorator instead. * * @typeParam This The type of the class the decorator is applied to. * @typeParam Value The type of the decorated property. * * @param {number | string | EOF} cmp The comparison value that indicates the * end of the reading process. This can be a specific character, number, or * the `EOF` symbol. * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @see {@link Count} * @see {@link While} * @see {@link Controller} * * @category Decorators */ export declare function Until(cmp: number | string | typeof EOF, opt?: Partial): DecoratorType; /** * `@Count` decorator defines a variable-length array based on a value you pass * as argument. * * This decorator is useful for dynamic parsing of arrays when the length is * not fixed but can be derived from another property. * * @example * * In the following example, the `@Count` decorator is used to define an array * (`vec`) whose length is determined by the value of another property (`len`): * * ```typescript * class Protocol { * @Uint8 * len: Number * * @Count('len') * @Uint8 * vec: Number * } * ``` * * @see {@link Until} * @see {@link While} * @see {@link Controller} * * @typeParam This The type of the class the decorator is applied to. * @typeParam Value The type of the decorated property. * * @param {number | string} arg The number of time to read the target property * or a string referring to a property that specifies the array length. * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @category Decorators */ export declare function Count(arg: NumberOrRecursiveKey, opt?: Partial): DecoratorType; /** * `@Size` decorator reads data until the specified size in bytes is met. * * This decorator is useful when you need to process a fixed-size amount of * data, either in bytes or based on another property that dynamically defines * the size in bytes to read. * * Binary format definitions often specify the size of sections in bytes. * These sections can have components of dynamic size, making it difficult to * deduce the exact number of components. * * @example * * In the following example, the `@Size` decorator is used to read * a specific number of bytes from a binary data stream into the decorated * property. * * ```typescript * class Protocol { * @Size(16) * @Uint16 * data: number[] // Will contain 8 numbers * } * ``` * * You can also use a string representing a property path to define the size * dynamically. * * ```typescript * class Protocol { * _size: number = 16 * * @Size('_size') * @Uint16 * data: number[] * } * ``` * * A simple literal arithmetic expression can also be used by the `@Size` * decorator. * * In the following example the `length` property include the terminator to * count the string length. The `@Size` decorator substract that number from * the size. * * ```typescript * class Protocol { * @Uint32 * length: number * * @Size('length - 1') * @Ascii * data: string * * @Match(0) * @Uint8 * terminator: number * } * ``` * * @typeParam This The type of the class the decorator is applied to. * @typeParam Value The type of the decorated property. * * @param {number | string} size The fixed size or a property path that defines * the size dynamically. * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @category Decorators */ export declare function Size(size: NumberOrRecursiveKey, opt?: Partial): DecoratorType; /** * `@MapTo` decorator map each value of an array to a child relation constructor. * This is useful when a property is an array, and you want each item in the array * to be processed by a specific relation. * * @example * * In the following example, the `@MapTo` decorator passes each element of the * array passed as an argument to the child 'Relation' (`SubProtocol`) * constructor. * The `SubProtocol` then uses this value to set the length of array of number * in the `data` property. * * ```typescript * class SubProtocol { * _size: number * * @Count('_size') * @Uint8 * data: number[] * * constructor(size: number) { * this._size = size * } * } * * class Protocol { * @MapTo([1, 2]) * @Relation(SubProtocol) * field: SubProtocol[] * } * ``` * * @typeParam This The type of the class the decorator is applied to. * @typeParam Value The type of the decorated property. * * @param {number | string} arr * @param {Partial} [opt] Optional configuration. * @returns {DecoratorType} The property decorator function. * * @category Decorators */ export declare function MapTo(arr: StringFormattedRecursiveKeyOf | any[] | ((_: This) => any[]), opt?: Partial): DecoratorType; /** * useController execute an array of `Contoller` decorator metadata on a target * instance. * * @typeParam This The type of the class the controllers belong in. * * @param {Array>} controllers Array of `Controller` decorator * metadata. * @param {This} targetInstance Current state of the object the `Controller` is * defined in, that will be passed to the `Controller` function. * @param {ControllerReader} reader Function defining how to read the next chunk * of data. * @returns {any} * * @category Advanced Use */ export declare function useController(controllers: Array>, targetInstance: This, cursor: Cursor, reader: ControllerReader): any;