@solana/codecs-data-structures 2.0.0-experimental.efe6f4d → 2.0.0-experimental.f025b33

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.
Files changed (45) hide show
  1. package/README.md +482 -4
  2. package/dist/index.browser.cjs +322 -430
  3. package/dist/index.browser.cjs.map +1 -1
  4. package/dist/index.browser.js +324 -428
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.native.js +324 -428
  7. package/dist/index.native.js.map +1 -1
  8. package/dist/index.node.cjs +322 -430
  9. package/dist/index.node.cjs.map +1 -1
  10. package/dist/index.node.js +324 -428
  11. package/dist/index.node.js.map +1 -1
  12. package/dist/types/array.d.ts +35 -6
  13. package/dist/types/array.d.ts.map +1 -1
  14. package/dist/types/bit-array.d.ts +5 -5
  15. package/dist/types/bit-array.d.ts.map +1 -1
  16. package/dist/types/boolean.d.ts +18 -6
  17. package/dist/types/boolean.d.ts.map +1 -1
  18. package/dist/types/bytes.d.ts +14 -5
  19. package/dist/types/bytes.d.ts.map +1 -1
  20. package/dist/types/data-enum.d.ts +14 -14
  21. package/dist/types/data-enum.d.ts.map +1 -1
  22. package/dist/types/index.d.ts +13 -14
  23. package/dist/types/index.d.ts.map +1 -1
  24. package/dist/types/map.d.ts +24 -6
  25. package/dist/types/map.d.ts.map +1 -1
  26. package/dist/types/nullable.d.ts +24 -6
  27. package/dist/types/nullable.d.ts.map +1 -1
  28. package/dist/types/scalar-enum.d.ts +18 -6
  29. package/dist/types/scalar-enum.d.ts.map +1 -1
  30. package/dist/types/set.d.ts +24 -6
  31. package/dist/types/set.d.ts.map +1 -1
  32. package/dist/types/struct.d.ts +28 -18
  33. package/dist/types/struct.d.ts.map +1 -1
  34. package/dist/types/tuple.d.ts +22 -15
  35. package/dist/types/tuple.d.ts.map +1 -1
  36. package/dist/types/unit.d.ts +4 -12
  37. package/dist/types/unit.d.ts.map +1 -1
  38. package/dist/types/utils.d.ts +10 -2
  39. package/dist/types/utils.d.ts.map +1 -1
  40. package/package.json +10 -10
  41. package/dist/index.development.js +0 -865
  42. package/dist/index.development.js.map +0 -1
  43. package/dist/index.production.min.js +0 -51
  44. package/dist/types/array-like-codec-size.d.ts +0 -20
  45. package/dist/types/array-like-codec-size.d.ts.map +0 -1
@@ -5,7 +5,12 @@ var codecsNumbers = require('@solana/codecs-numbers');
5
5
 
6
6
  // src/array.ts
7
7
 
