import { z } from 'zod'; import { instance } from '../instance'; import { math } from '../math'; import { bounds } from '../spatial'; import { GLBufferController, GLBufferUsage } from './gl'; import { CrudeDataType, DataType, Size, TelemValue, TimeRange, TimeSpan, TimeStamp, TypedArray } from './telem'; interface IterableIterator extends Iterator, Iterable { } /** A condensed set of information describing the layout of a series. */ export interface SeriesDigest { key: string; dataType: string; sampleOffset: math.Numeric; alignment: { lower: AlignmentDigest; upper: AlignmentDigest; multiple: bigint; }; timeRange?: string; length: number; capacity: number; } interface BaseSeriesArgs { dataType?: CrudeDataType; timeRange?: TimeRange; sampleOffset?: math.Numeric; glBufferUsage?: GLBufferUsage; alignment?: bigint; alignmentMultiple?: bigint; key?: string; } /** A value or set of values that a series can be constructed from. */ export type CrudeSeries = Series | ArrayBuffer | TypedArray | string[] | number[] | boolean[] | unknown[] | TimeStamp[] | Date[] | TelemValue; /** Arguments for constructing a {@link Series}. */ export interface SeriesArgs extends BaseSeriesArgs { data?: CrudeSeries | null; } /** Arguments for allocating a {@link Series} with a given capacity and data type. */ export interface SeriesAllocArgs extends BaseSeriesArgs { capacity: number; dataType: CrudeDataType; } /** * Series is a strongly typed array of telemetry samples backed by an underlying binary * buffer. */ export declare class Series implements instance.Discriminated { /** * A unique identifier for the series. If specified by the user, it is their * responsibility to ensure that it is unique. If not specified, a new ID will be * generated. */ key: string; /** * A discriminator used for identifying instances of the series class even * when bundlers mangle the class name. */ discriminator: string; /** The data type of the series. */ readonly dataType: DataType; /** * A sample offset that can be used to shift the values of all samples upwards or * downwards. Useful to convert series to lower precision data types while preserving * the relative range of actual values. */ sampleOffset: math.Numeric; /** * Stores information about the buffer state of this array into a WebGL buffer. */ private readonly gl; /** The underlying data. */ private readonly _data; /** The time range occupied by the series' data. */ readonly timeRange: TimeRange; /** * Alignment defines the location of the series relative to other series in a logical * group. Useful for defining the position of the series within a channel's data. */ readonly alignment: bigint; /** * Alignment multiple defines the number of alignment steps taken per sample. This is * useful for when the samples in a series represent a partial view of the raw data * i.e. decimation or averaging. */ readonly alignmentMultiple: bigint; /** A cached minimum value. */ private cachedMin?; /** A cached maximum value. */ private cachedMax?; /** The write position of the buffer. */ private writePos; /** Tracks the number of entities currently using this array. */ private _refCount; /** Caches the length of the array for variable length data types. */ private cachedLength?; /** Caches the indexes of the array for variable length data types. */ private _cachedIndexes?; /** * A zod schema that can be used to validate that a particular value * can be constructed into a series. */ static readonly crudeZ: z.ZodObject<{ timeRange: z.ZodOptional, z.ZodPipe, z.ZodTransform>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe, z.ZodTransform>, z.ZodPipe, z.ZodTuple<[z.ZodInt, z.ZodInt], null>, z.ZodTuple<[z.ZodInt, z.ZodInt, z.ZodInt], null>]>, z.ZodTransform>]>; end: z.ZodUnion, z.ZodPipe, z.ZodTransform>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe, z.ZodTransform>, z.ZodPipe, z.ZodTuple<[z.ZodInt, z.ZodInt], null>, z.ZodTuple<[z.ZodInt, z.ZodInt, z.ZodInt], null>]>, z.ZodTransform>]>; }, z.core.$strip>, z.ZodTransform>, z.ZodCustom]>>; dataType: z.ZodUnion>, z.ZodCustom]>; alignment: z.ZodOptional>; data: z.ZodDefault>, z.ZodPipe, z.ZodTransform>, z.ZodCustom, z.ZodCustom, Uint8Array>]>>; glBufferUsage: z.ZodOptional>>; }, z.core.$strip>; /** * A zod schema that validates and constructs a series from it's crude * representation. */ static readonly z: z.ZodPipe, z.ZodPipe, z.ZodTransform>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe, z.ZodTransform>, z.ZodPipe, z.ZodTuple<[z.ZodInt, z.ZodInt], null>, z.ZodTuple<[z.ZodInt, z.ZodInt, z.ZodInt], null>]>, z.ZodTransform>]>; end: z.ZodUnion, z.ZodPipe, z.ZodTransform>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe>, z.ZodPipe, z.ZodTransform>, z.ZodPipe, z.ZodTuple<[z.ZodInt, z.ZodInt], null>, z.ZodTuple<[z.ZodInt, z.ZodInt, z.ZodInt], null>]>, z.ZodTransform>]>; }, z.core.$strip>, z.ZodTransform>, z.ZodCustom]>>; dataType: z.ZodUnion>, z.ZodCustom]>; alignment: z.ZodOptional>; data: z.ZodDefault>, z.ZodPipe, z.ZodTransform>, z.ZodCustom, z.ZodCustom, Uint8Array>]>>; glBufferUsage: z.ZodOptional>>; }, z.core.$strip>, z.ZodTransform, { dataType: DataType; data: ArrayBuffer | Uint8Array; timeRange?: TimeRange | undefined; alignment?: bigint | undefined; glBufferUsage?: "static" | "dynamic" | undefined; }>>; /** * The Series constructor accepts either a SeriesArgs object or a CrudeSeries value. * * SeriesArgs interface properties: * @property {CrudeSeries | null} [data] - The data to construct the series from. Can be: * - A typed array (e.g. Float32Array, Int32Array) * - A JS array of numbers, strings, or objects * - A single value (number, string, bigint, etc.) * - An ArrayBuffer * - Another Series instance * @property {CrudeDataType} [dataType] - The data type of the series. If not provided, * will be inferred from the data. Required when constructing from an ArrayBuffer, or * an empty JS array. * @property {TimeRange} [timeRange] - The time range occupied by the series' data. * Defaults to TimeRange.ZERO. * @property {math.Numeric} [sampleOffset] - An offset to apply to each sample value. * Useful for converting arrays to lower precision while preserving relative range. * Defaults to 0. * @property {GLBufferUsage} [glBufferUsage] - The WebGL buffer usage hint. Can be * "static" or "dynamic". Defaults to "static". * @property {bigint} [alignment] - The logical position of the series relative to other * series in a group. Defaults to 0n. * @property {string} [key] - A unique identifier for the series. If not provided, * a new ID will be generated. * * @example * // Create a series from a typed array * const s1 = new Series(new Float32Array([1, 2, 3])); * * @example * // Create a series from a JS array with explicit data type * const s2 = new Series({ data: [1, 2, 3], dataType: DataType.FLOAT32 }); * * @example * // Create a series from a single value (data type inferred) * const s3 = new Series(1); // Creates a FLOAT64 series * const s4 = new Series("abc"); // Creates a STRING series * const s5 = new Series(1n); // Creates an INT64 series * * @example * // Create a series from objects (automatically uses JSON data type) * const s6 = new Series([{ a: 1, b: "apple" }]); * * @example * // Create a series with time range and alignment * const s7 = new Series({ * data: new Float32Array([1, 2, 3]), * timeRange: new TimeRange(1, 2), * alignment: 1n * }); * * @example * // Create a series from another series (copies properties) * const s8 = new Series(s1); * * @example * // Create a series with sample offset * const s9 = new Series({ * data: new Float32Array([1, 2, 3]), * sampleOffset: 2 * }); // Values will be 3, 4, 5 * * @example * // Create a series with WebGL buffer usage * const s10 = new Series({ * data: new Float32Array([1, 2, 3]), * glBufferUsage: "dynamic" * }); * * @throws Error if constructing from an empty JS array without specifying data type * @throws Error if constructing from an ArrayBuffer without specifying data type * @throws Error if data type cannot be inferred from input */ constructor(props: SeriesArgs | CrudeSeries); /** * Allocates a new series with a given capacity and data type. * @param args.capacity the capacity of the series in samples. If the data type is of * variable density (i.e. JSON, STRING, BYTES), this is the capacity in bytes. * @param args.dataType the data type of the series. * @param args.rest the rest of the arguments to pass to the series constructor. */ static alloc({ capacity, dataType, ...rest }: SeriesAllocArgs): Series; /** * @returns the number of references to this series i.e. the number of times this * series has been acquired (by calling acquire) and not released (by calling * release). */ get refCount(): number; /** * Acquires a reference to this series, optionally buffering its data into the * specified buffer controller. This method is useful for managing the life span * of series buffered to the GPU. * @param gl the buffer controller to buffer the series to. If not provided, the series * will not be buffered to the GPU. */ acquire(gl?: GLBufferController): void; /** * Releases a reference to this series. If the reference count to the series reaches * 0 and the series has been buffered to the GPU, the series will be deleted from * the GPU. */ release(): void; /** * Writes the given series to this series. If the series being written exceeds the * remaining of series being written to, only the portion that fits will be written. * @param other the series to write to this series. The data type of the series written * must be the same as the data type of the series being written to. * @returns the number of samples written. If the entire series fits, this value is * equal to the length of the series being written. */ write(other: Series): number; private writeVariable; private writeFixed; private writeToUnderlyingData; /** @returns the underlying buffer backing this array. */ get buffer(): ArrayBuffer; private get underlyingData(); /** * Returns a native JS typed array with the proper data type. * If the series is not full, returns a view of the data up to the write position. * @returns A typed array containing the series data. */ get data(): TypedArray; /** * Returns an array of the values in the series as strings. * For variable length data types (like STRING or JSON), this decodes the underlying buffer. * @returns An array of string representations of the series values. */ toStrings(): string[]; /** * Parses a JSON series into an array of values using the provided zod schema. * @template Z The zod schema type. * @param schema The zod schema to use to parse the JSON series. * @throws Error if the series does not have a data type of JSON. * @returns An array of values parsed from the JSON series. */ parseJSON(schema: Z): Array>; /** * Returns the capacity of the series in bytes. * @returns The size of the underlying buffer in bytes. */ get byteCapacity(): Size; /** * Returns the capacity of the series in samples. * For variable length data types, this is the capacity in bytes. * @returns The number of samples that can be stored in the series. */ get capacity(): number; /** * Returns the length of the series in bytes. * For variable length data types, this is the actual number of bytes used. * @returns The size of the data in bytes. */ get byteLength(): Size; /** * Returns the number of samples in this array. * For variable length data types, this is calculated by scanning uint32 length prefixes. * @returns The number of samples in the series. */ get length(): number; private calculateCachedLength; /** * Creates a new array with a different data type. * @param target the data type to convert to. * @param sampleOffset an offset to apply to each sample. This can help with precision * issues when converting between data types. * * WARNING: This method is expensive and copies the entire underlying array. There * also may be untimely precision issues when converting between data types. */ convert(target: DataType, sampleOffset?: math.Numeric): Series; private calcRawMax; /** @returns the maximum value in the array */ get max(): math.Numeric; private calcMax; private calcRawMin; /** @returns the minimum value in the array */ get min(): math.Numeric; private calcMin; /** @returns the bounds of the series. */ get bounds(): bounds.Bounds; private maybeRecomputeMinMax; /** * @returns the value at the given alignment. * @param alignment the alignment to get the value at. * @param required throws an error if the value is not found. */ atAlignment(alignment: bigint, required: true): T; /** * @returns the value at the given alignment. * @param alignment the alignment to get the value at. * @param required throws an error if the value is not found. */ atAlignment(alignment: bigint, required?: false): T | undefined; /** * @returns the value at the given index. * @param index the index to get the value at. * @param required throws an error if the value is not found. */ at(index: number, required: true): T; /** * @returns the value at the given index. * @param index the index to get the value at. * @param required throws an error if the value is not found. */ at(index: number, required?: false): T | undefined; private applyOffset; private atUUID; asString(index: number, required: true): string; asString(index: number, required?: false): string | undefined; private atVariable; /** * @returns the index of the first sample that is greater than or equal to the given value. * The underlying array must be sorted. If it is not, the behavior of this method is undefined. * @param value the value to search for. */ binarySearch(value: math.Numeric): number; /** * Updates the WebGL buffer for the series if it is not up to date. This method * should be called whenever a series has been previously buffered to the GPU and * then modified via calls to write(). * @param gl the buffer controller to update the buffer for. This controller should * be the same buffer previously passed to {@method acquire} or {@method updateGLBuffer}. */ updateGLBuffer(gl: GLBufferController): void; /** * Reinterprets the series as containing strings as its JS primitive type. * @throws if the series does not have a data type of STRING or JSON. */ as(jsType: "string"): Series; /** * Reinterprets the series as containing numbers as its JS primitive type. * @throws if the series does not have a numeric data type. */ as(jsType: "number"): Series; /** * Reinterprets the series as containing bigints as its JS primitive type. * @throws if the series does not have a data type that requires bigints i.e. * INT64 and UINT64. */ as(jsType: "bigint"): Series; /** @returns a digest containing information about the series. */ get digest(): SeriesDigest; /** * @returns the alignment bounds of the series, representing the logical space * occupied by the series in a group of series. This is typically used to order the * series within a channel's data. * * The lower bound is the alignment of the first sample, and the upper bound is the * alignment of the last sample + 1. The lower bound is inclusive, while the upper bound * is exclusive. */ get alignmentBounds(): bounds.Bounds; private maybeGarbageCollectGLBuffer; /** * @returns the WebGL buffer for the series. This method should only be called after * the series has been buffered to the GPU via a call to {@method acquire} or * {@method updateGLBuffer}. * @throws if the series has not been buffered to the GPU. */ get glBuffer(): WebGLBuffer; [Symbol.iterator](): Iterator; /** * Returns a slice of the series from start to end. * @param start The start index (inclusive). * @param end The end index (exclusive). * @returns A new series containing the sliced data. */ slice(start: number, end?: number): Series; /** * Returns a subarray view of the series from start to end. * @param start The start index (inclusive). * @param end The end index (exclusive). * @returns A new series containing the subarray data. */ sub(start: number, end?: number): Series; /** * Returns an iterator over a portion of the series. * @param start The start index (inclusive). * @param end The end index (exclusive). * @returns An iterator over the specified range. */ subIterator(start: number, end?: number): Iterator; /** * Returns an iterator over a portion of the series based on alignment. * @param start The start alignment (inclusive). * @param end The end alignment (exclusive). * @returns An iterator over the specified alignment range. */ subAlignmentIterator(start: bigint, end: bigint): Iterator; private subBytes; private sliceSub; /** * Creates a new series with a different alignment. * @param alignment The new alignment value. * @returns A new series with the specified alignment. */ reAlign(alignment: bigint): Series; /** * Returns a string representation of the series. * For series with more than 10 elements, shows the first 5 and last 5 elements. * @returns A string representation of the series. */ toString(): string; } /** @returns true if a Series can be constructed from the given value, and false otherwise. */ export declare const isCrudeSeries: (value: unknown) => value is CrudeSeries; /** * MultiSeries represents a collection of Series instances that share the same data type. * It provides a unified interface for working with multiple series as if they were a single * continuous series. * */ export declare class MultiSeries implements Iterable { /** The array of series in this collection */ readonly series: Array>; /** * The MultiSeries constructor accepts an optional array of Series instances. All series * in the collection must have the same data type. * * @example * // Create an empty MultiSeries * const ms1 = new MultiSeries(); * * @example * // Create a MultiSeries from multiple numeric series * const s1 = new Series(new Float32Array([1, 2, 3])); * const s2 = new Series(new Float32Array([4, 5, 6])); * const ms2 = new MultiSeries([s1, s2]); * * @example * // Create a MultiSeries from string series * const s3 = new Series(["apple", "banana"]); * const s4 = new Series(["carrot", "date"]); * const ms3 = new MultiSeries([s3, s4]); * * @example * // Create a MultiSeries from JSON series * const s5 = new Series([{ a: 1, b: "apple" }]); * const s6 = new Series([{ a: 2, b: "banana" }]); * const ms4 = new MultiSeries([s5, s6]); * * @example * // Add series to an existing MultiSeries * const ms5 = new MultiSeries(); * ms5.push(s1); * ms5.push(s2); * * @example * // Combine two MultiSeries * const ms6 = new MultiSeries([s1]); * const ms7 = new MultiSeries([s2]); * ms6.push(ms7); * * @throws Error if attempting to add a series with a different data type */ constructor(series?: Array>); /** * Reinterprets the series as containing strings as its JS primitive type. * @throws if the series does not have a data type of STRING or JSON. */ as(jsType: "string"): MultiSeries; /** * Reinterprets the series as containing numbers as its JS primitive type. * @throws if the series does not have a numeric data type. */ as(jsType: "number"): MultiSeries; /** * Reinterprets the series as containing bigints as its JS primitive type. * @throws if the series does not have a data type that requires bigints i.e. * INT64 and UINT64. */ as(jsType: "bigint"): MultiSeries; /** * Returns the data type of the series in this collection. If the collection is empty, * returns DataType.UNKNOWN. */ get dataType(): DataType; /** * Returns the combined time range of all series in the collection. If the collection * is empty, returns TimeRange.ZERO. The time range spans from the start of the first * series to the end of the last series. */ get timeRange(): TimeRange; /** * Returns the alignment of the first series in the collection. If the collection is * empty, returns 0n. */ get alignment(): bigint; /** * Returns the alignment bounds of the entire collection. The lower bound is the * alignment of the first series, and the upper bound is the alignment of the last * series + its length. If the collection is empty, returns bounds.construct(0n, 0n). */ get alignmentBounds(): bounds.Bounds; /** * Adds a series or another MultiSeries to this collection. * @param series - The series or MultiSeries to add. Must have the same data type * as the existing series in this collection. * @throws Error if the series being added has a different data type */ push(series: Series): void; push(series: MultiSeries): void; /** * Returns the total length of all series in the collection. * @returns The sum of the lengths of all series. */ get length(): number; /** * Returns the value at the specified alignment. * @param alignment - The alignment to get the value at. * @param required - If true, throws an error if the value is not found. * @returns The value at the specified alignment, or undefined if not found. * @throws Error if required is true and the value is not found. */ atAlignment(alignment: bigint, required: true): T; atAlignment(alignment: bigint, required?: false): T | undefined; /** * Returns the value at the specified index. * @param index - The index to get the value at. * @param required - If true, throws an error if the value is not found. * @returns The value at the specified index, or undefined if not found. * @throws Error if required is true and the value is not found. */ at(index: number, required: true): T; at(index: number, required?: false): T | undefined; /** * Returns an iterator over a portion of the multi-series. * @param start - The start index (inclusive). * @param end - The end index (exclusive). * @returns An iterator over the specified range. */ subIterator(start: number, end?: number): IterableIterator; /** * Returns an iterator over a portion of the multi-series based on alignment. * @param start - The start alignment (inclusive). * @param end - The end alignment (exclusive). * @returns An iterator over the specified alignment range. */ subAlignmentIterator(start: bigint, end: bigint): IterableIterator; /** * Returns an iterator over the specified alignment range and span. * @param start - The start alignment (inclusive). * @param span - The number of samples to include. * @returns An iterator over the specified range. */ subAlignmentSpanIterator(start: bigint, span: number): IterableIterator; /** * Updates the WebGL buffer for all series in the collection. * @param gl - The WebGL buffer controller to use. */ updateGLBuffer(gl: GLBufferController): void; /** * Returns the bounds containing the minimum and maximum values across all series. */ get bounds(): bounds.Bounds; /** * Returns the sum of the byte lengths of all series. */ get byteLength(): Size; /** * Returns a combined typed array containing all data from all series. * @returns A typed array containing all data from all series. */ get data(): TypedArray; /** * Traverses the alignment space by a given distance from a start point. * @param start - The starting alignment. * @param dist - The distance to traverse. * @returns The resulting alignment after traversal. */ traverseAlignment(start: bigint, dist: bigint): bigint; /** * Acquires a reference to the WebGL buffer for all series. * @param gl - Optional WebGL buffer controller to use. */ acquire(gl?: GLBufferController): void; /** * Releases the WebGL buffer reference for all series. */ release(): void; /** * Calculates the number of samples between two alignments in the multi-series. * @param start - The starting alignment. * @param end - The ending alignment. * @returns The distance between the alignments. */ distance(start: bigint, end: bigint): bigint; /** * Parses a JSON multi-series into an array of values using the provided zod schema. * @template Z - The zod schema type. * @param schema - The zod schema to use to parse the JSON series. * @throws Error if the series does not have a data type of JSON. * @returns An array of values parsed from the JSON series. */ parseJSON(schema: Z): Array>; /** * Returns an iterator over all values in the multi-series. * @returns An iterator that yields all values from all series in sequence. */ [Symbol.iterator](): Iterator; /** * Returns an array of the values in the multi-series as strings. * For variable length data types (like STRING or JSON), this decodes the underlying buffer. * @returns An array of string representations of the multi-series values. */ toStrings(): string[]; } interface AlignmentDigest { domain: bigint; sample: bigint; } export type SeriesPayload = z.infer; export {}; //# sourceMappingURL=series.d.ts.map