@solana/codecs-data-structures 6.3.1 → 6.3.2-canary-20260313143218
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -5
- package/src/array.ts +300 -0
- package/src/assertions.ts +16 -0
- package/src/bit-array.ts +203 -0
- package/src/boolean.ts +163 -0
- package/src/bytes.ts +115 -0
- package/src/constant.ts +135 -0
- package/src/discriminated-union.ts +384 -0
- package/src/enum-helpers.ts +102 -0
- package/src/enum.ts +309 -0
- package/src/hidden-prefix.ts +180 -0
- package/src/hidden-suffix.ts +180 -0
- package/src/index.ts +30 -0
- package/src/literal-union.ts +249 -0
- package/src/map.ts +285 -0
- package/src/nullable.ts +356 -0
- package/src/pattern-match.ts +312 -0
- package/src/predicate.ts +214 -0
- package/src/set.ts +206 -0
- package/src/struct.ts +239 -0
- package/src/tuple.ts +228 -0
- package/src/union.ts +257 -0
- package/src/unit.ts +111 -0
- package/src/utils.ts +32 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import {
|
|
3
|
+
Codec,
|
|
4
|
+
combineCodec,
|
|
5
|
+
Decoder,
|
|
6
|
+
Encoder,
|
|
7
|
+
FixedSizeCodec,
|
|
8
|
+
FixedSizeDecoder,
|
|
9
|
+
FixedSizeEncoder,
|
|
10
|
+
transformDecoder,
|
|
11
|
+
transformEncoder,
|
|
12
|
+
} from '@solana/codecs-core';
|
|
13
|
+
import { getU8Decoder, getU8Encoder, NumberCodec, NumberDecoder, NumberEncoder } from '@solana/codecs-numbers';
|
|
14
|
+
import { SOLANA_ERROR__CODECS__INVALID_DISCRIMINATED_UNION_VARIANT, SolanaError } from '@solana/errors';
|
|
15
|
+
|
|
16
|
+
import { getTupleDecoder, getTupleEncoder } from './tuple';
|
|
17
|
+
import { getUnionDecoder, getUnionEncoder } from './union';
|
|
18
|
+
import { DrainOuterGeneric } from './utils';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Represents a discriminated union using a specific discriminator property.
|
|
22
|
+
*
|
|
23
|
+
* A discriminated union is a TypeScript-friendly way to represent Rust-like enums.
|
|
24
|
+
* Each variant in the union is distinguished by a shared discriminator property.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam TDiscriminatorProperty - The name of the discriminator property.
|
|
27
|
+
* @typeParam TDiscriminatorValue - The type of the discriminator value.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* type Message =
|
|
32
|
+
* | { __kind: 'Quit' } // Empty variant
|
|
33
|
+
* | { __kind: 'Write'; fields: [string] } // Tuple variant
|
|
34
|
+
* | { __kind: 'Move'; x: number; y: number }; // Struct variant
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export type DiscriminatedUnion<
|
|
38
|
+
TDiscriminatorProperty extends string = '__kind',
|
|
39
|
+
TDiscriminatorValue extends string = string,
|
|
40
|
+
> = {
|
|
41
|
+
[P in TDiscriminatorProperty]: TDiscriminatorValue;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Extracts a variant from a discriminated union based on its discriminator value.
|
|
46
|
+
*
|
|
47
|
+
* @typeParam TUnion - The discriminated union type.
|
|
48
|
+
* @typeParam TDiscriminatorProperty - The property used as the discriminator.
|
|
49
|
+
* @typeParam TDiscriminatorValue - The specific variant to extract.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* type Message =
|
|
54
|
+
* | { __kind: 'Quit' }
|
|
55
|
+
* | { __kind: 'Write'; fields: [string] }
|
|
56
|
+
* | { __kind: 'Move'; x: number; y: number };
|
|
57
|
+
*
|
|
58
|
+
* type ClickEvent = GetDiscriminatedUnionVariant<Message, '__kind', 'Move'>;
|
|
59
|
+
* // -> { __kind: 'Move'; x: number; y: number }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export type GetDiscriminatedUnionVariant<
|
|
63
|
+
TUnion extends DiscriminatedUnion<TDiscriminatorProperty>,
|
|
64
|
+
TDiscriminatorProperty extends string,
|
|
65
|
+
TDiscriminatorValue extends TUnion[TDiscriminatorProperty],
|
|
66
|
+
> = Extract<TUnion, DiscriminatedUnion<TDiscriminatorProperty, TDiscriminatorValue>>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extracts a variant from a discriminated union without its discriminator property.
|
|
70
|
+
*
|
|
71
|
+
* @typeParam TUnion - The discriminated union type.
|
|
72
|
+
* @typeParam TDiscriminatorProperty - The property used as the discriminator.
|
|
73
|
+
* @typeParam TDiscriminatorValue - The specific variant to extract.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* type Message =
|
|
78
|
+
* | { __kind: 'Quit' }
|
|
79
|
+
* | { __kind: 'Write'; fields: [string] }
|
|
80
|
+
* | { __kind: 'Move'; x: number; y: number };
|
|
81
|
+
*
|
|
82
|
+
* type MoveContent = GetDiscriminatedUnionVariantContent<Message, '__kind', 'Move'>;
|
|
83
|
+
* // -> { x: number; y: number }
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export type GetDiscriminatedUnionVariantContent<
|
|
87
|
+
TUnion extends DiscriminatedUnion<TDiscriminatorProperty>,
|
|
88
|
+
TDiscriminatorProperty extends string,
|
|
89
|
+
TDiscriminatorValue extends TUnion[TDiscriminatorProperty],
|
|
90
|
+
> = Omit<GetDiscriminatedUnionVariant<TUnion, TDiscriminatorProperty, TDiscriminatorValue>, TDiscriminatorProperty>;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Defines the configuration for discriminated union codecs.
|
|
94
|
+
*
|
|
95
|
+
* This configuration controls how the discriminator is stored and named.
|
|
96
|
+
*
|
|
97
|
+
* @typeParam TDiscriminatorProperty - The property name of the discriminator.
|
|
98
|
+
* @typeParam TDiscriminatorSize - The codec used for the discriminator prefix.
|
|
99
|
+
*/
|
|
100
|
+
export type DiscriminatedUnionCodecConfig<
|
|
101
|
+
TDiscriminatorProperty extends string = '__kind',
|
|
102
|
+
TDiscriminatorSize = NumberCodec | NumberDecoder | NumberEncoder,
|
|
103
|
+
> = {
|
|
104
|
+
/**
|
|
105
|
+
* The property name of the discriminator.
|
|
106
|
+
* @defaultValue `__kind`
|
|
107
|
+
*/
|
|
108
|
+
discriminator?: TDiscriminatorProperty;
|
|
109
|
+
/**
|
|
110
|
+
* The codec used to encode/decode the discriminator prefix.
|
|
111
|
+
* @defaultValue `u8` prefix
|
|
112
|
+
*/
|
|
113
|
+
size?: TDiscriminatorSize;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
type DiscriminatorValue = bigint | boolean | number | string | null | undefined;
|
|
117
|
+
type Variants<T> = readonly (readonly [DiscriminatorValue, T])[];
|
|
118
|
+
type ArrayIndices<T extends readonly unknown[]> = Exclude<Partial<T>['length'], T['length']> & number;
|
|
119
|
+
|
|
120
|
+
type GetEncoderTypeFromVariants<
|
|
121
|
+
TVariants extends Variants<Encoder<any>>,
|
|
122
|
+
TDiscriminatorProperty extends string,
|
|
123
|
+
> = DrainOuterGeneric<{
|
|
124
|
+
[I in ArrayIndices<TVariants>]: (TVariants[I][1] extends Encoder<infer TFrom>
|
|
125
|
+
? TFrom extends object
|
|
126
|
+
? TFrom
|
|
127
|
+
: object
|
|
128
|
+
: never) & { [P in TDiscriminatorProperty]: TVariants[I][0] };
|
|
129
|
+
}>[ArrayIndices<TVariants>];
|
|
130
|
+
|
|
131
|
+
type GetDecoderTypeFromVariants<
|
|
132
|
+
TVariants extends Variants<Decoder<any>>,
|
|
133
|
+
TDiscriminatorProperty extends string,
|
|
134
|
+
> = DrainOuterGeneric<{
|
|
135
|
+
[I in ArrayIndices<TVariants>]: (TVariants[I][1] extends Decoder<infer TTo>
|
|
136
|
+
? TTo extends object
|
|
137
|
+
? TTo
|
|
138
|
+
: object
|
|
139
|
+
: never) & { [P in TDiscriminatorProperty]: TVariants[I][0] };
|
|
140
|
+
}>[ArrayIndices<TVariants>];
|
|
141
|
+
|
|
142
|
+
type UnionEncoder<TVariants extends Variants<Encoder<unknown>>, TDiscriminatorProperty extends string> =
|
|
143
|
+
TVariants extends Variants<FixedSizeEncoder<any>>
|
|
144
|
+
? FixedSizeEncoder<GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>>
|
|
145
|
+
: Encoder<GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>>;
|
|
146
|
+
|
|
147
|
+
type UnionDecoder<TVariants extends Variants<Decoder<unknown>>, TDiscriminatorProperty extends string> =
|
|
148
|
+
TVariants extends Variants<FixedSizeDecoder<any>>
|
|
149
|
+
? FixedSizeDecoder<GetDecoderTypeFromVariants<TVariants, TDiscriminatorProperty>>
|
|
150
|
+
: Decoder<GetDecoderTypeFromVariants<TVariants, TDiscriminatorProperty>>;
|
|
151
|
+
|
|
152
|
+
type UnionCodec<TVariants extends Variants<Codec<unknown, unknown>>, TDiscriminatorProperty extends string> =
|
|
153
|
+
TVariants extends Variants<FixedSizeCodec<any, any>>
|
|
154
|
+
? FixedSizeCodec<
|
|
155
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>,
|
|
156
|
+
GetDecoderTypeFromVariants<TVariants, TDiscriminatorProperty> &
|
|
157
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>
|
|
158
|
+
>
|
|
159
|
+
: Codec<
|
|
160
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>,
|
|
161
|
+
GetDecoderTypeFromVariants<TVariants, TDiscriminatorProperty> &
|
|
162
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>
|
|
163
|
+
>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Returns an encoder for discriminated unions.
|
|
167
|
+
*
|
|
168
|
+
* This encoder serializes objects that follow the discriminated union pattern
|
|
169
|
+
* by prefixing them with a numerical discriminator that represents their variant.
|
|
170
|
+
*
|
|
171
|
+
* Unlike {@link getUnionEncoder}, this encoder automatically extracts and processes
|
|
172
|
+
* the discriminator property (default: `__kind`) from each variant.
|
|
173
|
+
*
|
|
174
|
+
* For more details, see {@link getDiscriminatedUnionCodec}.
|
|
175
|
+
*
|
|
176
|
+
* @typeParam TVariants - The variants of the discriminated union.
|
|
177
|
+
* @typeParam TDiscriminatorProperty - The property used as the discriminator.
|
|
178
|
+
*
|
|
179
|
+
* @param variants - The variant encoders as `[discriminator, encoder]` pairs.
|
|
180
|
+
* @param config - Configuration options for encoding.
|
|
181
|
+
* @returns An `Encoder` for encoding discriminated union objects.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* Encoding a discriminated union.
|
|
185
|
+
* ```ts
|
|
186
|
+
* type Message =
|
|
187
|
+
* | { __kind: 'Quit' } // Empty variant.
|
|
188
|
+
* | { __kind: 'Write'; fields: [string] } // Tuple variant.
|
|
189
|
+
* | { __kind: 'Move'; x: number; y: number }; // Struct variant.
|
|
190
|
+
*
|
|
191
|
+
* const messageEncoder = getDiscriminatedUnionEncoder([
|
|
192
|
+
* ['Quit', getUnitEncoder()],
|
|
193
|
+
* ['Write', getStructEncoder([['fields', getTupleEncoder([addCodecSizePrefix(getUtf8Encoder(), getU32Encoder())])]])],
|
|
194
|
+
* ['Move', getStructEncoder([['x', getI32Encoder()], ['y', getI32Encoder()]])]
|
|
195
|
+
* ]);
|
|
196
|
+
*
|
|
197
|
+
* messageEncoder.encode({ __kind: 'Move', x: 5, y: 6 });
|
|
198
|
+
* // 0x020500000006000000
|
|
199
|
+
* // | | └── Field y (6)
|
|
200
|
+
* // | └── Field x (5)
|
|
201
|
+
* // └── 1-byte discriminator (Index 2 — the "Move" variant)
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @see {@link getDiscriminatedUnionCodec}
|
|
205
|
+
*/
|
|
206
|
+
export function getDiscriminatedUnionEncoder<
|
|
207
|
+
const TVariants extends Variants<Encoder<any>>,
|
|
208
|
+
const TDiscriminatorProperty extends string = '__kind',
|
|
209
|
+
>(
|
|
210
|
+
variants: TVariants,
|
|
211
|
+
config: DiscriminatedUnionCodecConfig<TDiscriminatorProperty, NumberEncoder> = {},
|
|
212
|
+
): UnionEncoder<TVariants, TDiscriminatorProperty> {
|
|
213
|
+
type TFrom = GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>;
|
|
214
|
+
const discriminatorProperty = (config.discriminator ?? '__kind') as TDiscriminatorProperty;
|
|
215
|
+
const prefix = config.size ?? getU8Encoder();
|
|
216
|
+
return getUnionEncoder(
|
|
217
|
+
variants.map(([, variant], index) =>
|
|
218
|
+
transformEncoder(getTupleEncoder([prefix, variant]), (value: TFrom): [number, TFrom] => [index, value]),
|
|
219
|
+
),
|
|
220
|
+
value => getVariantDiscriminator(variants, value[discriminatorProperty]),
|
|
221
|
+
) as UnionEncoder<TVariants, TDiscriminatorProperty>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Returns a decoder for discriminated unions.
|
|
226
|
+
*
|
|
227
|
+
* This decoder deserializes objects that follow the discriminated union pattern
|
|
228
|
+
* by **reading a numerical discriminator** and mapping it to the corresponding variant.
|
|
229
|
+
*
|
|
230
|
+
* Unlike {@link getUnionDecoder}, this decoder automatically inserts the discriminator
|
|
231
|
+
* property (default: `__kind`) into the decoded object.
|
|
232
|
+
*
|
|
233
|
+
* For more details, see {@link getDiscriminatedUnionCodec}.
|
|
234
|
+
*
|
|
235
|
+
* @typeParam TVariants - The variants of the discriminated union.
|
|
236
|
+
* @typeParam TDiscriminatorProperty - The property used as the discriminator.
|
|
237
|
+
*
|
|
238
|
+
* @param variants - The variant decoders as `[discriminator, decoder]` pairs.
|
|
239
|
+
* @param config - Configuration options for decoding.
|
|
240
|
+
* @returns A `Decoder` for decoding discriminated union objects.
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* Decoding a discriminated union.
|
|
244
|
+
* ```ts
|
|
245
|
+
* type Message =
|
|
246
|
+
* | { __kind: 'Quit' } // Empty variant.
|
|
247
|
+
* | { __kind: 'Write'; fields: [string] } // Tuple variant.
|
|
248
|
+
* | { __kind: 'Move'; x: number; y: number }; // Struct variant.
|
|
249
|
+
*
|
|
250
|
+
* const messageDecoder = getDiscriminatedUnionDecoder([
|
|
251
|
+
* ['Quit', getUnitDecoder()],
|
|
252
|
+
* ['Write', getStructDecoder([['fields', getTupleDecoder([addCodecSizePrefix(getUtf8Decoder(), getU32Decoder())])]])],
|
|
253
|
+
* ['Move', getStructDecoder([['x', getI32Decoder()], ['y', getI32Decoder()]])]
|
|
254
|
+
* ]);
|
|
255
|
+
*
|
|
256
|
+
* messageDecoder.decode(new Uint8Array([0x02,0x05,0x00,0x00,0x00,0x06,0x00,0x00,0x00]));
|
|
257
|
+
* // { __kind: 'Move', x: 5, y: 6 }
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* @see {@link getDiscriminatedUnionCodec}
|
|
261
|
+
*/
|
|
262
|
+
export function getDiscriminatedUnionDecoder<
|
|
263
|
+
const TVariants extends Variants<Decoder<any>>,
|
|
264
|
+
const TDiscriminatorProperty extends string = '__kind',
|
|
265
|
+
>(
|
|
266
|
+
variants: TVariants,
|
|
267
|
+
config: DiscriminatedUnionCodecConfig<TDiscriminatorProperty, NumberDecoder> = {},
|
|
268
|
+
): UnionDecoder<TVariants, TDiscriminatorProperty> {
|
|
269
|
+
const discriminatorProperty = config.discriminator ?? '__kind';
|
|
270
|
+
const prefix = config.size ?? getU8Decoder();
|
|
271
|
+
return getUnionDecoder(
|
|
272
|
+
variants.map(([discriminator, variant]) =>
|
|
273
|
+
transformDecoder(getTupleDecoder([prefix, variant]), ([, value]) => ({
|
|
274
|
+
[discriminatorProperty]: discriminator,
|
|
275
|
+
...value,
|
|
276
|
+
})),
|
|
277
|
+
),
|
|
278
|
+
(bytes, offset) => Number(prefix.read(bytes, offset)[0]),
|
|
279
|
+
) as UnionDecoder<TVariants, TDiscriminatorProperty>;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Returns a codec for encoding and decoding {@link DiscriminatedUnion}.
|
|
284
|
+
*
|
|
285
|
+
* A {@link DiscriminatedUnion} is a TypeScript representation of Rust-like enums, where
|
|
286
|
+
* each variant is distinguished by a discriminator field (default: `__kind`).
|
|
287
|
+
*
|
|
288
|
+
* This codec inserts a numerical prefix to represent the variant index.
|
|
289
|
+
*
|
|
290
|
+
* @typeParam TVariants - The variants of the discriminated union.
|
|
291
|
+
* @typeParam TDiscriminatorProperty - The property used as the discriminator.
|
|
292
|
+
*
|
|
293
|
+
* @param variants - The variant codecs as `[discriminator, codec]` pairs.
|
|
294
|
+
* @param config - Configuration options for encoding/decoding.
|
|
295
|
+
* @returns A `Codec` for encoding and decoding discriminated union objects.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* Encoding and decoding a discriminated union.
|
|
299
|
+
* ```ts
|
|
300
|
+
* type Message =
|
|
301
|
+
* | { __kind: 'Quit' } // Empty variant.
|
|
302
|
+
* | { __kind: 'Write'; fields: [string] } // Tuple variant.
|
|
303
|
+
* | { __kind: 'Move'; x: number; y: number }; // Struct variant.
|
|
304
|
+
*
|
|
305
|
+
* const messageCodec = getDiscriminatedUnionCodec([
|
|
306
|
+
* ['Quit', getUnitCodec()],
|
|
307
|
+
* ['Write', getStructCodec([['fields', getTupleCodec([addCodecSizePrefix(getUtf8Codec(), getU32Codec())])]])],
|
|
308
|
+
* ['Move', getStructCodec([['x', getI32Codec()], ['y', getI32Codec()]])]
|
|
309
|
+
* ]);
|
|
310
|
+
*
|
|
311
|
+
* messageCodec.encode({ __kind: 'Move', x: 5, y: 6 });
|
|
312
|
+
* // 0x020500000006000000
|
|
313
|
+
* // | | └── Field y (6)
|
|
314
|
+
* // | └── Field x (5)
|
|
315
|
+
* // └── 1-byte discriminator (Index 2 — the "Move" variant)
|
|
316
|
+
*
|
|
317
|
+
* const value = messageCodec.decode(bytes);
|
|
318
|
+
* // { __kind: 'Move', x: 5, y: 6 }
|
|
319
|
+
* ```
|
|
320
|
+
*
|
|
321
|
+
* @example
|
|
322
|
+
* Using a `u32` discriminator instead of `u8`.
|
|
323
|
+
* ```ts
|
|
324
|
+
* const codec = getDiscriminatedUnionCodec([...], { size: getU32Codec() });
|
|
325
|
+
*
|
|
326
|
+
* codec.encode({ __kind: 'Quit' });
|
|
327
|
+
* // 0x00000000
|
|
328
|
+
* // └------┘ 4-byte discriminator (Index 0)
|
|
329
|
+
*
|
|
330
|
+
* codec.decode(new Uint8Array([0x00, 0x00, 0x00, 0x00]));
|
|
331
|
+
* // { __kind: 'Quit' }
|
|
332
|
+
* ```
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* Customizing the discriminator property.
|
|
336
|
+
* ```ts
|
|
337
|
+
* const codec = getDiscriminatedUnionCodec([...], { discriminator: 'message' });
|
|
338
|
+
*
|
|
339
|
+
* codec.encode({ message: 'Quit' }); // 0x00
|
|
340
|
+
* codec.decode(new Uint8Array([0x00])); // { message: 'Quit' }
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @remarks
|
|
344
|
+
* Separate `getDiscriminatedUnionEncoder` and `getDiscriminatedUnionDecoder` functions are available.
|
|
345
|
+
*
|
|
346
|
+
* ```ts
|
|
347
|
+
* const bytes = getDiscriminatedUnionEncoder(variantEncoders).encode({ __kind: 'Quit' });
|
|
348
|
+
* const message = getDiscriminatedUnionDecoder(variantDecoders).decode(bytes);
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @see {@link getDiscriminatedUnionEncoder}
|
|
352
|
+
* @see {@link getDiscriminatedUnionDecoder}
|
|
353
|
+
*/
|
|
354
|
+
export function getDiscriminatedUnionCodec<
|
|
355
|
+
const TVariants extends Variants<Codec<any, any>>,
|
|
356
|
+
const TDiscriminatorProperty extends string = '__kind',
|
|
357
|
+
>(
|
|
358
|
+
variants: TVariants,
|
|
359
|
+
config: DiscriminatedUnionCodecConfig<TDiscriminatorProperty, NumberCodec> = {},
|
|
360
|
+
): UnionCodec<TVariants, TDiscriminatorProperty> {
|
|
361
|
+
return combineCodec(
|
|
362
|
+
getDiscriminatedUnionEncoder(variants, config) as Encoder<
|
|
363
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>
|
|
364
|
+
>,
|
|
365
|
+
getDiscriminatedUnionDecoder(variants, config) as Decoder<
|
|
366
|
+
GetDecoderTypeFromVariants<TVariants, TDiscriminatorProperty> &
|
|
367
|
+
GetEncoderTypeFromVariants<TVariants, TDiscriminatorProperty>
|
|
368
|
+
>,
|
|
369
|
+
) as UnionCodec<TVariants, TDiscriminatorProperty>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function getVariantDiscriminator<const TVariants extends Variants<Decoder<any> | Encoder<any>>>(
|
|
373
|
+
variants: TVariants,
|
|
374
|
+
discriminatorValue: DiscriminatorValue,
|
|
375
|
+
) {
|
|
376
|
+
const discriminator = variants.findIndex(([key]) => discriminatorValue === key);
|
|
377
|
+
if (discriminator < 0) {
|
|
378
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_DISCRIMINATED_UNION_VARIANT, {
|
|
379
|
+
value: discriminatorValue,
|
|
380
|
+
variants: variants.map(([key]) => key),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
return discriminator;
|
|
384
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defines the "lookup object" of an enum.
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* enum Direction { Left, Right };
|
|
7
|
+
* ```
|
|
8
|
+
*/
|
|
9
|
+
export type EnumLookupObject = { [key: string]: number | string };
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns the allowed input for an enum.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* enum Direction { Left, Right };
|
|
17
|
+
* type DirectionInput = GetEnumFrom<Direction>; // "Left" | "Right" | 0 | 1
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export type GetEnumFrom<TEnum extends EnumLookupObject> = TEnum[keyof TEnum] | keyof TEnum;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns all the available variants of an enum.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* enum Direction { Left, Right };
|
|
28
|
+
* type DirectionOutput = GetEnumTo<Direction>; // 0 | 1
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export type GetEnumTo<TEnum extends EnumLookupObject> = TEnum[keyof TEnum];
|
|
32
|
+
|
|
33
|
+
export function getEnumStats(constructor: EnumLookupObject) {
|
|
34
|
+
const numericalValues = [...new Set(Object.values(constructor).filter(v => typeof v === 'number'))].sort();
|
|
35
|
+
const enumRecord = Object.fromEntries(Object.entries(constructor).slice(numericalValues.length)) as Record<
|
|
36
|
+
string,
|
|
37
|
+
number | string
|
|
38
|
+
>;
|
|
39
|
+
const enumKeys = Object.keys(enumRecord);
|
|
40
|
+
const enumValues = Object.values(enumRecord);
|
|
41
|
+
const stringValues: string[] = [
|
|
42
|
+
...new Set([...enumKeys, ...enumValues.filter((v): v is string => typeof v === 'string')]),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
return { enumKeys, enumRecord, enumValues, numericalValues, stringValues };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function getEnumIndexFromVariant({
|
|
49
|
+
enumKeys,
|
|
50
|
+
enumValues,
|
|
51
|
+
variant,
|
|
52
|
+
}: {
|
|
53
|
+
enumKeys: string[];
|
|
54
|
+
enumValues: (number | string)[];
|
|
55
|
+
variant: number | string | symbol;
|
|
56
|
+
}): number {
|
|
57
|
+
const valueIndex = findLastIndex(enumValues, value => value === variant);
|
|
58
|
+
if (valueIndex >= 0) return valueIndex;
|
|
59
|
+
return enumKeys.findIndex(key => key === variant);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function getEnumIndexFromDiscriminator({
|
|
63
|
+
discriminator,
|
|
64
|
+
enumKeys,
|
|
65
|
+
enumValues,
|
|
66
|
+
useValuesAsDiscriminators,
|
|
67
|
+
}: {
|
|
68
|
+
discriminator: number;
|
|
69
|
+
enumKeys: string[];
|
|
70
|
+
enumValues: (number | string)[];
|
|
71
|
+
useValuesAsDiscriminators: boolean;
|
|
72
|
+
}): number {
|
|
73
|
+
if (!useValuesAsDiscriminators) {
|
|
74
|
+
return discriminator >= 0 && discriminator < enumKeys.length ? discriminator : -1;
|
|
75
|
+
}
|
|
76
|
+
return findLastIndex(enumValues, value => value === discriminator);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function findLastIndex<T>(array: Array<T>, predicate: (value: T, index: number, obj: T[]) => boolean): number {
|
|
80
|
+
let l = array.length;
|
|
81
|
+
while (l--) {
|
|
82
|
+
if (predicate(array[l], l, array)) return l;
|
|
83
|
+
}
|
|
84
|
+
return -1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function formatNumericalValues(values: number[]): string {
|
|
88
|
+
if (values.length === 0) return '';
|
|
89
|
+
let range: [number, number] = [values[0], values[0]];
|
|
90
|
+
const ranges: string[] = [];
|
|
91
|
+
for (let index = 1; index < values.length; index++) {
|
|
92
|
+
const value = values[index];
|
|
93
|
+
if (range[1] + 1 === value) {
|
|
94
|
+
range[1] = value;
|
|
95
|
+
} else {
|
|
96
|
+
ranges.push(range[0] === range[1] ? `${range[0]}` : `${range[0]}-${range[1]}`);
|
|
97
|
+
range = [value, value];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ranges.push(range[0] === range[1] ? `${range[0]}` : `${range[0]}-${range[1]}`);
|
|
101
|
+
return ranges.join(', ');
|
|
102
|
+
}
|