@solana/codecs-data-structures 2.0.0-experimental.7ed772d → 2.0.0-experimental.803b2d8

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.
@@ -1,12 +1,15 @@
1
- import { assertIsFixedSize, createEncoder, getEncodedSize, createDecoder, combineCodec, assertByteArrayHasEnoughBytesForCodec, mapEncoder, mapDecoder, fixEncoder, fixDecoder, assertByteArrayIsNotEmptyForCodec, isFixedSize } from '@solana/codecs-core';
1
+ import { createEncoder, getEncodedSize, createDecoder, combineCodec, assertByteArrayHasEnoughBytesForCodec, assertIsFixedSize, mapEncoder, mapDecoder, fixEncoder, fixDecoder, assertByteArrayIsNotEmptyForCodec, isFixedSize } from '@solana/codecs-core';
2
2
  import { getU32Encoder, getU32Decoder, getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
3
+ import { SolanaError, SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_ITEMS, isSolanaError, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH, SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE, SOLANA_ERROR__CODECS_ENUM_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT, SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC, SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX, SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT } from '@solana/errors';
3
4
 
4
5
  // src/array.ts
5
-
6
- // src/assertions.ts
7
6
  function assertValidNumberOfItemsForCodec(codecDescription, expected, actual) {
8
7
  if (expected !== actual) {
9
- throw new Error(`Expected [${codecDescription}] to have ${expected} items, got ${actual}.`);
8
+ throw new SolanaError(SOLANA_ERROR__CODECS_WRONG_NUMBER_OF_ITEMS, {
9
+ actual,
10
+ codecDescription,
11
+ expected
12
+ });
10
13
  }
11
14
  }
12
15
  function maxCodecSizes(sizes) {
@@ -28,9 +31,6 @@ function getMaxSize(codec) {
28
31
  // src/array.ts
29
32
  function getArrayEncoder(item, config = {}) {
30
33
  const size = config.size ?? getU32Encoder();
31
- if (size === "remainder") {
32
- assertIsFixedSize(item, 'Codecs of "remainder" size must have fixed-size items.');
33
- }
34
34
  const fixedSize = computeArrayLikeCodecSize(size, getFixedSize(item));
35
35
  const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
36
36
  return createEncoder({
@@ -57,9 +57,6 @@ function getArrayEncoder(item, config = {}) {
57
57
  }
58
58
  function getArrayDecoder(item, config = {}) {
59
59
  const size = config.size ?? getU32Decoder();
60
- if (size === "remainder") {
61
- assertIsFixedSize(item, 'Codecs of "remainder" size must have fixed-size items.');
62
- }
63
60
  const itemSize = getFixedSize(item);
64
61
  const fixedSize = computeArrayLikeCodecSize(size, itemSize);
65
62
  const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
@@ -70,7 +67,15 @@ function getArrayDecoder(item, config = {}) {
70
67
  if (typeof size === "object" && bytes.slice(offset).length === 0) {
71
68
  return [array, offset];
72
69
  }
73
- const [resolvedSize, newOffset] = readArrayLikeCodecSize(size, itemSize, bytes, offset);
70
+ if (size === "remainder") {
71
+ while (offset < bytes.length) {
72
+ const [value, newOffset2] = item.read(bytes, offset);
73
+ offset = newOffset2;
74
+ array.push(value);
75
+ }
76
+ return [array, offset];
77
+ }
78
+ const [resolvedSize, newOffset] = typeof size === "number" ? [size, offset] : size.read(bytes, offset);
74
79
  offset = newOffset;
75
80
  for (let i = 0; i < resolvedSize; i += 1) {
76
81
  const [value, newOffset2] = item.read(bytes, offset);
@@ -84,27 +89,6 @@ function getArrayDecoder(item, config = {}) {
84
89
  function getArrayCodec(item, config = {}) {
85
90
  return combineCodec(getArrayEncoder(item, config), getArrayDecoder(item, config));
86
91
  }
87
- function readArrayLikeCodecSize(size, itemSize, bytes, offset) {
88
- if (typeof size === "number") {
89
- return [size, offset];
90
- }
91
- if (typeof size === "object") {
92
- return size.read(bytes, offset);
93
- }
94
- if (size === "remainder") {
95
- if (itemSize === null) {
96
- throw new Error('Codecs of "remainder" size must have fixed-size items.');
97
- }
98
- const remainder = Math.max(0, bytes.length - offset);
99
- if (remainder % itemSize !== 0) {
100
- throw new Error(
101
- `The remainder of the byte array (${remainder} bytes) cannot be split into chunks of ${itemSize} bytes. Codecs of "remainder" size must have a remainder that is a multiple of its item size. In other words, ${remainder} modulo ${itemSize} should be equal to zero.`
102
- );
103
- }
104
- return [remainder / itemSize, offset];
105
- }
106
- throw new Error(`Unrecognized array-like codec size: ${JSON.stringify(size)}`);
107
- }
108
92
  function computeArrayLikeCodecSize(size, itemSize) {
109
93
  if (typeof size !== "number")
110
94
  return null;
@@ -166,12 +150,32 @@ function getBitArrayCodec(size, config = {}) {
166
150
  }
167
151
  function getBooleanEncoder(config = {}) {
168
152
  const size = config.size ?? getU8Encoder();
169
- assertIsFixedSize(size, "Codec [bool] requires a fixed size.");
153
+ try {
154
+ assertIsFixedSize(size);
155
+ } catch (e) {
156
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
157
+ throw new SolanaError(SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE, {
158
+ codecDescription: "bool"
159
+ });
160
+ } else {
161
+ throw e;
162
+ }
163
+ }
170
164
  return mapEncoder(size, (value) => value ? 1 : 0);
171
165
  }
172
166
  function getBooleanDecoder(config = {}) {
173
167
  const size = config.size ?? getU8Decoder();
174
- assertIsFixedSize(size, "Codec [bool] requires a fixed size.");
168
+ try {
169
+ assertIsFixedSize(size);
170
+ } catch (e) {
171
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
172
+ throw new SolanaError(SOLANA_ERROR__CODECS_CODEC_REQUIRES_FIXED_SIZE, {
173
+ codecDescription: "bool"
174
+ });
175
+ } else {
176
+ throw e;
177
+ }
178
+ }
175
179
  return mapDecoder(size, (value) => Number(value) === 1);
176
180
  }
177
181
  function getBooleanCodec(config = {}) {
@@ -262,9 +266,11 @@ function getDataEnumDecoder(variants, config = {}) {
262
266
  offset = dOffset;
263
267
  const variantField = variants[Number(discriminator)] ?? null;
264
268
  if (!variantField) {
265
- throw new Error(
266
- `Enum discriminator out of range. Expected a number between 0 and ${variants.length - 1}, got ${discriminator}.`
267
- );
269
+ throw new SolanaError(SOLANA_ERROR__CODECS_ENUM_DISCRIMINATOR_OUT_OF_RANGE, {
270
+ discriminator,
271
+ maxRange: variants.length - 1,
272
+ minRange: 0
273
+ });
268
274
  }
269
275
  const [variant, vOffset] = variantField[1].read(bytes, offset);
270
276
  offset = vOffset;
@@ -273,7 +279,10 @@ function getDataEnumDecoder(variants, config = {}) {
273
279
  });
274
280
  }
275
281
  function getDataEnumCodec(variants, config = {}) {
276
- return combineCodec(getDataEnumEncoder(variants, config), getDataEnumDecoder(variants, config));
282
+ return combineCodec(
283
+ getDataEnumEncoder(variants, config),
284
+ getDataEnumDecoder(variants, config)
285
+ );
277
286
  }
278
287
  function getDataEnumFixedSize(variants, prefix) {
279
288
  if (variants.length === 0)
@@ -295,9 +304,10 @@ function getDataEnumMaxSize(variants, prefix) {
295
304
  function getVariantDiscriminator(variants, variant) {
296
305
  const discriminator = variants.findIndex(([key]) => variant.__kind === key);
297
306
  if (discriminator < 0) {
298
- throw new Error(
299
- `Invalid data enum variant. Expected one of [${variants.map(([key]) => key).join(", ")}], got "${variant.__kind}".`
300
- );
307
+ throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_DATA_ENUM_VARIANT, {
308
+ value: variant.__kind,
309
+ variants: variants.map(([key]) => key)
310
+ });
301
311
  }
302
312
  return discriminator;
303
313
  }
@@ -362,8 +372,24 @@ function getNullableEncoder(item, config = {}) {
362
372
  const fixed = config.fixed ?? false;
363
373
  const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
364
374
  if (fixed || isZeroSizeItem) {
365
- assertIsFixedSize(item, "Fixed nullables can only be used with fixed-size codecs.");
366
- assertIsFixedSize(prefix, "Fixed nullables can only be used with fixed-size prefix.");
375
+ try {
376
+ assertIsFixedSize(item);
377
+ } catch (e) {
378
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
379
+ throw new SolanaError(SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC);
380
+ } else {
381
+ throw e;
382
+ }
383
+ }
384
+ try {
385
+ assertIsFixedSize(prefix);
386
+ } catch (e) {
387
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
388
+ throw new SolanaError(SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX);
389
+ } else {
390
+ throw e;
391
+ }
392
+ }
367
393
  const fixedSize = prefix.fixedSize + item.fixedSize;
368
394
  return createEncoder({
369
395
  fixedSize,
@@ -394,8 +420,24 @@ function getNullableDecoder(item, config = {}) {
394
420
  let fixedSize = null;
395
421
  const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
396
422
  if (fixed || isZeroSizeItem) {
397
- assertIsFixedSize(item, "Fixed nullables can only be used with fixed-size codecs.");
398
- assertIsFixedSize(prefix, "Fixed nullables can only be used with fixed-size prefix.");
423
+ try {
424
+ assertIsFixedSize(item);
425
+ } catch (e) {
426
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
427
+ throw new SolanaError(SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_CODEC);
428
+ } else {
429
+ throw e;
430
+ }
431
+ }
432
+ try {
433
+ assertIsFixedSize(prefix);
434
+ } catch (e) {
435
+ if (isSolanaError(e, SOLANA_ERROR__CODECS_EXPECTED_FIXED_LENGTH_GOT_VARIABLE_LENGTH)) {
436
+ throw new SolanaError(SOLANA_ERROR__CODECS_FIXED_NULLABLE_WITH_VARIABLE_SIZE_PREFIX);
437
+ } else {
438
+ throw e;
439
+ }
440
+ }
399
441
  fixedSize = prefix.fixedSize + item.fixedSize;
400
442
  }
401
443
  return createDecoder({
@@ -419,14 +461,17 @@ function getNullableCodec(item, config = {}) {
419
461
  }
420
462
  function getScalarEnumEncoder(constructor, config = {}) {
421
463
  const prefix = config.size ?? getU8Encoder();
422
- const { minRange, maxRange, stringValues, enumKeys, enumValues } = getScalarEnumStats(constructor);
464
+ const { minRange, maxRange, allStringInputs, enumKeys, enumValues } = getScalarEnumStats(constructor);
423
465
  return mapEncoder(prefix, (value) => {
424
466
  const isInvalidNumber = typeof value === "number" && (value < minRange || value > maxRange);
425
- const isInvalidString = typeof value === "string" && !stringValues.includes(value);
467
+ const isInvalidString = typeof value === "string" && !allStringInputs.includes(value);
426
468
  if (isInvalidNumber || isInvalidString) {
427
- throw new Error(
428
- `Invalid scalar enum variant. Expected one of [${stringValues.join(", ")}] or a number between ${minRange} and ${maxRange}, got "${value}".`
429
- );
469
+ throw new SolanaError(SOLANA_ERROR__CODECS_INVALID_SCALAR_ENUM_VARIANT, {
470
+ maxRange,
471
+ minRange,
472
+ value,
473
+ variants: allStringInputs
474
+ });
430
475
  }
431
476
  if (typeof value === "number")
432
477
  return value;
@@ -438,34 +483,40 @@ function getScalarEnumEncoder(constructor, config = {}) {
438
483
  }
439
484
  function getScalarEnumDecoder(constructor, config = {}) {
440
485
  const prefix = config.size ?? getU8Decoder();
441
- const { minRange, maxRange, isNumericEnum, enumValues } = getScalarEnumStats(constructor);
486
+ const { minRange, maxRange, enumKeys } = getScalarEnumStats(constructor);
442
487
  return mapDecoder(prefix, (value) => {
443
488
  const valueAsNumber = Number(value);
444
489
  if (valueAsNumber < minRange || valueAsNumber > maxRange) {
445
- throw new Error(
446
- `Enum discriminator out of range. Expected a number between ${minRange} and ${maxRange}, got ${valueAsNumber}.`
447
- );
490
+ throw new SolanaError(SOLANA_ERROR__CODECS_ENUM_DISCRIMINATOR_OUT_OF_RANGE, {
491
+ discriminator: valueAsNumber,
492
+ maxRange,
493
+ minRange
494
+ });
448
495
  }
449
- return isNumericEnum ? valueAsNumber : enumValues[valueAsNumber];
496
+ return constructor[enumKeys[valueAsNumber]];
450
497
  });
451
498
  }
452
499
  function getScalarEnumCodec(constructor, config = {}) {
453
500
  return combineCodec(getScalarEnumEncoder(constructor, config), getScalarEnumDecoder(constructor, config));
454
501
  }
455
502
  function getScalarEnumStats(constructor) {
456
- const enumKeys = Object.keys(constructor);
457
- const enumValues = Object.values(constructor);
458
- const isNumericEnum = enumValues.some((v) => typeof v === "number");
503
+ const numericValues = Object.values(constructor).filter((v) => typeof v === "number");
504
+ const deduplicatedConstructor = Object.fromEntries(
505
+ Object.entries(constructor).slice(numericValues.length)
506
+ );
507
+ const enumKeys = Object.keys(deduplicatedConstructor);
508
+ const enumValues = Object.values(deduplicatedConstructor);
459
509
  const minRange = 0;
460
- const maxRange = isNumericEnum ? enumValues.length / 2 - 1 : enumValues.length - 1;
461
- const stringValues = isNumericEnum ? [...enumKeys] : [.../* @__PURE__ */ new Set([...enumKeys, ...enumValues])];
510
+ const maxRange = enumValues.length - 1;
511
+ const allStringInputs = [
512
+ .../* @__PURE__ */ new Set([...enumKeys, ...enumValues.filter((v) => typeof v === "string")])
513
+ ];
462
514
  return {
515
+ allStringInputs,
463
516
  enumKeys,
464
517
  enumValues,
465
- isNumericEnum,
466
518
  maxRange,
467
- minRange,
468
- stringValues
519
+ minRange
469
520
  };
470
521
  }
471
522
  function getSetEncoder(item, config = {}) {
@@ -512,7 +563,10 @@ function getStructDecoder(fields) {
512
563
  });
513
564
  }
514
565
  function getStructCodec(fields) {
515
- return combineCodec(getStructEncoder(fields), getStructDecoder(fields));
566
+ return combineCodec(
567
+ getStructEncoder(fields),
568
+ getStructDecoder(fields)
569
+ );
516
570
  }
517
571
  function getUnitEncoder() {
518
572
  return createEncoder({