@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,249 @@
|
|
|
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__INVALID_LITERAL_UNION_VARIANT,
|
|
27
|
+
SOLANA_ERROR__CODECS__LITERAL_UNION_DISCRIMINATOR_OUT_OF_RANGE,
|
|
28
|
+
SolanaError,
|
|
29
|
+
} from '@solana/errors';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Defines the configuration options for literal union codecs.
|
|
33
|
+
*
|
|
34
|
+
* A literal union codec encodes values from a predefined set of literals.
|
|
35
|
+
* The `size` option determines the numerical encoding used for the discriminant.
|
|
36
|
+
* By default, literals are stored as a `u8` (1 byte).
|
|
37
|
+
*
|
|
38
|
+
* @typeParam TDiscriminator - A number codec, encoder, or decoder used for the discriminant.
|
|
39
|
+
*/
|
|
40
|
+
export type LiteralUnionCodecConfig<TDiscriminator = NumberCodec | NumberDecoder | NumberEncoder> = {
|
|
41
|
+
/**
|
|
42
|
+
* The codec used to encode/decode the discriminator.
|
|
43
|
+
* @defaultValue `u8` discriminator.
|
|
44
|
+
*/
|
|
45
|
+
size?: TDiscriminator;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type Variant = bigint | boolean | number | string | null | undefined;
|
|
49
|
+
type GetTypeFromVariants<TVariants extends readonly Variant[]> = TVariants[number];
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Returns an encoder for literal unions.
|
|
53
|
+
*
|
|
54
|
+
* This encoder serializes a value from a predefined set of literals
|
|
55
|
+
* as a numerical index representing its position in the `variants` array.
|
|
56
|
+
*
|
|
57
|
+
* For more details, see {@link getLiteralUnionCodec}.
|
|
58
|
+
*
|
|
59
|
+
* @typeParam TVariants - A tuple of allowed literal values.
|
|
60
|
+
*
|
|
61
|
+
* @param variants - The possible literal values for the union.
|
|
62
|
+
* @param config - Configuration options for encoding the literal union.
|
|
63
|
+
* @returns A `FixedSizeEncoder` or `VariableSizeEncoder` for encoding literal unions.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* Encoding a union of string literals.
|
|
67
|
+
* ```ts
|
|
68
|
+
* type Size = 'small' | 'medium' | 'large';
|
|
69
|
+
* const sizeEncoder = getLiteralUnionEncoder(['small', 'medium', 'large']);
|
|
70
|
+
*
|
|
71
|
+
* sizeEncoder.encode('small'); // 0x00
|
|
72
|
+
* sizeEncoder.encode('medium'); // 0x01
|
|
73
|
+
* sizeEncoder.encode('large'); // 0x02
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @see {@link getLiteralUnionCodec}
|
|
77
|
+
*/
|
|
78
|
+
export function getLiteralUnionEncoder<const TVariants extends readonly Variant[]>(
|
|
79
|
+
variants: TVariants,
|
|
80
|
+
): FixedSizeEncoder<GetTypeFromVariants<TVariants>, 1>;
|
|
81
|
+
export function getLiteralUnionEncoder<const TVariants extends readonly Variant[], TSize extends number>(
|
|
82
|
+
variants: TVariants,
|
|
83
|
+
config: LiteralUnionCodecConfig<NumberEncoder> & { size: FixedSizeNumberEncoder<TSize> },
|
|
84
|
+
): FixedSizeEncoder<GetTypeFromVariants<TVariants>, TSize>;
|
|
85
|
+
export function getLiteralUnionEncoder<const TVariants extends readonly Variant[]>(
|
|
86
|
+
variants: TVariants,
|
|
87
|
+
config?: LiteralUnionCodecConfig<NumberEncoder>,
|
|
88
|
+
): VariableSizeEncoder<GetTypeFromVariants<TVariants>>;
|
|
89
|
+
export function getLiteralUnionEncoder<const TVariants extends readonly Variant[]>(
|
|
90
|
+
variants: TVariants,
|
|
91
|
+
config: LiteralUnionCodecConfig<NumberEncoder> = {},
|
|
92
|
+
): Encoder<GetTypeFromVariants<TVariants>> {
|
|
93
|
+
const discriminator = config.size ?? getU8Encoder();
|
|
94
|
+
return transformEncoder(discriminator, variant => {
|
|
95
|
+
const index = variants.indexOf(variant);
|
|
96
|
+
if (index < 0) {
|
|
97
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_LITERAL_UNION_VARIANT, {
|
|
98
|
+
value: variant,
|
|
99
|
+
variants,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return index;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns a decoder for literal unions.
|
|
108
|
+
*
|
|
109
|
+
* This decoder deserializes a numerical index into a corresponding
|
|
110
|
+
* value from a predefined set of literals.
|
|
111
|
+
*
|
|
112
|
+
* For more details, see {@link getLiteralUnionCodec}.
|
|
113
|
+
*
|
|
114
|
+
* @typeParam TVariants - A tuple of allowed literal values.
|
|
115
|
+
*
|
|
116
|
+
* @param variants - The possible literal values for the union.
|
|
117
|
+
* @param config - Configuration options for decoding the literal union.
|
|
118
|
+
* @returns A `FixedSizeDecoder` or `VariableSizeDecoder` for decoding literal unions.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* Decoding a union of string literals.
|
|
122
|
+
* ```ts
|
|
123
|
+
* type Size = 'small' | 'medium' | 'large';
|
|
124
|
+
* const sizeDecoder = getLiteralUnionDecoder(['small', 'medium', 'large']);
|
|
125
|
+
*
|
|
126
|
+
* sizeDecoder.decode(new Uint8Array([0x00])); // 'small'
|
|
127
|
+
* sizeDecoder.decode(new Uint8Array([0x01])); // 'medium'
|
|
128
|
+
* sizeDecoder.decode(new Uint8Array([0x02])); // 'large'
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @see {@link getLiteralUnionCodec}
|
|
132
|
+
*/
|
|
133
|
+
export function getLiteralUnionDecoder<const TVariants extends readonly Variant[]>(
|
|
134
|
+
variants: TVariants,
|
|
135
|
+
): FixedSizeDecoder<GetTypeFromVariants<TVariants>, 1>;
|
|
136
|
+
export function getLiteralUnionDecoder<const TVariants extends readonly Variant[], TSize extends number>(
|
|
137
|
+
variants: TVariants,
|
|
138
|
+
config: LiteralUnionCodecConfig<NumberDecoder> & { size: FixedSizeNumberDecoder<TSize> },
|
|
139
|
+
): FixedSizeDecoder<GetTypeFromVariants<TVariants>, TSize>;
|
|
140
|
+
export function getLiteralUnionDecoder<const TVariants extends readonly Variant[]>(
|
|
141
|
+
variants: TVariants,
|
|
142
|
+
config?: LiteralUnionCodecConfig<NumberDecoder>,
|
|
143
|
+
): VariableSizeDecoder<GetTypeFromVariants<TVariants>>;
|
|
144
|
+
export function getLiteralUnionDecoder<const TVariants extends readonly Variant[]>(
|
|
145
|
+
variants: TVariants,
|
|
146
|
+
config: LiteralUnionCodecConfig<NumberDecoder> = {},
|
|
147
|
+
): Decoder<GetTypeFromVariants<TVariants>> {
|
|
148
|
+
const discriminator = config.size ?? getU8Decoder();
|
|
149
|
+
return transformDecoder(discriminator, (index: bigint | number) => {
|
|
150
|
+
if (index < 0 || index >= variants.length) {
|
|
151
|
+
throw new SolanaError(SOLANA_ERROR__CODECS__LITERAL_UNION_DISCRIMINATOR_OUT_OF_RANGE, {
|
|
152
|
+
discriminator: index,
|
|
153
|
+
maxRange: variants.length - 1,
|
|
154
|
+
minRange: 0,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return variants[Number(index)];
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Returns a codec for encoding and decoding literal unions.
|
|
163
|
+
*
|
|
164
|
+
* A literal union codec serializes and deserializes values
|
|
165
|
+
* from a predefined set of literals, using a numerical index
|
|
166
|
+
* to represent each value in the `variants` array.
|
|
167
|
+
*
|
|
168
|
+
* This allows efficient storage and retrieval of common
|
|
169
|
+
* predefined values such as enum-like structures in TypeScript.
|
|
170
|
+
*
|
|
171
|
+
* @typeParam TVariants - A tuple of allowed literal values.
|
|
172
|
+
*
|
|
173
|
+
* @param variants - The possible literal values for the union.
|
|
174
|
+
* @param config - Configuration options for encoding and decoding the literal union.
|
|
175
|
+
* @returns A `FixedSizeCodec` or `VariableSizeCodec` for encoding and decoding literal unions.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* Encoding and decoding a union of string literals.
|
|
179
|
+
* ```ts
|
|
180
|
+
* type Size = 'small' | 'medium' | 'large';
|
|
181
|
+
* const sizeCodec = getLiteralUnionCodec(['small', 'medium', 'large']);
|
|
182
|
+
*
|
|
183
|
+
* sizeCodec.encode('small'); // 0x00
|
|
184
|
+
* sizeCodec.encode('medium'); // 0x01
|
|
185
|
+
* sizeCodec.encode('large'); // 0x02
|
|
186
|
+
*
|
|
187
|
+
* sizeCodec.decode(new Uint8Array([0x00])); // 'small'
|
|
188
|
+
* sizeCodec.decode(new Uint8Array([0x01])); // 'medium'
|
|
189
|
+
* sizeCodec.decode(new Uint8Array([0x02])); // 'large'
|
|
190
|
+
* ```
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* Encoding and decoding a union of number literals.
|
|
194
|
+
* ```ts
|
|
195
|
+
* type Level = 10 | 20 | 30;
|
|
196
|
+
* const levelCodec = getLiteralUnionCodec([10, 20, 30]);
|
|
197
|
+
*
|
|
198
|
+
* levelCodec.encode(10); // 0x00
|
|
199
|
+
* levelCodec.encode(20); // 0x01
|
|
200
|
+
* levelCodec.encode(30); // 0x02
|
|
201
|
+
*
|
|
202
|
+
* levelCodec.decode(new Uint8Array([0x00])); // 10
|
|
203
|
+
* levelCodec.decode(new Uint8Array([0x01])); // 20
|
|
204
|
+
* levelCodec.decode(new Uint8Array([0x02])); // 30
|
|
205
|
+
* ```
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* Using a custom discriminator size with different variant types.
|
|
209
|
+
* ```ts
|
|
210
|
+
* type MaybeBoolean = false | true | "either";
|
|
211
|
+
* const codec = getLiteralUnionCodec([false, true, 'either'], { size: getU16Codec() });
|
|
212
|
+
*
|
|
213
|
+
* codec.encode(false); // 0x0000
|
|
214
|
+
* codec.encode(true); // 0x0100
|
|
215
|
+
* codec.encode('either'); // 0x0200
|
|
216
|
+
*
|
|
217
|
+
* codec.decode(new Uint8Array([0x00, 0x00])); // false
|
|
218
|
+
* codec.decode(new Uint8Array([0x01, 0x00])); // true
|
|
219
|
+
* codec.decode(new Uint8Array([0x02, 0x00])); // 'either'
|
|
220
|
+
* ```
|
|
221
|
+
*
|
|
222
|
+
* @remarks
|
|
223
|
+
* Separate {@link getLiteralUnionEncoder} and {@link getLiteralUnionDecoder} functions are available.
|
|
224
|
+
*
|
|
225
|
+
* ```ts
|
|
226
|
+
* const bytes = getLiteralUnionEncoder(['red', 'green', 'blue']).encode('green');
|
|
227
|
+
* const value = getLiteralUnionDecoder(['red', 'green', 'blue']).decode(bytes);
|
|
228
|
+
* ```
|
|
229
|
+
*
|
|
230
|
+
* @see {@link getLiteralUnionEncoder}
|
|
231
|
+
* @see {@link getLiteralUnionDecoder}
|
|
232
|
+
*/
|
|
233
|
+
export function getLiteralUnionCodec<const TVariants extends readonly Variant[]>(
|
|
234
|
+
variants: TVariants,
|
|
235
|
+
): FixedSizeCodec<GetTypeFromVariants<TVariants>, GetTypeFromVariants<TVariants>, 1>;
|
|
236
|
+
export function getLiteralUnionCodec<const TVariants extends readonly Variant[], TSize extends number>(
|
|
237
|
+
variants: TVariants,
|
|
238
|
+
config: LiteralUnionCodecConfig<NumberCodec> & { size: FixedSizeNumberCodec<TSize> },
|
|
239
|
+
): FixedSizeCodec<GetTypeFromVariants<TVariants>, GetTypeFromVariants<TVariants>, TSize>;
|
|
240
|
+
export function getLiteralUnionCodec<const TVariants extends readonly Variant[]>(
|
|
241
|
+
variants: TVariants,
|
|
242
|
+
config?: LiteralUnionCodecConfig<NumberCodec>,
|
|
243
|
+
): VariableSizeCodec<GetTypeFromVariants<TVariants>>;
|
|
244
|
+
export function getLiteralUnionCodec<const TVariants extends readonly Variant[]>(
|
|
245
|
+
variants: TVariants,
|
|
246
|
+
config: LiteralUnionCodecConfig<NumberCodec> = {},
|
|
247
|
+
): Codec<GetTypeFromVariants<TVariants>> {
|
|
248
|
+
return combineCodec(getLiteralUnionEncoder(variants, config), getLiteralUnionDecoder(variants, config));
|
|
249
|
+
}
|
package/src/map.ts
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
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 { NumberCodec, NumberDecoder, NumberEncoder } from '@solana/codecs-numbers';
|
|
16
|
+
|
|
17
|
+
import { ArrayLikeCodecSize, getArrayDecoder, getArrayEncoder } from './array';
|
|
18
|
+
import { getTupleDecoder, getTupleEncoder } from './tuple';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Defines the configuration options for map codecs.
|
|
22
|
+
*
|
|
23
|
+
* The `size` option determines how the number of entries in the map is stored.
|
|
24
|
+
* It can be:
|
|
25
|
+
* - A {@link NumberCodec} to prefix the map with its size.
|
|
26
|
+
* - A fixed number of entries.
|
|
27
|
+
* - `'remainder'`, which infers the number of entries based on the remaining bytes.
|
|
28
|
+
* This option is only available for fixed-size keys and values.
|
|
29
|
+
*
|
|
30
|
+
* @typeParam TPrefix - A number codec, encoder, or decoder used for the size prefix.
|
|
31
|
+
*/
|
|
32
|
+
export type MapCodecConfig<TPrefix extends NumberCodec | NumberDecoder | NumberEncoder> = {
|
|
33
|
+
/**
|
|
34
|
+
* The size of the map.
|
|
35
|
+
* @defaultValue u32 prefix.
|
|
36
|
+
*/
|
|
37
|
+
size?: ArrayLikeCodecSize<TPrefix>;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Returns an encoder for maps.
|
|
42
|
+
*
|
|
43
|
+
* This encoder serializes maps where the keys and values are encoded
|
|
44
|
+
* using the provided key and value encoders. The number of entries
|
|
45
|
+
* is determined by the `size` configuration.
|
|
46
|
+
*
|
|
47
|
+
* For more details, see {@link getMapCodec}.
|
|
48
|
+
*
|
|
49
|
+
* @typeParam TFromKey - The type of the keys before encoding.
|
|
50
|
+
* @typeParam TFromValue - The type of the values before encoding.
|
|
51
|
+
*
|
|
52
|
+
* @param key - The encoder for the map's keys.
|
|
53
|
+
* @param value - The encoder for the map's values.
|
|
54
|
+
* @param config - Configuration options for encoding the map.
|
|
55
|
+
* @returns A `FixedSizeEncoder` or `VariableSizeEncoder` for encoding maps.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* Encoding a map with a `u32` size prefix.
|
|
59
|
+
* ```ts
|
|
60
|
+
* const encoder = getMapEncoder(fixCodecSize(getUtf8Encoder(), 5), getU8Encoder());
|
|
61
|
+
* const bytes = encoder.encode(new Map([['alice', 42], ['bob', 5]]));
|
|
62
|
+
* // 0x02000000616c6963652a626f62000005
|
|
63
|
+
* // | | | | └── Value (5)
|
|
64
|
+
* // | | | └── Key ("bob", 5 bytes fixed, null-padded)
|
|
65
|
+
* // | | └── Value (42)
|
|
66
|
+
* // | └── Key ("alice", 5 bytes fixed)
|
|
67
|
+
* // └── 4-byte prefix (2 entries)
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @see {@link getMapCodec}
|
|
71
|
+
*/
|
|
72
|
+
export function getMapEncoder<TFromKey, TFromValue>(
|
|
73
|
+
key: Encoder<TFromKey>,
|
|
74
|
+
value: Encoder<TFromValue>,
|
|
75
|
+
config: MapCodecConfig<NumberEncoder> & { size: 0 },
|
|
76
|
+
): FixedSizeEncoder<Map<TFromKey, TFromValue>, 0>;
|
|
77
|
+
export function getMapEncoder<TFromKey, TFromValue>(
|
|
78
|
+
key: FixedSizeEncoder<TFromKey>,
|
|
79
|
+
value: FixedSizeEncoder<TFromValue>,
|
|
80
|
+
config: MapCodecConfig<NumberEncoder> & { size: number },
|
|
81
|
+
): FixedSizeEncoder<Map<TFromKey, TFromValue>>;
|
|
82
|
+
export function getMapEncoder<TFromKey, TFromValue>(
|
|
83
|
+
key: Encoder<TFromKey>,
|
|
84
|
+
value: Encoder<TFromValue>,
|
|
85
|
+
config?: MapCodecConfig<NumberEncoder>,
|
|
86
|
+
): VariableSizeEncoder<Map<TFromKey, TFromValue>>;
|
|
87
|
+
export function getMapEncoder<TFromKey, TFromValue>(
|
|
88
|
+
key: Encoder<TFromKey>,
|
|
89
|
+
value: Encoder<TFromValue>,
|
|
90
|
+
config: MapCodecConfig<NumberEncoder> = {},
|
|
91
|
+
): Encoder<Map<TFromKey, TFromValue>> {
|
|
92
|
+
return transformEncoder(
|
|
93
|
+
getArrayEncoder(getTupleEncoder([key, value]), config as object),
|
|
94
|
+
(map: Map<TFromKey, TFromValue>): [TFromKey, TFromValue][] => [...map.entries()],
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Returns a decoder for maps.
|
|
100
|
+
*
|
|
101
|
+
* This decoder deserializes maps where the keys and values are decoded
|
|
102
|
+
* using the provided key and value decoders. The number of entries
|
|
103
|
+
* is determined by the `size` configuration.
|
|
104
|
+
*
|
|
105
|
+
* For more details, see {@link getMapCodec}.
|
|
106
|
+
*
|
|
107
|
+
* @typeParam TToKey - The type of the keys after decoding.
|
|
108
|
+
* @typeParam TToValue - The type of the values after decoding.
|
|
109
|
+
*
|
|
110
|
+
* @param key - The decoder for the map's keys.
|
|
111
|
+
* @param value - The decoder for the map's values.
|
|
112
|
+
* @param config - Configuration options for decoding the map.
|
|
113
|
+
* @returns A `FixedSizeDecoder` or `VariableSizeDecoder` for decoding maps.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* Decoding a map with a `u32` size prefix.
|
|
117
|
+
* ```ts
|
|
118
|
+
* const decoder = getMapDecoder(fixCodecSize(getUtf8Decoder(), 5), getU8Decoder());
|
|
119
|
+
* const map = decoder.decode(new Uint8Array([
|
|
120
|
+
* 0x02,0x00,0x00,0x00,0x61,0x6c,0x69,0x63,0x65,0x2a,0x62,0x6f,0x62,0x00,0x00,0x05
|
|
121
|
+
* ]));
|
|
122
|
+
* // new Map([['alice', 42], ['bob', 5]])
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @see {@link getMapCodec}
|
|
126
|
+
*/
|
|
127
|
+
export function getMapDecoder<TToKey, TToValue>(
|
|
128
|
+
key: Decoder<TToKey>,
|
|
129
|
+
value: Decoder<TToValue>,
|
|
130
|
+
config: MapCodecConfig<NumberDecoder> & { size: 0 },
|
|
131
|
+
): FixedSizeDecoder<Map<TToKey, TToValue>, 0>;
|
|
132
|
+
export function getMapDecoder<TToKey, TToValue>(
|
|
133
|
+
key: FixedSizeDecoder<TToKey>,
|
|
134
|
+
value: FixedSizeDecoder<TToValue>,
|
|
135
|
+
config: MapCodecConfig<NumberDecoder> & { size: number },
|
|
136
|
+
): FixedSizeDecoder<Map<TToKey, TToValue>>;
|
|
137
|
+
export function getMapDecoder<TToKey, TToValue>(
|
|
138
|
+
key: Decoder<TToKey>,
|
|
139
|
+
value: Decoder<TToValue>,
|
|
140
|
+
config?: MapCodecConfig<NumberDecoder>,
|
|
141
|
+
): VariableSizeDecoder<Map<TToKey, TToValue>>;
|
|
142
|
+
export function getMapDecoder<TToKey, TToValue>(
|
|
143
|
+
key: Decoder<TToKey>,
|
|
144
|
+
value: Decoder<TToValue>,
|
|
145
|
+
config: MapCodecConfig<NumberDecoder> = {},
|
|
146
|
+
): Decoder<Map<TToKey, TToValue>> {
|
|
147
|
+
return transformDecoder(
|
|
148
|
+
getArrayDecoder(getTupleDecoder([key, value]), config as object) as Decoder<[TToKey, TToValue][]>,
|
|
149
|
+
(entries: [TToKey, TToValue][]): Map<TToKey, TToValue> => new Map(entries),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Returns a codec for encoding and decoding maps.
|
|
155
|
+
*
|
|
156
|
+
* This codec serializes maps where the key/value pairs are encoded
|
|
157
|
+
* and decoded one after another using the provided key and value codecs.
|
|
158
|
+
* The number of entries is determined by the `size` configuration and
|
|
159
|
+
* defaults to a `u32` size prefix.
|
|
160
|
+
*
|
|
161
|
+
* @typeParam TFromKey - The type of the keys before encoding.
|
|
162
|
+
* @typeParam TFromValue - The type of the values before encoding.
|
|
163
|
+
* @typeParam TToKey - The type of the keys after decoding.
|
|
164
|
+
* @typeParam TToValue - The type of the values after decoding.
|
|
165
|
+
*
|
|
166
|
+
* @param key - The codec for the map's keys.
|
|
167
|
+
* @param value - The codec for the map's values.
|
|
168
|
+
* @param config - Configuration options for encoding and decoding the map.
|
|
169
|
+
* @returns A `FixedSizeCodec` or `VariableSizeCodec` for encoding and decoding maps.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* Encoding and decoding a map with a `u32` size prefix (default).
|
|
173
|
+
* ```ts
|
|
174
|
+
* const codec = getMapCodec(fixCodecSize(getUtf8Codec(), 5), getU8Codec());
|
|
175
|
+
* const bytes = codec.encode(new Map([['alice', 42], ['bob', 5]]));
|
|
176
|
+
* // 0x02000000616c6963652a626f62000005
|
|
177
|
+
* // | | | | └── Value (5)
|
|
178
|
+
* // | | | └── Key ("bob", 5 bytes fixed, null-padded)
|
|
179
|
+
* // | | └── Value (42)
|
|
180
|
+
* // | └── Key ("alice", 5 bytes fixed)
|
|
181
|
+
* // └── 4-byte prefix (2 entries)
|
|
182
|
+
*
|
|
183
|
+
* const map = codec.decode(bytes);
|
|
184
|
+
* // new Map([['alice', 42], ['bob', 5]])
|
|
185
|
+
* ```
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* Encoding and decoding a map with a `u16` size prefix.
|
|
189
|
+
* ```ts
|
|
190
|
+
* const codec = getMapCodec(fixCodecSize(getUtf8Codec(), 5), getU8Codec(), { size: getU16Codec() });
|
|
191
|
+
* const bytes = codec.encode(new Map([['alice', 42], ['bob', 5]]));
|
|
192
|
+
* // 0x0200616c6963652a626f62000005
|
|
193
|
+
* // | | | | └── Value (5)
|
|
194
|
+
* // | | | └── Key ("bob", 5 bytes fixed, null-padded)
|
|
195
|
+
* // | | └── Value (42)
|
|
196
|
+
* // | └── Key ("alice", 5 bytes fixed)
|
|
197
|
+
* // └── 2-byte prefix (2 entries)
|
|
198
|
+
*
|
|
199
|
+
* const map = codec.decode(bytes);
|
|
200
|
+
* // new Map([['alice', 42], ['bob', 5]])
|
|
201
|
+
* ```
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* Encoding and decoding a fixed-size map.
|
|
205
|
+
* ```ts
|
|
206
|
+
* const codec = getMapCodec(fixCodecSize(getUtf8Codec(), 5), getU8Codec(), { size: 2 });
|
|
207
|
+
* const bytes = codec.encode(new Map([['alice', 42], ['bob', 5]]));
|
|
208
|
+
* // 0x616c6963652a626f62000005
|
|
209
|
+
* // | | | └── Value (5)
|
|
210
|
+
* // | | └── Key ("bob", 5 bytes fixed, null-padded)
|
|
211
|
+
* // | └── Value (42)
|
|
212
|
+
* // └── Key ("alice", 5 bytes fixed)
|
|
213
|
+
*
|
|
214
|
+
* const map = codec.decode(bytes);
|
|
215
|
+
* // new Map([['alice', 42], ['bob', 5]])
|
|
216
|
+
* ```
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* Encoding and decoding a map with remainder size.
|
|
220
|
+
* ```ts
|
|
221
|
+
* const codec = getMapCodec(fixCodecSize(getUtf8Codec(), 5), getU8Codec(), { size: 'remainder' });
|
|
222
|
+
* const bytes = codec.encode(new Map([['alice', 42], ['bob', 5]]));
|
|
223
|
+
* // 0x616c6963652a626f62000005
|
|
224
|
+
* // | | | └── Value (5)
|
|
225
|
+
* // | | └── Key ("bob", 5 bytes fixed, null-padded)
|
|
226
|
+
* // | └── Value (42)
|
|
227
|
+
* // └── Key ("alice", 5 bytes fixed)
|
|
228
|
+
* // No size prefix, the size is inferred from the remaining bytes.
|
|
229
|
+
*
|
|
230
|
+
* const map = codec.decode(bytes);
|
|
231
|
+
* // new Map([['alice', 42], ['bob', 5]])
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @remarks
|
|
235
|
+
* Separate {@link getMapEncoder} and {@link getMapDecoder} functions are available.
|
|
236
|
+
* ```ts
|
|
237
|
+
* const bytes = getMapEncoder(fixCodecSize(getUtf8Encoder(), 5), getU8Encoder()).encode(new Map([['alice', 42]]));
|
|
238
|
+
* const map = getMapDecoder(fixCodecSize(getUtf8Decoder(), 5), getU8Decoder()).decode(bytes);
|
|
239
|
+
* ```
|
|
240
|
+
*
|
|
241
|
+
* @see {@link getMapEncoder}
|
|
242
|
+
* @see {@link getMapDecoder}
|
|
243
|
+
*/
|
|
244
|
+
export function getMapCodec<
|
|
245
|
+
TFromKey,
|
|
246
|
+
TFromValue,
|
|
247
|
+
TToKey extends TFromKey = TFromKey,
|
|
248
|
+
TToValue extends TFromValue = TFromValue,
|
|
249
|
+
>(
|
|
250
|
+
key: Codec<TFromKey, TToKey>,
|
|
251
|
+
value: Codec<TFromValue, TToValue>,
|
|
252
|
+
config: MapCodecConfig<NumberCodec> & { size: 0 },
|
|
253
|
+
): FixedSizeCodec<Map<TFromKey, TFromValue>, Map<TToKey, TToValue>, 0>;
|
|
254
|
+
export function getMapCodec<
|
|
255
|
+
TFromKey,
|
|
256
|
+
TFromValue,
|
|
257
|
+
TToKey extends TFromKey = TFromKey,
|
|
258
|
+
TToValue extends TFromValue = TFromValue,
|
|
259
|
+
>(
|
|
260
|
+
key: FixedSizeCodec<TFromKey, TToKey>,
|
|
261
|
+
value: FixedSizeCodec<TFromValue, TToValue>,
|
|
262
|
+
config: MapCodecConfig<NumberCodec> & { size: number },
|
|
263
|
+
): FixedSizeCodec<Map<TFromKey, TFromValue>, Map<TToKey, TToValue>>;
|
|
264
|
+
export function getMapCodec<
|
|
265
|
+
TFromKey,
|
|
266
|
+
TFromValue,
|
|
267
|
+
TToKey extends TFromKey = TFromKey,
|
|
268
|
+
TToValue extends TFromValue = TFromValue,
|
|
269
|
+
>(
|
|
270
|
+
key: Codec<TFromKey, TToKey>,
|
|
271
|
+
value: Codec<TFromValue, TToValue>,
|
|
272
|
+
config?: MapCodecConfig<NumberCodec>,
|
|
273
|
+
): VariableSizeCodec<Map<TFromKey, TFromValue>, Map<TToKey, TToValue>>;
|
|
274
|
+
export function getMapCodec<
|
|
275
|
+
TFromKey,
|
|
276
|
+
TFromValue,
|
|
277
|
+
TToKey extends TFromKey = TFromKey,
|
|
278
|
+
TToValue extends TFromValue = TFromValue,
|
|
279
|
+
>(
|
|
280
|
+
key: Codec<TFromKey, TToKey>,
|
|
281
|
+
value: Codec<TFromValue, TToValue>,
|
|
282
|
+
config: MapCodecConfig<NumberCodec> = {},
|
|
283
|
+
): Codec<Map<TFromKey, TFromValue>, Map<TToKey, TToValue>> {
|
|
284
|
+
return combineCodec(getMapEncoder(key, value, config as object), getMapDecoder(key, value, config as object));
|
|
285
|
+
}
|