@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
package/src/enum.ts
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Codec,
|
|
3
|
+
combineCodec,
|
|
4
|
+
Decoder,
|
|
5
|
+
Encoder,
|
|
6
|
+
FixedSizeCodec,
|
|
7
|
+
FixedSizeDecoder,
|
|
8
|
+
FixedSizeEncoder,
|
|
9
|
+
transformDecoder,
|
|
10
|
+
transformEncoder,
|
|
11
|
+
VariableSizeCodec,
|
|
12
|
+
VariableSizeDecoder,
|
|
13
|
+
VariableSizeEncoder,
|
|
14
|
+
} from '@solana/codecs-core';
|
|
15
|
+
import {
|
|
16
|
+
FixedSizeNumberCodec,
|
|
17
|
+
FixedSizeNumberDecoder,
|
|
18
|
+
FixedSizeNumberEncoder,
|
|
19
|
+
getU8Decoder,
|
|
20
|
+
getU8Encoder,
|
|
21
|
+
NumberCodec,
|
|
22
|
+
NumberDecoder,
|
|
23
|
+
NumberEncoder,
|
|
24
|
+
} from '@solana/codecs-numbers';
|
|
25
|
+
import {
|
|
26
|
+
SOLANA_ERROR__CODECS__CANNOT_USE_LEXICAL_VALUES_AS_ENUM_DISCRIMINATORS,
|
|
27
|
+
SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE,
|
|
28
|
+
SOLANA_ERROR__CODECS__INVALID_ENUM_VARIANT,
|
|
29
|
+
SolanaError,
|
|
30
|
+
} from '@solana/errors';
|
|
31
|
+
|
|
32
|
+
import {
|
|
33
|
+
EnumLookupObject,
|
|
34
|
+
formatNumericalValues,
|
|
35
|
+
GetEnumFrom,
|
|
36
|
+
getEnumIndexFromDiscriminator,
|
|
37
|
+
getEnumIndexFromVariant,
|
|
38
|
+
getEnumStats,
|
|
39
|
+
GetEnumTo,
|
|
40
|
+
} from './enum-helpers';
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Defines the configuration options for enum codecs.
|
|
44
|
+
*
|
|
45
|
+
* The `size` option determines the numerical encoding used for the enum's discriminant.
|
|
46
|
+
* By default, enums are stored as a `u8` (1 byte).
|
|
47
|
+
*
|
|
48
|
+
* The `useValuesAsDiscriminators` option allows mapping the actual enum values
|
|
49
|
+
* as discriminators instead of using their positional index.
|
|
50
|
+
*
|
|
51
|
+
* @typeParam TDiscriminator - A number codec, encoder, or decoder used for the discriminant.
|
|
52
|
+
*/
|
|
53
|
+
export type EnumCodecConfig<TDiscriminator extends NumberCodec | NumberDecoder | NumberEncoder> = {
|
|
54
|
+
/**
|
|
55
|
+
* The codec used to encode/decode the enum discriminator.
|
|
56
|
+
* @defaultValue `u8` discriminator.
|
|
57
|
+
*/
|
|
58
|
+
size?: TDiscriminator;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* If set to `true`, the enum values themselves will be used as discriminators.
|
|
62
|
+
* This is only valid for numerical enum values.
|
|
63
|
+
*
|
|
64
|
+
* @defaultValue `false`
|
|
65
|
+
*/
|
|
66
|
+
useValuesAsDiscriminators?: boolean;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns an encoder for enums.
|
|
71
|
+
*
|
|
72
|
+
* This encoder serializes enums as a numerical discriminator.
|
|
73
|
+
* By default, the discriminator is based on the positional index of the enum variants.
|
|
74
|
+
*
|
|
75
|
+
* For more details, see {@link getEnumCodec}.
|
|
76
|
+
*
|
|
77
|
+
* @typeParam TEnum - The TypeScript enum or object mapping enum keys to values.
|
|
78
|
+
*
|
|
79
|
+
* @param constructor - The constructor of the enum.
|
|
80
|
+
* @param config - Configuration options for encoding the enum.
|
|
81
|
+
* @returns A `FixedSizeEncoder` or `VariableSizeEncoder` for encoding enums.
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* Encoding enum values.
|
|
85
|
+
* ```ts
|
|
86
|
+
* enum Direction { Up, Down, Left, Right }
|
|
87
|
+
* const encoder = getEnumEncoder(Direction);
|
|
88
|
+
*
|
|
89
|
+
* encoder.encode(Direction.Up); // 0x00
|
|
90
|
+
* encoder.encode(Direction.Down); // 0x01
|
|
91
|
+
* encoder.encode(Direction.Left); // 0x02
|
|
92
|
+
* encoder.encode(Direction.Right); // 0x03
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @see {@link getEnumCodec}
|
|
96
|
+
*/
|
|
97
|
+
export function getEnumEncoder<TEnum extends EnumLookupObject>(
|
|
98
|
+
constructor: TEnum,
|
|
99
|
+
config?: Omit<EnumCodecConfig<NumberEncoder>, 'size'>,
|
|
100
|
+
): FixedSizeEncoder<GetEnumFrom<TEnum>, 1>;
|
|
101
|
+
export function getEnumEncoder<TEnum extends EnumLookupObject, TSize extends number>(
|
|
102
|
+
constructor: TEnum,
|
|
103
|
+
config: EnumCodecConfig<NumberEncoder> & { size: FixedSizeNumberEncoder<TSize> },
|
|
104
|
+
): FixedSizeEncoder<GetEnumFrom<TEnum>, TSize>;
|
|
105
|
+
export function getEnumEncoder<TEnum extends EnumLookupObject>(
|
|
106
|
+
constructor: TEnum,
|
|
107
|
+
config?: EnumCodecConfig<NumberEncoder>,
|
|
108
|
+
): VariableSizeEncoder<GetEnumFrom<TEnum>>;
|
|
109
|
+
export function getEnumEncoder<TEnum extends EnumLookupObject>(
|
|
110
|
+
constructor: TEnum,
|
|
111
|
+
config: EnumCodecConfig<NumberEncoder> = {},
|
|
112
|
+
): Encoder<GetEnumFrom<TEnum>> {
|
|
113
|
+
const prefix = config.size ?? getU8Encoder();
|
|
114
|
+
const useValuesAsDiscriminators = config.useValuesAsDiscriminators ?? false;
|
|
115
|
+
const { enumKeys, enumValues, numericalValues, stringValues } = getEnumStats(constructor);
|
|
116
|
+
if (useValuesAsDiscriminators && enumValues.some(value => typeof value === 'string')) {
|
|
117
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__CANNOT_USE_LEXICAL_VALUES_AS_ENUM_DISCRIMINATORS, {
|
|
118
|
+
stringValues: enumValues.filter((v): v is string => typeof v === 'string'),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return transformEncoder(prefix, (variant: GetEnumFrom<TEnum>): number => {
|
|
122
|
+
const index = getEnumIndexFromVariant({ enumKeys, enumValues, variant });
|
|
123
|
+
if (index < 0) {
|
|
124
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_ENUM_VARIANT, {
|
|
125
|
+
formattedNumericalValues: formatNumericalValues(numericalValues),
|
|
126
|
+
numericalValues,
|
|
127
|
+
stringValues,
|
|
128
|
+
variant,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return useValuesAsDiscriminators ? (enumValues[index] as number) : index;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Returns a decoder for enums.
|
|
137
|
+
*
|
|
138
|
+
* This decoder deserializes enums from a numerical discriminator.
|
|
139
|
+
* By default, the discriminator is based on the positional index of the enum variants.
|
|
140
|
+
*
|
|
141
|
+
* For more details, see {@link getEnumCodec}.
|
|
142
|
+
*
|
|
143
|
+
* @typeParam TEnum - The TypeScript enum or object mapping enum keys to values.
|
|
144
|
+
*
|
|
145
|
+
* @param constructor - The constructor of the enum.
|
|
146
|
+
* @param config - Configuration options for decoding the enum.
|
|
147
|
+
* @returns A `FixedSizeDecoder` or `VariableSizeDecoder` for decoding enums.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* Decoding enum values.
|
|
151
|
+
* ```ts
|
|
152
|
+
* enum Direction { Up, Down, Left, Right }
|
|
153
|
+
* const decoder = getEnumDecoder(Direction);
|
|
154
|
+
*
|
|
155
|
+
* decoder.decode(new Uint8Array([0x00])); // Direction.Up
|
|
156
|
+
* decoder.decode(new Uint8Array([0x01])); // Direction.Down
|
|
157
|
+
* decoder.decode(new Uint8Array([0x02])); // Direction.Left
|
|
158
|
+
* decoder.decode(new Uint8Array([0x03])); // Direction.Right
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* @see {@link getEnumCodec}
|
|
162
|
+
*/
|
|
163
|
+
export function getEnumDecoder<TEnum extends EnumLookupObject>(
|
|
164
|
+
constructor: TEnum,
|
|
165
|
+
config?: Omit<EnumCodecConfig<NumberDecoder>, 'size'>,
|
|
166
|
+
): FixedSizeDecoder<GetEnumTo<TEnum>, 1>;
|
|
167
|
+
export function getEnumDecoder<TEnum extends EnumLookupObject, TSize extends number>(
|
|
168
|
+
constructor: TEnum,
|
|
169
|
+
config: EnumCodecConfig<NumberDecoder> & { size: FixedSizeNumberDecoder<TSize> },
|
|
170
|
+
): FixedSizeDecoder<GetEnumTo<TEnum>, TSize>;
|
|
171
|
+
export function getEnumDecoder<TEnum extends EnumLookupObject>(
|
|
172
|
+
constructor: TEnum,
|
|
173
|
+
config?: EnumCodecConfig<NumberDecoder>,
|
|
174
|
+
): VariableSizeDecoder<GetEnumTo<TEnum>>;
|
|
175
|
+
export function getEnumDecoder<TEnum extends EnumLookupObject>(
|
|
176
|
+
constructor: TEnum,
|
|
177
|
+
config: EnumCodecConfig<NumberDecoder> = {},
|
|
178
|
+
): Decoder<GetEnumTo<TEnum>> {
|
|
179
|
+
const prefix = config.size ?? getU8Decoder();
|
|
180
|
+
const useValuesAsDiscriminators = config.useValuesAsDiscriminators ?? false;
|
|
181
|
+
const { enumKeys, enumValues, numericalValues } = getEnumStats(constructor);
|
|
182
|
+
if (useValuesAsDiscriminators && enumValues.some(value => typeof value === 'string')) {
|
|
183
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__CANNOT_USE_LEXICAL_VALUES_AS_ENUM_DISCRIMINATORS, {
|
|
184
|
+
stringValues: enumValues.filter((v): v is string => typeof v === 'string'),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return transformDecoder(prefix, (value: bigint | number): GetEnumTo<TEnum> => {
|
|
188
|
+
const discriminator = Number(value);
|
|
189
|
+
const index = getEnumIndexFromDiscriminator({
|
|
190
|
+
discriminator,
|
|
191
|
+
enumKeys,
|
|
192
|
+
enumValues,
|
|
193
|
+
useValuesAsDiscriminators,
|
|
194
|
+
});
|
|
195
|
+
if (index < 0) {
|
|
196
|
+
const validDiscriminators = useValuesAsDiscriminators
|
|
197
|
+
? numericalValues
|
|
198
|
+
: [...Array(enumKeys.length).keys()];
|
|
199
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, {
|
|
200
|
+
discriminator,
|
|
201
|
+
formattedValidDiscriminators: formatNumericalValues(validDiscriminators),
|
|
202
|
+
validDiscriminators,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return enumValues[index] as GetEnumTo<TEnum>;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Returns a codec for encoding and decoding enums.
|
|
211
|
+
*
|
|
212
|
+
* This codec serializes enums as a numerical discriminator, allowing them
|
|
213
|
+
* to be efficiently stored and reconstructed from binary data.
|
|
214
|
+
*
|
|
215
|
+
* By default, the discriminator is derived from the positional index
|
|
216
|
+
* of the enum variant, but it can be configured to use the enum's numeric values instead.
|
|
217
|
+
*
|
|
218
|
+
* @typeParam TEnum - The TypeScript enum or object mapping enum keys to values.
|
|
219
|
+
*
|
|
220
|
+
* @param constructor - The constructor of the enum.
|
|
221
|
+
* @param config - Configuration options for encoding and decoding the enum.
|
|
222
|
+
* @returns A `FixedSizeCodec` or `VariableSizeCodec` for encoding and decoding enums.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* Encoding and decoding enums using positional indexes.
|
|
226
|
+
* ```ts
|
|
227
|
+
* enum Direction { Up, Down, Left, Right }
|
|
228
|
+
* const codec = getEnumCodec(Direction);
|
|
229
|
+
*
|
|
230
|
+
* codec.encode(Direction.Up); // 0x00
|
|
231
|
+
* codec.encode(Direction.Down); // 0x01
|
|
232
|
+
* codec.encode(Direction.Left); // 0x02
|
|
233
|
+
* codec.encode(Direction.Right); // 0x03
|
|
234
|
+
*
|
|
235
|
+
* codec.decode(new Uint8Array([0x00])); // Direction.Up
|
|
236
|
+
* codec.decode(new Uint8Array([0x01])); // Direction.Down
|
|
237
|
+
* codec.decode(new Uint8Array([0x02])); // Direction.Left
|
|
238
|
+
* codec.decode(new Uint8Array([0x03])); // Direction.Right
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* Encoding and decoding enums using their numeric values.
|
|
243
|
+
* ```ts
|
|
244
|
+
* enum GameDifficulty { Easy = 1, Normal = 4, Hard = 7, Expert = 9 }
|
|
245
|
+
* const codec = getEnumCodec(GameDifficulty, { useValuesAsDiscriminators: true });
|
|
246
|
+
*
|
|
247
|
+
* codec.encode(GameDifficulty.Easy); // 0x01
|
|
248
|
+
* codec.encode(GameDifficulty.Normal); // 0x04
|
|
249
|
+
* codec.encode(GameDifficulty.Hard); // 0x07
|
|
250
|
+
* codec.encode(GameDifficulty.Expert); // 0x09
|
|
251
|
+
*
|
|
252
|
+
* codec.decode(new Uint8Array([0x01])); // GameDifficulty.Easy
|
|
253
|
+
* codec.decode(new Uint8Array([0x04])); // GameDifficulty.Normal
|
|
254
|
+
* codec.decode(new Uint8Array([0x07])); // GameDifficulty.Hard
|
|
255
|
+
* codec.decode(new Uint8Array([0x09])); // GameDifficulty.Expert
|
|
256
|
+
* ```
|
|
257
|
+
*
|
|
258
|
+
* Note that, when using values as discriminators, the enum values must be numerical.
|
|
259
|
+
* Otherwise, an error will be thrown.
|
|
260
|
+
*
|
|
261
|
+
* ```ts
|
|
262
|
+
* enum GameDifficulty { Easy = 'EASY', Normal = 'NORMAL', Hard = 'HARD' }
|
|
263
|
+
* getEnumCodec(GameDifficulty, { useValuesAsDiscriminators: true }); // Throws an error.
|
|
264
|
+
* ```
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* Using a custom discriminator size.
|
|
268
|
+
* ```ts
|
|
269
|
+
* enum Status { Pending, Approved, Rejected }
|
|
270
|
+
* const codec = getEnumCodec(Status, { size: getU16Codec() });
|
|
271
|
+
*
|
|
272
|
+
* codec.encode(Status.Pending); // 0x0000
|
|
273
|
+
* codec.encode(Status.Approved); // 0x0100
|
|
274
|
+
* codec.encode(Status.Rejected); // 0x0200
|
|
275
|
+
*
|
|
276
|
+
* codec.decode(new Uint8Array([0x00, 0x00])); // Status.Pending
|
|
277
|
+
* codec.decode(new Uint8Array([0x01, 0x00])); // Status.Approved
|
|
278
|
+
* codec.decode(new Uint8Array([0x02, 0x00])); // Status.Rejected
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* @remarks
|
|
282
|
+
* Separate {@link getEnumEncoder} and {@link getEnumDecoder} functions are available.
|
|
283
|
+
*
|
|
284
|
+
* ```ts
|
|
285
|
+
* const bytes = getEnumEncoder(Direction).encode(Direction.Up);
|
|
286
|
+
* const value = getEnumDecoder(Direction).decode(bytes);
|
|
287
|
+
* ```
|
|
288
|
+
*
|
|
289
|
+
* @see {@link getEnumEncoder}
|
|
290
|
+
* @see {@link getEnumDecoder}
|
|
291
|
+
*/
|
|
292
|
+
export function getEnumCodec<TEnum extends EnumLookupObject>(
|
|
293
|
+
constructor: TEnum,
|
|
294
|
+
config?: Omit<EnumCodecConfig<NumberCodec>, 'size'>,
|
|
295
|
+
): FixedSizeCodec<GetEnumFrom<TEnum>, GetEnumTo<TEnum>, 1>;
|
|
296
|
+
export function getEnumCodec<TEnum extends EnumLookupObject, TSize extends number>(
|
|
297
|
+
constructor: TEnum,
|
|
298
|
+
config: EnumCodecConfig<NumberCodec> & { size: FixedSizeNumberCodec<TSize> },
|
|
299
|
+
): FixedSizeCodec<GetEnumFrom<TEnum>, GetEnumTo<TEnum>, TSize>;
|
|
300
|
+
export function getEnumCodec<TEnum extends EnumLookupObject>(
|
|
301
|
+
constructor: TEnum,
|
|
302
|
+
config?: EnumCodecConfig<NumberCodec>,
|
|
303
|
+
): VariableSizeCodec<GetEnumFrom<TEnum>, GetEnumTo<TEnum>>;
|
|
304
|
+
export function getEnumCodec<TEnum extends EnumLookupObject>(
|
|
305
|
+
constructor: TEnum,
|
|
306
|
+
config: EnumCodecConfig<NumberCodec> = {},
|
|
307
|
+
): Codec<GetEnumFrom<TEnum>, GetEnumTo<TEnum>> {
|
|
308
|
+
return combineCodec(getEnumEncoder(constructor, config), getEnumDecoder(constructor, config));
|
|
309
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Codec,
|
|
3
|
+
combineCodec,
|
|
4
|
+
Decoder,
|
|
5
|
+
Encoder,
|
|
6
|
+
FixedSizeCodec,
|
|
7
|
+
FixedSizeDecoder,
|
|
8
|
+
FixedSizeEncoder,
|
|
9
|
+
transformDecoder,
|
|
10
|
+
transformEncoder,
|
|
11
|
+
VariableSizeCodec,
|
|
12
|
+
VariableSizeDecoder,
|
|
13
|
+
VariableSizeEncoder,
|
|
14
|
+
} from '@solana/codecs-core';
|
|
15
|
+
|
|
16
|
+
import { getTupleDecoder, getTupleEncoder } from './tuple';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns an encoder that prefixes encoded values with hidden data.
|
|
20
|
+
*
|
|
21
|
+
* This encoder applies a list of void encoders before encoding the main value.
|
|
22
|
+
* The prefixed data is encoded before the main value without being exposed to the user.
|
|
23
|
+
*
|
|
24
|
+
* For more details, see {@link getHiddenPrefixCodec}.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam TFrom - The type of the main value being encoded.
|
|
27
|
+
*
|
|
28
|
+
* @param encoder - The encoder for the main value.
|
|
29
|
+
* @param prefixedEncoders - A list of void encoders that produce the hidden prefix.
|
|
30
|
+
* @returns A `FixedSizeEncoder` or `VariableSizeEncoder` that encodes the value with a hidden prefix.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* Prefixing a value with constants.
|
|
34
|
+
* ```ts
|
|
35
|
+
* const encoder = getHiddenPrefixEncoder(getUtf8Encoder(), [
|
|
36
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
37
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
38
|
+
* ]);
|
|
39
|
+
*
|
|
40
|
+
* encoder.encode('Hello');
|
|
41
|
+
* // 0x01020304050648656c6c6f
|
|
42
|
+
* // | | └-- Our encoded value ("Hello").
|
|
43
|
+
* // | └-- Our second hidden prefix.
|
|
44
|
+
* // └-- Our first hidden prefix.
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link getHiddenPrefixCodec}
|
|
48
|
+
*/
|
|
49
|
+
export function getHiddenPrefixEncoder<TFrom>(
|
|
50
|
+
encoder: FixedSizeEncoder<TFrom>,
|
|
51
|
+
prefixedEncoders: readonly FixedSizeEncoder<void>[],
|
|
52
|
+
): FixedSizeEncoder<TFrom>;
|
|
53
|
+
export function getHiddenPrefixEncoder<TFrom>(
|
|
54
|
+
encoder: Encoder<TFrom>,
|
|
55
|
+
prefixedEncoders: readonly Encoder<void>[],
|
|
56
|
+
): VariableSizeEncoder<TFrom>;
|
|
57
|
+
export function getHiddenPrefixEncoder<TFrom>(
|
|
58
|
+
encoder: Encoder<TFrom>,
|
|
59
|
+
prefixedEncoders: readonly Encoder<void>[],
|
|
60
|
+
): Encoder<TFrom> {
|
|
61
|
+
return transformEncoder(
|
|
62
|
+
getTupleEncoder([...prefixedEncoders, encoder]) as Encoder<readonly [...void[], TFrom]>,
|
|
63
|
+
(value: TFrom) => [...prefixedEncoders.map(() => undefined), value] as const,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns a decoder that skips hidden prefixed data before decoding the main value.
|
|
69
|
+
*
|
|
70
|
+
* This decoder applies a list of void decoders before decoding the main value.
|
|
71
|
+
* The prefixed data is skipped during decoding without being exposed to the user.
|
|
72
|
+
*
|
|
73
|
+
* For more details, see {@link getHiddenPrefixCodec}.
|
|
74
|
+
*
|
|
75
|
+
* @typeParam TTo - The type of the main value being decoded.
|
|
76
|
+
*
|
|
77
|
+
* @param decoder - The decoder for the main value.
|
|
78
|
+
* @param prefixedDecoders - A list of void decoders that produce the hidden prefix.
|
|
79
|
+
* @returns A `FixedSizeDecoder` or `VariableSizeDecoder` that decodes values while ignoring the hidden prefix.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* Decoding a value with prefixed constants.
|
|
83
|
+
* ```ts
|
|
84
|
+
* const decoder = getHiddenPrefixDecoder(getUtf8Decoder(), [
|
|
85
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
86
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
87
|
+
* ]);
|
|
88
|
+
*
|
|
89
|
+
* decoder.decode(new Uint8Array([1, 2, 3, 4, 5, 6, 0x48, 0x65, 0x6C, 0x6C, 0x6F]));
|
|
90
|
+
* // 'Hello'
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see {@link getHiddenPrefixCodec}
|
|
94
|
+
*/
|
|
95
|
+
export function getHiddenPrefixDecoder<TTo>(
|
|
96
|
+
decoder: FixedSizeDecoder<TTo>,
|
|
97
|
+
prefixedDecoders: readonly FixedSizeDecoder<void>[],
|
|
98
|
+
): FixedSizeDecoder<TTo>;
|
|
99
|
+
export function getHiddenPrefixDecoder<TTo>(
|
|
100
|
+
decoder: Decoder<TTo>,
|
|
101
|
+
prefixedDecoders: readonly Decoder<void>[],
|
|
102
|
+
): VariableSizeDecoder<TTo>;
|
|
103
|
+
export function getHiddenPrefixDecoder<TTo>(
|
|
104
|
+
decoder: Decoder<TTo>,
|
|
105
|
+
prefixedDecoders: readonly Decoder<void>[],
|
|
106
|
+
): Decoder<TTo> {
|
|
107
|
+
return transformDecoder(
|
|
108
|
+
getTupleDecoder([...prefixedDecoders, decoder]) as Decoder<readonly [...void[], TTo]>,
|
|
109
|
+
tuple => tuple[tuple.length - 1] as TTo,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns a codec that encodes and decodes values with a hidden prefix.
|
|
115
|
+
*
|
|
116
|
+
* - **Encoding:** Prefixes the value with hidden data before encoding.
|
|
117
|
+
* - **Decoding:** Skips the hidden prefix before decoding the main value.
|
|
118
|
+
*
|
|
119
|
+
* This is useful for any implicit metadata that should be present in
|
|
120
|
+
* binary formats but omitted from the API.
|
|
121
|
+
*
|
|
122
|
+
* @typeParam TFrom - The type of the main value being encoded.
|
|
123
|
+
* @typeParam TTo - The type of the main value being decoded.
|
|
124
|
+
*
|
|
125
|
+
* @param codec - The codec for the main value.
|
|
126
|
+
* @param prefixedCodecs - A list of void codecs that produce the hidden prefix.
|
|
127
|
+
* @returns A `FixedSizeCodec` or `VariableSizeCodec` for encoding and decoding values with a hidden prefix.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* Encoding and decoding a value with prefixed constants.
|
|
131
|
+
* ```ts
|
|
132
|
+
* const codec = getHiddenPrefixCodec(getUtf8Codec(), [
|
|
133
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
134
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
135
|
+
* ]);
|
|
136
|
+
*
|
|
137
|
+
* const bytes = codec.encode('Hello');
|
|
138
|
+
* // 0x01020304050648656c6c6f
|
|
139
|
+
* // | | └-- Our encoded value ("Hello").
|
|
140
|
+
* // | └-- Our second hidden prefix.
|
|
141
|
+
* // └-- Our first hidden prefix.
|
|
142
|
+
*
|
|
143
|
+
* codec.decode(bytes);
|
|
144
|
+
* // 'Hello'
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @remarks
|
|
148
|
+
* If all you need is padding zeroes before a value, consider using {@link padLeftCodec} instead.
|
|
149
|
+
*
|
|
150
|
+
* Separate {@link getHiddenPrefixEncoder} and {@link getHiddenPrefixDecoder} functions are available.
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* const bytes = getHiddenPrefixEncoder(getUtf8Encoder(), [
|
|
154
|
+
* getConstantEncoder(new Uint8Array([1, 2, 3])),
|
|
155
|
+
* getConstantEncoder(new Uint8Array([4, 5, 6])),
|
|
156
|
+
* ]).encode('Hello');
|
|
157
|
+
*
|
|
158
|
+
* const value = getHiddenPrefixDecoder(getUtf8Decoder(), [
|
|
159
|
+
* getConstantDecoder(new Uint8Array([1, 2, 3])),
|
|
160
|
+
* getConstantDecoder(new Uint8Array([4, 5, 6])),
|
|
161
|
+
* ]).decode(bytes);
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @see {@link getHiddenPrefixEncoder}
|
|
165
|
+
* @see {@link getHiddenPrefixDecoder}
|
|
166
|
+
*/
|
|
167
|
+
export function getHiddenPrefixCodec<TFrom, TTo extends TFrom>(
|
|
168
|
+
codec: FixedSizeCodec<TFrom, TTo>,
|
|
169
|
+
prefixedCodecs: readonly FixedSizeCodec<void>[],
|
|
170
|
+
): FixedSizeCodec<TFrom, TTo>;
|
|
171
|
+
export function getHiddenPrefixCodec<TFrom, TTo extends TFrom>(
|
|
172
|
+
codec: Codec<TFrom, TTo>,
|
|
173
|
+
prefixedCodecs: readonly Codec<void>[],
|
|
174
|
+
): VariableSizeCodec<TFrom, TTo>;
|
|
175
|
+
export function getHiddenPrefixCodec<TFrom, TTo extends TFrom>(
|
|
176
|
+
codec: Codec<TFrom, TTo>,
|
|
177
|
+
prefixedCodecs: readonly Codec<void>[],
|
|
178
|
+
): Codec<TFrom, TTo> {
|
|
179
|
+
return combineCodec(getHiddenPrefixEncoder(codec, prefixedCodecs), getHiddenPrefixDecoder(codec, prefixedCodecs));
|
|
180
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Codec,
|
|
3
|
+
combineCodec,
|
|
4
|
+
Decoder,
|
|
5
|
+
Encoder,
|
|
6
|
+
FixedSizeCodec,
|
|
7
|
+
FixedSizeDecoder,
|
|
8
|
+
FixedSizeEncoder,
|
|
9
|
+
transformDecoder,
|
|
10
|
+
transformEncoder,
|
|
11
|
+
VariableSizeCodec,
|
|
12
|
+
VariableSizeDecoder,
|
|
13
|
+
VariableSizeEncoder,
|
|
14
|
+
} from '@solana/codecs-core';
|
|
15
|
+
|
|
16
|
+
import { getTupleDecoder, getTupleEncoder } from './tuple';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns an encoder that appends hidden data after the encoded value.
|
|
20
|
+
*
|
|
21
|
+
* This encoder applies a list of void encoders after encoding the main value.
|
|
22
|
+
* The suffixed data is encoded after the main value without being exposed to the user.
|
|
23
|
+
*
|
|
24
|
+
* For more details, see {@link getHiddenSuffixCodec}.
|
|
25
|
+
*
|
|
26
|
+
* @typeParam TFrom - The type of the main value being encoded.
|
|
27
|
+
*
|
|
28
|
+
* @param encoder - The encoder for the main value.
|
|
29
|
+
* @param suffixedEncoders - A list of void encoders that produce the hidden suffix.
|
|
30
|
+
* @returns A `FixedSizeEncoder` or `VariableSizeEncoder` that encodes the value with a hidden suffix.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* Suffixing a value with constants.
|
|
34
|
+
* ```ts
|
|
35
|
+
* const encoder = getHiddenSuffixEncoder(getUtf8Encoder(), [
|
|
36
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
37
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
38
|
+
* ]);
|
|
39
|
+
*
|
|
40
|
+
* encoder.encode('Hello');
|
|
41
|
+
* // 0x48656c6c6f010203040506
|
|
42
|
+
* // | | └-- Our second hidden suffix.
|
|
43
|
+
* // | └-- Our first hidden suffix.
|
|
44
|
+
* // └-- Our encoded value ("Hello").
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* @see {@link getHiddenSuffixCodec}
|
|
48
|
+
*/
|
|
49
|
+
export function getHiddenSuffixEncoder<TFrom>(
|
|
50
|
+
encoder: FixedSizeEncoder<TFrom>,
|
|
51
|
+
suffixedEncoders: readonly FixedSizeEncoder<void>[],
|
|
52
|
+
): FixedSizeEncoder<TFrom>;
|
|
53
|
+
export function getHiddenSuffixEncoder<TFrom>(
|
|
54
|
+
encoder: Encoder<TFrom>,
|
|
55
|
+
suffixedEncoders: readonly Encoder<void>[],
|
|
56
|
+
): VariableSizeEncoder<TFrom>;
|
|
57
|
+
export function getHiddenSuffixEncoder<TFrom>(
|
|
58
|
+
encoder: Encoder<TFrom>,
|
|
59
|
+
suffixedEncoders: readonly Encoder<void>[],
|
|
60
|
+
): Encoder<TFrom> {
|
|
61
|
+
return transformEncoder(
|
|
62
|
+
getTupleEncoder([encoder, ...suffixedEncoders]) as Encoder<readonly [TFrom, ...void[]]>,
|
|
63
|
+
(value: TFrom) => [value, ...suffixedEncoders.map(() => undefined)] as const,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns a decoder that skips hidden suffixed data after decoding the main value.
|
|
69
|
+
*
|
|
70
|
+
* This decoder applies a list of void decoders after decoding the main value.
|
|
71
|
+
* The suffixed data is skipped during decoding without being exposed to the user.
|
|
72
|
+
*
|
|
73
|
+
* For more details, see {@link getHiddenSuffixCodec}.
|
|
74
|
+
*
|
|
75
|
+
* @typeParam TTo - The type of the main value being decoded.
|
|
76
|
+
*
|
|
77
|
+
* @param decoder - The decoder for the main value.
|
|
78
|
+
* @param suffixedDecoders - A list of void decoders that produce the hidden suffix.
|
|
79
|
+
* @returns A `FixedSizeDecoder` or `VariableSizeDecoder` that decodes values while ignoring the hidden suffix.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* Decoding a value with suffixed constants.
|
|
83
|
+
* ```ts
|
|
84
|
+
* const decoder = getHiddenSuffixDecoder(getUtf8Decoder(), [
|
|
85
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
86
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
87
|
+
* ]);
|
|
88
|
+
*
|
|
89
|
+
* decoder.decode(new Uint8Array([0x48, 0x65, 0x6C, 0x6C, 0x6F, 1, 2, 3, 4, 5, 6]));
|
|
90
|
+
* // 'Hello'
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @see {@link getHiddenSuffixCodec}
|
|
94
|
+
*/
|
|
95
|
+
export function getHiddenSuffixDecoder<TTo>(
|
|
96
|
+
decoder: FixedSizeDecoder<TTo>,
|
|
97
|
+
suffixedDecoders: readonly FixedSizeDecoder<void>[],
|
|
98
|
+
): FixedSizeDecoder<TTo>;
|
|
99
|
+
export function getHiddenSuffixDecoder<TTo>(
|
|
100
|
+
decoder: Decoder<TTo>,
|
|
101
|
+
suffixedDecoders: readonly Decoder<void>[],
|
|
102
|
+
): VariableSizeDecoder<TTo>;
|
|
103
|
+
export function getHiddenSuffixDecoder<TTo>(
|
|
104
|
+
decoder: Decoder<TTo>,
|
|
105
|
+
suffixedDecoders: readonly Decoder<void>[],
|
|
106
|
+
): Decoder<TTo> {
|
|
107
|
+
return transformDecoder(
|
|
108
|
+
getTupleDecoder([decoder, ...suffixedDecoders]) as Decoder<readonly [TTo, ...void[]]>,
|
|
109
|
+
tuple => tuple[0],
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Returns a codec that encodes and decodes values with a hidden suffix.
|
|
115
|
+
*
|
|
116
|
+
* - **Encoding:** Appends hidden data after encoding the main value.
|
|
117
|
+
* - **Decoding:** Skips the hidden suffix after decoding the main value.
|
|
118
|
+
*
|
|
119
|
+
* This is useful for any implicit metadata that should be present in
|
|
120
|
+
* binary formats but omitted from the API.
|
|
121
|
+
*
|
|
122
|
+
* @typeParam TFrom - The type of the main value being encoded.
|
|
123
|
+
* @typeParam TTo - The type of the main value being decoded.
|
|
124
|
+
*
|
|
125
|
+
* @param codec - The codec for the main value.
|
|
126
|
+
* @param suffixedCodecs - A list of void codecs that produce the hidden suffix.
|
|
127
|
+
* @returns A `FixedSizeCodec` or `VariableSizeCodec` for encoding and decoding values with a hidden suffix.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* Encoding and decoding a value with suffixed constants.
|
|
131
|
+
* ```ts
|
|
132
|
+
* const codec = getHiddenSuffixCodec(getUtf8Codec(), [
|
|
133
|
+
* getConstantCodec(new Uint8Array([1, 2, 3])),
|
|
134
|
+
* getConstantCodec(new Uint8Array([4, 5, 6])),
|
|
135
|
+
* ]);
|
|
136
|
+
*
|
|
137
|
+
* const bytes = codec.encode('Hello');
|
|
138
|
+
* // 0x48656c6c6f010203040506
|
|
139
|
+
* // | | └-- Our second hidden suffix.
|
|
140
|
+
* // | └-- Our first hidden suffix.
|
|
141
|
+
* // └-- Our encoded value ("Hello").
|
|
142
|
+
*
|
|
143
|
+
* codec.decode(bytes);
|
|
144
|
+
* // 'Hello'
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @remarks
|
|
148
|
+
* If all you need is padding zeroes after a value, consider using {@link padRightCodec} instead.
|
|
149
|
+
*
|
|
150
|
+
* Separate {@link getHiddenSuffixEncoder} and {@link getHiddenSuffixDecoder} functions are available.
|
|
151
|
+
*
|
|
152
|
+
* ```ts
|
|
153
|
+
* const bytes = getHiddenSuffixEncoder(getUtf8Encoder(), [
|
|
154
|
+
* getConstantEncoder(new Uint8Array([1, 2, 3])),
|
|
155
|
+
* getConstantEncoder(new Uint8Array([4, 5, 6])),
|
|
156
|
+
* ]).encode('Hello');
|
|
157
|
+
*
|
|
158
|
+
* const value = getHiddenSuffixDecoder(getUtf8Decoder(), [
|
|
159
|
+
* getConstantDecoder(new Uint8Array([1, 2, 3])),
|
|
160
|
+
* getConstantDecoder(new Uint8Array([4, 5, 6])),
|
|
161
|
+
* ]).decode(bytes);
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @see {@link getHiddenSuffixEncoder}
|
|
165
|
+
* @see {@link getHiddenSuffixDecoder}
|
|
166
|
+
*/
|
|
167
|
+
export function getHiddenSuffixCodec<TFrom, TTo extends TFrom>(
|
|
168
|
+
codec: FixedSizeCodec<TFrom, TTo>,
|
|
169
|
+
suffixedCodecs: readonly FixedSizeCodec<void>[],
|
|
170
|
+
): FixedSizeCodec<TFrom, TTo>;
|
|
171
|
+
export function getHiddenSuffixCodec<TFrom, TTo extends TFrom>(
|
|
172
|
+
codec: Codec<TFrom, TTo>,
|
|
173
|
+
suffixedCodecs: readonly Codec<void>[],
|
|
174
|
+
): VariableSizeCodec<TFrom, TTo>;
|
|
175
|
+
export function getHiddenSuffixCodec<TFrom, TTo extends TFrom>(
|
|
176
|
+
codec: Codec<TFrom, TTo>,
|
|
177
|
+
suffixedCodecs: readonly Codec<void>[],
|
|
178
|
+
): Codec<TFrom, TTo> {
|
|
179
|
+
return combineCodec(getHiddenSuffixEncoder(codec, suffixedCodecs), getHiddenSuffixDecoder(codec, suffixedCodecs));
|
|
180
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package contains codecs for various data structures such as arrays, maps, structs, tuples, enums, etc.
|
|
3
|
+
* It can be used standalone, but it is also exported as part of Kit
|
|
4
|
+
* [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
|
|
5
|
+
*
|
|
6
|
+
* This package is also part of the [`@solana/codecs` package](https://github.com/anza-xyz/kit/tree/main/packages/codecs)
|
|
7
|
+
* which acts as an entry point for all codec packages as well as for their documentation.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export * from './array';
|
|
12
|
+
export * from './assertions';
|
|
13
|
+
export * from './bit-array';
|
|
14
|
+
export * from './boolean';
|
|
15
|
+
export * from './bytes';
|
|
16
|
+
export * from './constant';
|
|
17
|
+
export * from './discriminated-union';
|
|
18
|
+
export * from './enum';
|
|
19
|
+
export * from './hidden-prefix';
|
|
20
|
+
export * from './hidden-suffix';
|
|
21
|
+
export * from './literal-union';
|
|
22
|
+
export * from './map';
|
|
23
|
+
export * from './nullable';
|
|
24
|
+
export * from './pattern-match';
|
|
25
|
+
export * from './predicate';
|
|
26
|
+
export * from './set';
|
|
27
|
+
export * from './struct';
|
|
28
|
+
export * from './tuple';
|
|
29
|
+
export * from './union';
|
|
30
|
+
export * from './unit';
|