8
- // src/utils.ts
8
+ // src/assertions.ts
9
+ function assertValidNumberOfItemsForCodec(codecDescription, expected, actual) {
10
+ if (expected !== actual) {
11
+ throw new Error(`Expected [${codecDescription}] to have ${expected} items, got ${actual}.`);
12
+ }
13
+ }
9
14
  function maxCodecSizes(sizes) {
10
15
  return sizes.reduce(
11
16
  (all, size) => all === null || size === null ? null : Math.max(all, size),
@@ -15,106 +20,88 @@ function maxCodecSizes(sizes) {
15
20
  function sumCodecSizes(sizes) {
16
21
  return sizes.reduce((all, size) => all === null || size === null ? null : all + size, 0);
17
22
  }
18
-
19
- // src/array-like-codec-size.ts
20
- function decodeArrayLikeCodecSize(size, childrenSizes, bytes, offset) {
21
- if (typeof size === "number") {
22
- return [size, offset];
23
- }
24
- if (typeof size === "object") {
25
- return size.decode(bytes, offset);
26
- }
27
- if (size === "remainder") {
28
- const childrenSize = sumCodecSizes(childrenSizes);
29
- if (childrenSize === null) {
30
- throw new Error('Codecs of "remainder" size must have fixed-size items.');
31
- }
32
- const remainder = bytes.slice(offset).length;
33
- if (remainder % childrenSize !== 0) {
34
- throw new Error(
35
- `The remainder of the byte array (${remainder} bytes) cannot be split into chunks of ${childrenSize} bytes. Codecs of "remainder" size must have a remainder that is a multiple of its item size. In other words, ${remainder} modulo ${childrenSize} should be equal to zero.`
36
- );
37
- }
38
- return [remainder / childrenSize, offset];
39
- }
40
- throw new Error(`Unrecognized array-like codec size: ${JSON.stringify(size)}`);
23
+ function getFixedSize(codec) {
24
+ return codecsCore.isFixedSize(codec) ? codec.fixedSize : null;
41
25
  }
42
- function getArrayLikeCodecSizeDescription(size) {
43
- return typeof size === "object" ? size.description : `${size}`;
44
- }
45
- function getArrayLikeCodecSizeFromChildren(size, childrenSizes) {
46
- if (typeof size !== "number")
47
- return null;
48
- if (size === 0)
49
- return 0;
50
- const childrenSize = sumCodecSizes(childrenSizes);
51
- return childrenSize === null ? null : childrenSize * size;
52
- }
53
- function getArrayLikeCodecSizePrefix(size, realSize) {
54
- return typeof size === "object" ? size.encode(realSize) : new Uint8Array();
55
- }
56
-
57
- // src/assertions.ts
58
- function assertValidNumberOfItemsForCodec(codecDescription, expected, actual) {
59
- if (expected !== actual) {
60
- throw new Error(`Expected [${codecDescription}] to have ${expected} items, got ${actual}.`);
61
- }
26
+ function getMaxSize(codec) {
27
+ return codecsCore.isFixedSize(codec) ? codec.fixedSize : codec.maxSize ?? null;
62
28
  }
63
29
 
64
30
  // src/array.ts
65
- function arrayCodecHelper(item, size, description) {
66
- if (size === "remainder" && item.fixedSize === null) {
67
- throw new Error('Codecs of "remainder" size must have fixed-size items.');
68
- }
69
- return {
70
- description: description ?? `array(${item.description}; ${getArrayLikeCodecSizeDescription(size)})`,
71
- fixedSize: getArrayLikeCodecSizeFromChildren(size, [item.fixedSize]),
72
- maxSize: getArrayLikeCodecSizeFromChildren(size, [item.maxSize])
73
- };
74
- }
75
31
  function getArrayEncoder(item, config = {}) {
76
32
  const size = config.size ?? codecsNumbers.getU32Encoder();
77
- return {
78
- ...arrayCodecHelper(item, size, config.description),
79
- encode: (value) => {
33
+ const fixedSize = computeArrayLikeCodecSize(size, getFixedSize(item));
34
+ const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
35
+ return codecsCore.createEncoder({
36
+ ...fixedSize !== null ? { fixedSize } : {
37
+ getSizeFromValue: (array) => {
38
+ const prefixSize = typeof size === "object" ? codecsCore.getEncodedSize(array.length, size) : 0;
39
+ return prefixSize + [...array].reduce((all, value) => all + codecsCore.getEncodedSize(value, item), 0);
40
+ },
41
+ maxSize
42
+ },
43
+ write: (array, bytes, offset) => {
80
44
  if (typeof size === "number") {
81
- assertValidNumberOfItemsForCodec("array", size, value.length);
45
+ assertValidNumberOfItemsForCodec("array", size, array.length);
46
+ }
47
+ if (typeof size === "object") {
48
+ offset = size.write(array.length, bytes, offset);
82
49
  }
83
- return codecsCore.mergeBytes([getArrayLikeCodecSizePrefix(size, value.length), ...value.map((v) => item.encode(v))]);
50
+ array.forEach((value) => {
51
+ offset = item.write(value, bytes, offset);
52
+ });
53
+ return offset;
84
54
  }
85
- };
55
+ });
86
56
  }
87
57
  function getArrayDecoder(item, config = {}) {
88
58
  const size = config.size ?? codecsNumbers.getU32Decoder();
89
- return {
90
- ...arrayCodecHelper(item, size, config.description),
91
- decode: (bytes, offset = 0) => {
59
+ const itemSize = getFixedSize(item);
60
+ const fixedSize = computeArrayLikeCodecSize(size, itemSize);
61
+ const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
62
+ return codecsCore.createDecoder({
63
+ ...fixedSize !== null ? { fixedSize } : { maxSize },
64
+ read: (bytes, offset) => {
65
+ const array = [];
92
66
  if (typeof size === "object" && bytes.slice(offset).length === 0) {
93
- return [[], offset];
67
+ return [array, offset];
68
+ }
69
+ if (size === "remainder") {
70
+ while (offset < bytes.length) {
71
+ const [value, newOffset2] = item.read(bytes, offset);
72
+ offset = newOffset2;
73
+ array.push(value);
74
+ }
75
+ return [array, offset];
94
76
  }
95
- const [resolvedSize, newOffset] = decodeArrayLikeCodecSize(size, [item.fixedSize], bytes, offset);
77
+ const [resolvedSize, newOffset] = typeof size === "number" ? [size, offset] : size.read(bytes, offset);
96
78
  offset = newOffset;
97
- const values = [];
98
79
  for (let i = 0; i < resolvedSize; i += 1) {
99
- const [value, newOffset2] = item.decode(bytes, offset);
100
- values.push(value);
80
+ const [value, newOffset2] = item.read(bytes, offset);
101
81
  offset = newOffset2;
82
+ array.push(value);
102
83
  }
103
- return [values, offset];
84
+ return [array, offset];
104
85
  }
105
- };
86
+ });
106
87
  }
107
88
  function getArrayCodec(item, config = {}) {
108
89
  return codecsCore.combineCodec(getArrayEncoder(item, config), getArrayDecoder(item, config));
109
90
  }
110
- var getBitArrayEncoder = (size, config = {}) => {
91
+ function computeArrayLikeCodecSize(size, itemSize) {
92
+ if (typeof size !== "number")
93
+ return null;
94
+ if (size === 0)
95
+ return 0;
96
+ return itemSize === null ? null : itemSize * size;
97
+ }
98
+ function getBitArrayEncoder(size, config = {}) {
111
99
  const parsedConfig = typeof config === "boolean" ? { backward: config } : config;
112
100
  const backward = parsedConfig.backward ?? false;
113
- const backwardSuffix = backward ? "; backward" : "";
114
- return {
115
- description: parsedConfig.description ?? `bitArray(${size}${backwardSuffix})`,
116
- encode(value) {
117
- const bytes = [];
101
+ return codecsCore.createEncoder({
102
+ fixedSize: size,
103
+ write(value, bytes, offset) {
104
+ const bytesToAdd = [];
118
105
  for (let i = 0; i < size; i += 1) {
119
106
  let byte = 0;
120
107
  for (let j = 0; j < 8; j += 1) {
@@ -122,23 +109,22 @@ var getBitArrayEncoder = (size, config = {}) => {
122
109
  byte |= feature << (backward ? j : 7 - j);
123
110
  }
124
111
  if (backward) {
125
- bytes.unshift(byte);
112
+ bytesToAdd.unshift(byte);
126
113
  } else {
127
- bytes.push(byte);
114
+ bytesToAdd.push(byte);
128
115
  }
129
116
  }
130
- return new Uint8Array(bytes);
131
- },
132
- fixedSize: size,
133
- maxSize: size
134
- };
135
- };
136
- var getBitArrayDecoder = (size, config = {}) => {
117
+ bytes.set(bytesToAdd, offset);
118
+ return size;
119
+ }
120
+ });
121
+ }
122
+ function getBitArrayDecoder(size, config = {}) {
137
123
  const parsedConfig = typeof config === "boolean" ? { backward: config } : config;
138
124
  const backward = parsedConfig.backward ?? false;
139
- const backwardSuffix = backward ? "; backward" : "";
140
- return {
141
- decode(bytes, offset = 0) {
125
+ return codecsCore.createDecoder({
126
+ fixedSize: size,
127
+ read(bytes, offset) {
142
128
  codecsCore.assertByteArrayHasEnoughBytesForCodec("bitArray", size, bytes, offset);
143
129
  const booleans = [];
144
130
  let slice = bytes.slice(offset, offset + size);
@@ -155,138 +141,107 @@ var getBitArrayDecoder = (size, config = {}) => {
155
141
  }
156
142
  });
157
143
  return [booleans, offset + size];
158
- },
159
- description: parsedConfig.description ?? `bitArray(${size}${backwardSuffix})`,
160
- fixedSize: size,
161
- maxSize: size
162
- };
163
- };
164
- var getBitArrayCodec = (size, config = {}) => codecsCore.combineCodec(getBitArrayEncoder(size, config), getBitArrayDecoder(size, config));
144
+ }
145
+ });
146
+ }
147
+ function getBitArrayCodec(size, config = {}) {
148
+ return codecsCore.combineCodec(getBitArrayEncoder(size, config), getBitArrayDecoder(size, config));
149
+ }
165
150
  function getBooleanEncoder(config = {}) {
166
151
  const size = config.size ?? codecsNumbers.getU8Encoder();
167
- codecsCore.assertFixedSizeCodec(size, "Codec [bool] requires a fixed size.");
168
- return {
169
- description: config.description ?? `bool(${size.description})`,
170
- encode: (value) => size.encode(value ? 1 : 0),
171
- fixedSize: size.fixedSize,
172
- maxSize: size.fixedSize
173
- };
152
+ codecsCore.assertIsFixedSize(size, "Codec [bool] requires a fixed size.");
153
+ return codecsCore.mapEncoder(size, (value) => value ? 1 : 0);
174
154
  }
175
155
  function getBooleanDecoder(config = {}) {
176
156
  const size = config.size ?? codecsNumbers.getU8Decoder();
177
- codecsCore.assertFixedSizeCodec(size, "Codec [bool] requires a fixed size.");
178
- return {
179
- decode: (bytes, offset = 0) => {
180
- codecsCore.assertByteArrayIsNotEmptyForCodec("bool", bytes, offset);
181
- const [value, vOffset] = size.decode(bytes, offset);
182
- return [value === 1, vOffset];
183
- },
184
- description: config.description ?? `bool(${size.description})`,
185
- fixedSize: size.fixedSize,
186
- maxSize: size.fixedSize
187
- };
157
+ codecsCore.assertIsFixedSize(size, "Codec [bool] requires a fixed size.");
158
+ return codecsCore.mapDecoder(size, (value) => Number(value) === 1);
188
159
  }
189
160
  function getBooleanCodec(config = {}) {
190
161
  return codecsCore.combineCodec(getBooleanEncoder(config), getBooleanDecoder(config));
191
162
  }
192
163
  function getBytesEncoder(config = {}) {
193
164
  const size = config.size ?? "variable";
194
- const sizeDescription = typeof size === "object" ? size.description : `${size}`;
195
- const description = config.description ?? `bytes(${sizeDescription})`;
196
- const byteEncoder = {
197
- description,
198
- encode: (value) => value,
199
- fixedSize: null,
200
- maxSize: null
201
- };
165
+ const byteEncoder = codecsCore.createEncoder({
166
+ getSizeFromValue: (value) => value.length,
167
+ write: (value, bytes, offset) => {
168
+ bytes.set(value, offset);
169
+ return offset + value.length;
170
+ }
171
+ });
202
172
  if (size === "variable") {
203
173
  return byteEncoder;
204
174
  }
205
175
  if (typeof size === "number") {
206
- return codecsCore.fixEncoder(byteEncoder, size, description);
176
+ return codecsCore.fixEncoder(byteEncoder, size);
207
177
  }
208
- return {
209
- ...byteEncoder,
210
- encode: (value) => {
211
- const contentBytes = byteEncoder.encode(value);
212
- const lengthBytes = size.encode(contentBytes.length);
213
- return codecsCore.mergeBytes([lengthBytes, contentBytes]);
178
+ return codecsCore.createEncoder({
179
+ getSizeFromValue: (value) => codecsCore.getEncodedSize(value.length, size) + value.length,
180
+ write: (value, bytes, offset) => {
181
+ offset = size.write(value.length, bytes, offset);
182
+ return byteEncoder.write(value, bytes, offset);
214
183
  }
215
- };
184
+ });
216
185
  }
217
186
  function getBytesDecoder(config = {}) {
218
187
  const size = config.size ?? "variable";
219
- const sizeDescription = typeof size === "object" ? size.description : `${size}`;
220
- const description = config.description ?? `bytes(${sizeDescription})`;
221
- const byteDecoder = {
222
- decode: (bytes, offset = 0) => {
188
+ const byteDecoder = codecsCore.createDecoder({
189
+ read: (bytes, offset) => {
223
190
  const slice = bytes.slice(offset);
224
191
  return [slice, offset + slice.length];
225
- },
226
- description,
227
- fixedSize: null,
228
- maxSize: null
229
- };
192
+ }
193
+ });
230
194
  if (size === "variable") {
231
195
  return byteDecoder;
232
196
  }
233
197
  if (typeof size === "number") {
234
- return codecsCore.fixDecoder(byteDecoder, size, description);
198
+ return codecsCore.fixDecoder(byteDecoder, size);
235
199
  }
236
- return {
237
- ...byteDecoder,
238
- decode: (bytes, offset = 0) => {
200
+ return codecsCore.createDecoder({
201
+ read: (bytes, offset) => {
239
202
  codecsCore.assertByteArrayIsNotEmptyForCodec("bytes", bytes, offset);
240
- const [lengthBigInt, lengthOffset] = size.decode(bytes, offset);
203
+ const [lengthBigInt, lengthOffset] = size.read(bytes, offset);
241
204
  const length = Number(lengthBigInt);
242
205
  offset = lengthOffset;
243
206
  const contentBytes = bytes.slice(offset, offset + length);
244
207
  codecsCore.assertByteArrayHasEnoughBytesForCodec("bytes", length, contentBytes);
245
- const [value, contentOffset] = byteDecoder.decode(contentBytes);
208
+ const [value, contentOffset] = byteDecoder.read(contentBytes, 0);
246
209
  offset += contentOffset;
247
210
  return [value, offset];
248
211
  }
249
- };
212
+ });
250
213
  }
251
214
  function getBytesCodec(config = {}) {
252
215
  return codecsCore.combineCodec(getBytesEncoder(config), getBytesDecoder(config));
253
216
  }
254
- function dataEnumCodecHelper(variants, prefix, description) {
255
- const fieldDescriptions = variants.map(([name, codec]) => `${String(name)}${codec ? `: ${codec.description}` : ""}`).join(", ");
256
- const allVariantHaveTheSameFixedSize = variants.every((one, _i, all) => one[1].fixedSize === all[0][1].fixedSize);
257
- const fixedVariantSize = allVariantHaveTheSameFixedSize ? variants[0][1].fixedSize : null;
258
- const maxVariantSize = maxCodecSizes(variants.map(([, field]) => field.maxSize));
259
- return {
260
- description: description ?? `dataEnum(${fieldDescriptions}; ${prefix.description})`,
261
- fixedSize: variants.length === 0 ? prefix.fixedSize : sumCodecSizes([prefix.fixedSize, fixedVariantSize]),
262
- maxSize: variants.length === 0 ? prefix.maxSize : sumCodecSizes([prefix.maxSize, maxVariantSize])
263
- };
264
- }
265
217
  function getDataEnumEncoder(variants, config = {}) {
266
218
  const prefix = config.size ?? codecsNumbers.getU8Encoder();
267
- return {
268
- ...dataEnumCodecHelper(variants, prefix, config.description),
269
- encode: (variant) => {
270
- const discriminator = variants.findIndex(([key]) => variant.__kind === key);
271
- if (discriminator < 0) {
272
- throw new Error(
273
- `Invalid data enum variant. Expected one of [${variants.map(([key]) => key).join(", ")}], got "${variant.__kind}".`
274
- );
275
- }
276
- const variantPrefix = prefix.encode(discriminator);
277
- const variantSerializer = variants[discriminator][1];
278
- const variantBytes = variantSerializer.encode(variant);
279
- return codecsCore.mergeBytes([variantPrefix, variantBytes]);
219
+ const fixedSize = getDataEnumFixedSize(variants, prefix);
220
+ return codecsCore.createEncoder({
221
+ ...fixedSize !== null ? { fixedSize } : {
222
+ getSizeFromValue: (variant) => {
223
+ const discriminator = getVariantDiscriminator(variants, variant);
224
+ const variantEncoder = variants[discriminator][1];
225
+ return codecsCore.getEncodedSize(discriminator, prefix) + codecsCore.getEncodedSize(variant, variantEncoder);
226
+ },
227
+ maxSize: getDataEnumMaxSize(variants, prefix)
228
+ },
229
+ write: (variant, bytes, offset) => {
230
+ const discriminator = getVariantDiscriminator(variants, variant);
231
+ offset = prefix.write(discriminator, bytes, offset);
232
+ const variantEncoder = variants[discriminator][1];
233
+ return variantEncoder.write(variant, bytes, offset);
280
234
  }
281
- };
235
+ });
282
236
  }
283
237
  function getDataEnumDecoder(variants, config = {}) {
284
238
  const prefix = config.size ?? codecsNumbers.getU8Decoder();
285
- return {
286
- ...dataEnumCodecHelper(variants, prefix, config.description),
287
- decode: (bytes, offset = 0) => {
239
+ const fixedSize = getDataEnumFixedSize(variants, prefix);
240
+ return codecsCore.createDecoder({
241
+ ...fixedSize !== null ? { fixedSize } : { maxSize: getDataEnumMaxSize(variants, prefix) },
242
+ read: (bytes, offset) => {
288
243
  codecsCore.assertByteArrayIsNotEmptyForCodec("dataEnum", bytes, offset);
289
- const [discriminator, dOffset] = prefix.decode(bytes, offset);
244
+ const [discriminator, dOffset] = prefix.read(bytes, offset);
290
245
  offset = dOffset;
291
246
  const variantField = variants[Number(discriminator)] ?? null;
292
247
  if (!variantField) {
@@ -294,337 +249,274 @@ function getDataEnumDecoder(variants, config = {}) {
294
249
  `Enum discriminator out of range. Expected a number between 0 and ${variants.length - 1}, got ${discriminator}.`
295
250
  );
296
251
  }
297
- const [variant, vOffset] = variantField[1].decode(bytes, offset);
252
+ const [variant, vOffset] = variantField[1].read(bytes, offset);
298
253
  offset = vOffset;
299
254
  return [{ __kind: variantField[0], ...variant ?? {} }, offset];
300
255
  }
301
- };
256
+ });
302
257
  }
303
258
  function getDataEnumCodec(variants, config = {}) {
304
259
  return codecsCore.combineCodec(getDataEnumEncoder(variants, config), getDataEnumDecoder(variants, config));
305
260
  }
306
- function mapCodecHelper(key, value, size, description) {
307
- if (size === "remainder" && (key.fixedSize === null || value.fixedSize === null)) {
308
- throw new Error('Codecs of "remainder" size must have fixed-size items.');
261
+ function getDataEnumFixedSize(variants, prefix) {
262
+ if (variants.length === 0)
263
+ return codecsCore.isFixedSize(prefix) ? prefix.fixedSize : null;
264
+ if (!codecsCore.isFixedSize(variants[0][1]))
265
+ return null;
266
+ const variantSize = variants[0][1].fixedSize;
267
+ const sameSizedVariants = variants.every(
268
+ (variant) => codecsCore.isFixedSize(variant[1]) && variant[1].fixedSize === variantSize
269
+ );
270
+ if (!sameSizedVariants)
271
+ return null;
272
+ return codecsCore.isFixedSize(prefix) ? prefix.fixedSize + variantSize : null;
273
+ }
274
+ function getDataEnumMaxSize(variants, prefix) {
275
+ const maxVariantSize = maxCodecSizes(variants.map(([, codec]) => getMaxSize(codec)));
276
+ return sumCodecSizes([getMaxSize(prefix), maxVariantSize]) ?? void 0;
277
+ }
278
+ function getVariantDiscriminator(variants, variant) {
279
+ const discriminator = variants.findIndex(([key]) => variant.__kind === key);
280
+ if (discriminator < 0) {
281
+ throw new Error(
282
+ `Invalid data enum variant. Expected one of [${variants.map(([key]) => key).join(", ")}], got "${variant.__kind}".`
283
+ );
309
284
  }
310
- return {
311
- description: description ?? `map(${key.description}, ${value.description}; ${getArrayLikeCodecSizeDescription(size)})`,
312
- fixedSize: getArrayLikeCodecSizeFromChildren(size, [key.fixedSize, value.fixedSize]),
313
- maxSize: getArrayLikeCodecSizeFromChildren(size, [key.maxSize, value.maxSize])
314
- };
285
+ return discriminator;
286
+ }
287
+ function getTupleEncoder(items) {
288
+ const fixedSize = sumCodecSizes(items.map(getFixedSize));
289
+ const maxSize = sumCodecSizes(items.map(getMaxSize)) ?? void 0;
290
+ return codecsCore.createEncoder({
291
+ ...fixedSize === null ? {
292
+ getSizeFromValue: (value) => items.map((item, index) => codecsCore.getEncodedSize(value[index], item)).reduce((all, one) => all + one, 0),
293
+ maxSize
294
+ } : { fixedSize },
295
+ write: (value, bytes, offset) => {
296
+ assertValidNumberOfItemsForCodec("tuple", items.length, value.length);
297
+ items.forEach((item, index) => {
298
+ offset = item.write(value[index], bytes, offset);
299
+ });
300
+ return offset;
301
+ }
302
+ });
303
+ }
304
+ function getTupleDecoder(items) {
305
+ const fixedSize = sumCodecSizes(items.map(getFixedSize));
306
+ const maxSize = sumCodecSizes(items.map(getMaxSize)) ?? void 0;
307
+ return codecsCore.createDecoder({
308
+ ...fixedSize === null ? { maxSize } : { fixedSize },
309
+ read: (bytes, offset) => {
310
+ const values = [];
311
+ items.forEach((item) => {
312
+ const [newValue, newOffset] = item.read(bytes, offset);
313
+ values.push(newValue);
314
+ offset = newOffset;
315
+ });
316
+ return [values, offset];
317
+ }
318
+ });
315
319
  }
320
+ function getTupleCodec(items) {
321
+ return codecsCore.combineCodec(
322
+ getTupleEncoder(items),
323
+ getTupleDecoder(items)
324
+ );
325
+ }
326
+
327
+ // src/map.ts
316
328
  function getMapEncoder(key, value, config = {}) {
317
- const size = config.size ?? codecsNumbers.getU32Encoder();
318
- return {
319
- ...mapCodecHelper(key, value, size, config.description),
320
- encode: (map) => {
321
- if (typeof size === "number") {
322
- assertValidNumberOfItemsForCodec("map", size, map.size);
323
- }
324
- const itemBytes = Array.from(map, ([k, v]) => codecsCore.mergeBytes([key.encode(k), value.encode(v)]));
325
- return codecsCore.mergeBytes([getArrayLikeCodecSizePrefix(size, map.size), ...itemBytes]);
326
- }
327
- };
329
+ return codecsCore.mapEncoder(
330
+ getArrayEncoder(getTupleEncoder([key, value]), config),
331
+ (map) => [...map.entries()]
332
+ );
328
333
  }
329
334
  function getMapDecoder(key, value, config = {}) {
330
- const size = config.size ?? codecsNumbers.getU32Decoder();
331
- return {
332
- ...mapCodecHelper(key, value, size, config.description),
333
- decode: (bytes, offset = 0) => {
334
- const map = /* @__PURE__ */ new Map();
335
- if (typeof size === "object" && bytes.slice(offset).length === 0) {
336
- return [map, offset];
337
- }
338
- const [resolvedSize, newOffset] = decodeArrayLikeCodecSize(
339
- size,
340
- [key.fixedSize, value.fixedSize],
341
- bytes,
342
- offset
343
- );
344
- offset = newOffset;
345
- for (let i = 0; i < resolvedSize; i += 1) {
346
- const [decodedKey, kOffset] = key.decode(bytes, offset);
347
- offset = kOffset;
348
- const [decodedValue, vOffset] = value.decode(bytes, offset);
349
- offset = vOffset;
350
- map.set(decodedKey, decodedValue);
351
- }
352
- return [map, offset];
353
- }
354
- };
335
+ return codecsCore.mapDecoder(
336
+ getArrayDecoder(getTupleDecoder([key, value]), config),
337
+ (entries) => new Map(entries)
338
+ );
355
339
  }
356
340
  function getMapCodec(key, value, config = {}) {
357
341
  return codecsCore.combineCodec(getMapEncoder(key, value, config), getMapDecoder(key, value, config));
358
342
  }
359
- function nullableCodecHelper(item, prefix, fixed, description) {
360
- let descriptionSuffix = `; ${prefix.description}`;
361
- let fixedSize = item.fixedSize === 0 ? prefix.fixedSize : null;
362
- if (fixed) {
363
- codecsCore.assertFixedSizeCodec(item, "Fixed nullables can only be used with fixed-size codecs.");
364
- codecsCore.assertFixedSizeCodec(prefix, "Fixed nullables can only be used with fixed-size prefix.");
365
- descriptionSuffix += "; fixed";
366
- fixedSize = prefix.fixedSize + item.fixedSize;
367
- }
368
- return {
369
- description: description ?? `nullable(${item.description + descriptionSuffix})`,
370
- fixedSize,
371
- maxSize: sumCodecSizes([prefix.maxSize, item.maxSize])
372
- };
373
- }
374
343
  function getNullableEncoder(item, config = {}) {
375
344
  const prefix = config.prefix ?? codecsNumbers.getU8Encoder();
376
345
  const fixed = config.fixed ?? false;
377
- return {
378
- ...nullableCodecHelper(item, prefix, fixed, config.description),
379
- encode: (option) => {
380
- const prefixByte = prefix.encode(Number(option !== null));
381
- let itemBytes = option !== null ? item.encode(option) : new Uint8Array();
382
- itemBytes = fixed ? codecsCore.fixBytes(itemBytes, item.fixedSize) : itemBytes;
383
- return codecsCore.mergeBytes([prefixByte, itemBytes]);
346
+ const isZeroSizeItem = codecsCore.isFixedSize(item) && codecsCore.isFixedSize(prefix) && item.fixedSize === 0;
347
+ if (fixed || isZeroSizeItem) {
348
+ codecsCore.assertIsFixedSize(item, "Fixed nullables can only be used with fixed-size codecs.");
349
+ codecsCore.assertIsFixedSize(prefix, "Fixed nullables can only be used with fixed-size prefix.");
350
+ const fixedSize = prefix.fixedSize + item.fixedSize;
351
+ return codecsCore.createEncoder({
352
+ fixedSize,
353
+ write: (option, bytes, offset) => {
354
+ const prefixOffset = prefix.write(Number(option !== null), bytes, offset);
355
+ if (option !== null) {
356
+ item.write(option, bytes, prefixOffset);
357
+ }
358
+ return offset + fixedSize;
359
+ }
360
+ });
361
+ }
362
+ return codecsCore.createEncoder({
363
+ getSizeFromValue: (option) => codecsCore.getEncodedSize(Number(option !== null), prefix) + (option !== null ? codecsCore.getEncodedSize(option, item) : 0),
364
+ maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? void 0,
365
+ write: (option, bytes, offset) => {
366
+ offset = prefix.write(Number(option !== null), bytes, offset);
367
+ if (option !== null) {
368
+ offset = item.write(option, bytes, offset);
369
+ }
370
+ return offset;
384
371
  }
385
- };
372
+ });
386
373
  }
387
374
  function getNullableDecoder(item, config = {}) {
388
375
  const prefix = config.prefix ?? codecsNumbers.getU8Decoder();
389
376
  const fixed = config.fixed ?? false;
390
- return {
391
- ...nullableCodecHelper(item, prefix, fixed, config.description),
392
- decode: (bytes, offset = 0) => {
377
+ let fixedSize = null;
378
+ const isZeroSizeItem = codecsCore.isFixedSize(item) && codecsCore.isFixedSize(prefix) && item.fixedSize === 0;
379
+ if (fixed || isZeroSizeItem) {
380
+ codecsCore.assertIsFixedSize(item, "Fixed nullables can only be used with fixed-size codecs.");
381
+ codecsCore.assertIsFixedSize(prefix, "Fixed nullables can only be used with fixed-size prefix.");
382
+ fixedSize = prefix.fixedSize + item.fixedSize;
383
+ }
384
+ return codecsCore.createDecoder({
385
+ ...fixedSize === null ? { maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? void 0 } : { fixedSize },
386
+ read: (bytes, offset) => {
393
387
  if (bytes.length - offset <= 0) {
394
388
  return [null, offset];
395
389
  }
396
- const fixedOffset = offset + (prefix.fixedSize ?? 0) + (item.fixedSize ?? 0);
397
- const [isSome, prefixOffset] = prefix.decode(bytes, offset);
398
- offset = prefixOffset;
390
+ const [isSome, prefixOffset] = prefix.read(bytes, offset);
399
391
  if (isSome === 0) {
400
- return [null, fixed ? fixedOffset : offset];
392
+ return [null, fixedSize !== null ? offset + fixedSize : prefixOffset];
401
393
  }
402
- const [value, newOffset] = item.decode(bytes, offset);
403
- offset = newOffset;
404
- return [value, fixed ? fixedOffset : offset];
394
+ const [value, newOffset] = item.read(bytes, prefixOffset);
395
+ return [value, fixedSize !== null ? offset + fixedSize : newOffset];
405
396
  }
406
- };
397
+ });
407
398
  }
408
399
  function getNullableCodec(item, config = {}) {
409
- return codecsCore.combineCodec(getNullableEncoder(item, config), getNullableDecoder(item, config));
400
+ const configCast = config;
401
+ return codecsCore.combineCodec(getNullableEncoder(item, configCast), getNullableDecoder(item, configCast));
402
+ }
403
+ function getScalarEnumEncoder(constructor, config = {}) {
404
+ const prefix = config.size ?? codecsNumbers.getU8Encoder();
405
+ const { minRange, maxRange, stringValues, enumKeys, enumValues } = getScalarEnumStats(constructor);
406
+ return codecsCore.mapEncoder(prefix, (value) => {
407
+ const isInvalidNumber = typeof value === "number" && (value < minRange || value > maxRange);
408
+ const isInvalidString = typeof value === "string" && !stringValues.includes(value);
409
+ if (isInvalidNumber || isInvalidString) {
410
+ throw new Error(
411
+ `Invalid scalar enum variant. Expected one of [${stringValues.join(", ")}] or a number between ${minRange} and ${maxRange}, got "${value}".`
412
+ );
413
+ }
414
+ if (typeof value === "number")
415
+ return value;
416
+ const valueIndex = enumValues.indexOf(value);
417
+ if (valueIndex >= 0)
418
+ return valueIndex;
419
+ return enumKeys.indexOf(value);
420
+ });
421
+ }
422
+ function getScalarEnumDecoder(constructor, config = {}) {
423
+ const prefix = config.size ?? codecsNumbers.getU8Decoder();
424
+ const { minRange, maxRange, isNumericEnum, enumValues } = getScalarEnumStats(constructor);
425
+ return codecsCore.mapDecoder(prefix, (value) => {
426
+ const valueAsNumber = Number(value);
427
+ if (valueAsNumber < minRange || valueAsNumber > maxRange) {
428
+ throw new Error(
429
+ `Enum discriminator out of range. Expected a number between ${minRange} and ${maxRange}, got ${valueAsNumber}.`
430
+ );
431
+ }
432
+ return isNumericEnum ? valueAsNumber : enumValues[valueAsNumber];
433
+ });
410
434
  }
411
- function scalarEnumCoderHelper(constructor, prefix, description) {
435
+ function getScalarEnumCodec(constructor, config = {}) {
436
+ return codecsCore.combineCodec(getScalarEnumEncoder(constructor, config), getScalarEnumDecoder(constructor, config));
437
+ }
438
+ function getScalarEnumStats(constructor) {
412
439
  const enumKeys = Object.keys(constructor);
413
440
  const enumValues = Object.values(constructor);
414
441
  const isNumericEnum = enumValues.some((v) => typeof v === "number");
415
- const valueDescriptions = enumValues.filter((v) => typeof v === "string").join(", ");
416
442
  const minRange = 0;
417
443
  const maxRange = isNumericEnum ? enumValues.length / 2 - 1 : enumValues.length - 1;
418
444
  const stringValues = isNumericEnum ? [...enumKeys] : [.../* @__PURE__ */ new Set([...enumKeys, ...enumValues])];
419
445
  return {
420
- description: description ?? `enum(${valueDescriptions}; ${prefix.description})`,
421
446
  enumKeys,
422
447
  enumValues,
423
- fixedSize: prefix.fixedSize,
424
448
  isNumericEnum,
425
449
  maxRange,
426
- maxSize: prefix.maxSize,
427
450
  minRange,
428
451
  stringValues
429
452
  };
430
453
  }
431
- function getScalarEnumEncoder(constructor, config = {}) {
432
- const prefix = config.size ?? codecsNumbers.getU8Encoder();
433
- const { description, fixedSize, maxSize, minRange, maxRange, stringValues, enumKeys, enumValues } = scalarEnumCoderHelper(constructor, prefix, config.description);
434
- return {
435
- description,
436
- encode: (value) => {
437
- const isInvalidNumber = typeof value === "number" && (value < minRange || value > maxRange);
438
- const isInvalidString = typeof value === "string" && !stringValues.includes(value);
439
- if (isInvalidNumber || isInvalidString) {
440
- throw new Error(
441
- `Invalid scalar enum variant. Expected one of [${stringValues.join(", ")}] or a number between ${minRange} and ${maxRange}, got "${value}".`
442
- );
443
- }
444
- if (typeof value === "number")
445
- return prefix.encode(value);
446
- const valueIndex = enumValues.indexOf(value);
447
- if (valueIndex >= 0)
448
- return prefix.encode(valueIndex);
449
- return prefix.encode(enumKeys.indexOf(value));
450
- },
451
- fixedSize,
452
- maxSize
453
- };
454
- }
455
- function getScalarEnumDecoder(constructor, config = {}) {
456
- const prefix = config.size ?? codecsNumbers.getU8Decoder();
457
- const { description, fixedSize, maxSize, minRange, maxRange, isNumericEnum, enumValues } = scalarEnumCoderHelper(
458
- constructor,
459
- prefix,
460
- config.description
461
- );
462
- return {
463
- decode: (bytes, offset = 0) => {
464
- codecsCore.assertByteArrayIsNotEmptyForCodec("enum", bytes, offset);
465
- const [value, newOffset] = prefix.decode(bytes, offset);
466
- const valueAsNumber = Number(value);
467
- offset = newOffset;
468
- if (valueAsNumber < minRange || valueAsNumber > maxRange) {
469
- throw new Error(
470
- `Enum discriminator out of range. Expected a number between ${minRange} and ${maxRange}, got ${valueAsNumber}.`
471
- );
472
- }
473
- return [isNumericEnum ? valueAsNumber : enumValues[valueAsNumber], offset];
474
- },
475
- description,
476
- fixedSize,
477
- maxSize
478
- };
479
- }
480
- function getScalarEnumCodec(constructor, config = {}) {
481
- return codecsCore.combineCodec(getScalarEnumEncoder(constructor, config), getScalarEnumDecoder(constructor, config));
482
- }
483
- function setCodecHelper(item, size, description) {
484
- if (size === "remainder" && item.fixedSize === null) {
485
- throw new Error('Codecs of "remainder" size must have fixed-size items.');
486
- }
487
- return {
488
- description: description ?? `set(${item.description}; ${getArrayLikeCodecSizeDescription(size)})`,
489
- fixedSize: getArrayLikeCodecSizeFromChildren(size, [item.fixedSize]),
490
- maxSize: getArrayLikeCodecSizeFromChildren(size, [item.maxSize])
491
- };
492
- }
493
454
  function getSetEncoder(item, config = {}) {
494
- const size = config.size ?? codecsNumbers.getU32Encoder();
495
- return {
496
- ...setCodecHelper(item, size, config.description),
497
- encode: (set) => {
498
- if (typeof size === "number" && set.size !== size) {
499
- assertValidNumberOfItemsForCodec("set", size, set.size);
500
- }
501
- const itemBytes = Array.from(set, (value) => item.encode(value));
502
- return codecsCore.mergeBytes([getArrayLikeCodecSizePrefix(size, set.size), ...itemBytes]);
503
- }
504
- };
455
+ return codecsCore.mapEncoder(getArrayEncoder(item, config), (set) => [...set]);
505
456
  }
506
457
  function getSetDecoder(item, config = {}) {
507
- const size = config.size ?? codecsNumbers.getU32Decoder();
508
- return {
509
- ...setCodecHelper(item, size, config.description),
510
- decode: (bytes, offset = 0) => {
511
- const set = /* @__PURE__ */ new Set();
512
- if (typeof size === "object" && bytes.slice(offset).length === 0) {
513
- return [set, offset];
514
- }
515
- const [resolvedSize, newOffset] = decodeArrayLikeCodecSize(size, [item.fixedSize], bytes, offset);
516
- offset = newOffset;
517
- for (let i = 0; i < resolvedSize; i += 1) {
518
- const [value, newOffset2] = item.decode(bytes, offset);
519
- offset = newOffset2;
520
- set.add(value);
521
- }
522
- return [set, offset];
523
- }
524
- };
458
+ return codecsCore.mapDecoder(getArrayDecoder(item, config), (entries) => new Set(entries));
525
459
  }
526
460
  function getSetCodec(item, config = {}) {
527
461
  return codecsCore.combineCodec(getSetEncoder(item, config), getSetDecoder(item, config));
528
462
  }
529
- function structCodecHelper(fields, description) {
530
- const fieldDescriptions = fields.map(([name, codec]) => `${String(name)}: ${codec.description}`).join(", ");
531
- return {
532
- description: description ?? `struct(${fieldDescriptions})`,
533
- fixedSize: sumCodecSizes(fields.map(([, field]) => field.fixedSize)),
534
- maxSize: sumCodecSizes(fields.map(([, field]) => field.maxSize))
535
- };
536
- }
537
- function getStructEncoder(fields, config = {}) {
538
- return {
539
- ...structCodecHelper(fields, config.description),
540
- encode: (struct) => {
541
- const fieldBytes = fields.map(([key, codec]) => codec.encode(struct[key]));
542
- return codecsCore.mergeBytes(fieldBytes);
463
+ function getStructEncoder(fields) {
464
+ const fieldCodecs = fields.map(([, codec]) => codec);
465
+ const fixedSize = sumCodecSizes(fieldCodecs.map(getFixedSize));
466
+ const maxSize = sumCodecSizes(fieldCodecs.map(getMaxSize)) ?? void 0;
467
+ return codecsCore.createEncoder({
468
+ ...fixedSize === null ? {
469
+ getSizeFromValue: (value) => fields.map(([key, codec]) => codecsCore.getEncodedSize(value[key], codec)).reduce((all, one) => all + one, 0),
470
+ maxSize
471
+ } : { fixedSize },
472
+ write: (struct, bytes, offset) => {
473
+ fields.forEach(([key, codec]) => {
474
+ offset = codec.write(struct[key], bytes, offset);
475
+ });
476
+ return offset;
543
477
  }
544
- };
545
- }
546
- function getStructDecoder(fields, config = {}) {
547
- return {
548
- ...structCodecHelper(fields, config.description),
549
- decode: (bytes, offset = 0) => {
478
+ });
479
+ }
480
+ function getStructDecoder(fields) {
481
+ const fieldCodecs = fields.map(([, codec]) => codec);
482
+ const fixedSize = sumCodecSizes(fieldCodecs.map(getFixedSize));
483
+ const maxSize = sumCodecSizes(fieldCodecs.map(getMaxSize)) ?? void 0;
484
+ return codecsCore.createDecoder({
485
+ ...fixedSize === null ? { maxSize } : { fixedSize },
486
+ read: (bytes, offset) => {
550
487
  const struct = {};
551
488
  fields.forEach(([key, codec]) => {
552
- const [value, newOffset] = codec.decode(bytes, offset);
489
+ const [value, newOffset] = codec.read(bytes, offset);
553
490
  offset = newOffset;
554
491
  struct[key] = value;
555
492
  });
556
493
  return [struct, offset];
557
494
  }
558
- };
559
- }
560
- function getStructCodec(fields, config = {}) {
561
- return codecsCore.combineCodec(getStructEncoder(fields, config), getStructDecoder(fields, config));
562
- }
563
- function tupleCodecHelper(items, description) {
564
- const itemDescriptions = items.map((item) => item.description).join(", ");
565
- return {
566
- description: description ?? `tuple(${itemDescriptions})`,
567
- fixedSize: sumCodecSizes(items.map((item) => item.fixedSize)),
568
- maxSize: sumCodecSizes(items.map((item) => item.maxSize))
569
- };
570
- }
571
- function getTupleEncoder(items, config = {}) {
572
- return {
573
- ...tupleCodecHelper(items, config.description),
574
- encode: (value) => {
575
- assertValidNumberOfItemsForCodec("tuple", items.length, value.length);
576
- return codecsCore.mergeBytes(items.map((item, index) => item.encode(value[index])));
577
- }
578
- };
579
- }
580
- function getTupleDecoder(items, config = {}) {
581
- return {
582
- ...tupleCodecHelper(items, config.description),
583
- decode: (bytes, offset = 0) => {
584
- const values = [];
585
- items.forEach((codec) => {
586
- const [newValue, newOffset] = codec.decode(bytes, offset);
587
- values.push(newValue);
588
- offset = newOffset;
589
- });
590
- return [values, offset];
591
- }
592
- };
495
+ });
593
496
  }
594
- function getTupleCodec(items, config = {}) {
595
- return codecsCore.combineCodec(
596
- getTupleEncoder(items, config),
597
- getTupleDecoder(items, config)
598
- );
497
+ function getStructCodec(fields) {
498
+ return codecsCore.combineCodec(getStructEncoder(fields), getStructDecoder(fields));
599
499
  }
600
- function getUnitEncoder(config = {}) {
601
- return {
602
- description: config.description ?? "unit",
603
- encode: () => new Uint8Array(),
500
+ function getUnitEncoder() {
501
+ return codecsCore.createEncoder({
604
502
  fixedSize: 0,
605
- maxSize: 0
606
- };
503
+ write: (_value, _bytes, offset) => offset
504
+ });
607
505
  }
608
- function getUnitDecoder(config = {}) {
609
- return {
610
- decode: (_bytes, offset = 0) => [void 0, offset],
611
- description: config.description ?? "unit",
506
+ function getUnitDecoder() {
507
+ return codecsCore.createDecoder({
612
508
  fixedSize: 0,
613
- maxSize: 0
614
- };
509
+ read: (_bytes, offset) => [void 0, offset]
510
+ });
615
511
  }
616
- function getUnitCodec(config = {}) {
617
- return codecsCore.combineCodec(getUnitEncoder(config), getUnitDecoder(config));
512
+ function getUnitCodec() {
513
+ return codecsCore.combineCodec(getUnitEncoder(), getUnitDecoder());
618
514
  }
619
515
 
620
516
  exports.assertValidNumberOfItemsForCodec = assertValidNumberOfItemsForCodec;
621
- exports.decodeArrayLikeCodecSize = decodeArrayLikeCodecSize;
622
517
  exports.getArrayCodec = getArrayCodec;
623
518
  exports.getArrayDecoder = getArrayDecoder;
624
519
  exports.getArrayEncoder = getArrayEncoder;
625
- exports.getArrayLikeCodecSizeDescription = getArrayLikeCodecSizeDescription;
626
- exports.getArrayLikeCodecSizeFromChildren = getArrayLikeCodecSizeFromChildren;
627
- exports.getArrayLikeCodecSizePrefix = getArrayLikeCodecSizePrefix;
628
520
  exports.getBitArrayCodec = getBitArrayCodec;
629
521
  exports.getBitArrayDecoder = getBitArrayDecoder;
630
522
  exports.getBitArrayEncoder = getBitArrayEncoder;