@solana/codecs-data-structures 2.0.0-experimental.3bc22e7 → 2.0.0-experimental.3fc662d

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__INVALID_NUMBER_OF_ITEMS, SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_DATA_ENUM_VARIANT, 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__INVALID_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,12 @@ 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
+ assertIsFixedSize(size);
170
154
  return mapEncoder(size, (value) => value ? 1 : 0);
171
155
  }
172
156
  function getBooleanDecoder(config = {}) {
173
157
  const size = config.size ?? getU8Decoder();
174
- assertIsFixedSize(size, "Codec [bool] requires a fixed size.");
158
+ assertIsFixedSize(size);
175
159
  return mapDecoder(size, (value) => Number(value) === 1);
176
160
  }
177
161
  function getBooleanCodec(config = {}) {
@@ -262,9 +246,11 @@ function getDataEnumDecoder(variants, config = {}) {
262
246
  offset = dOffset;
263
247
  const variantField = variants[Number(discriminator)] ?? null;
264
248
  if (!variantField) {
265
- throw new Error(
266
- `Enum discriminator out of range. Expected a number between 0 and ${variants.length - 1}, got ${discriminator}.`
267
- );
249
+ throw new SolanaError(SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, {
250
+ discriminator,
251
+ maxRange: variants.length - 1,
252
+ minRange: 0
253
+ });
268
254
  }
269
255
  const [variant, vOffset] = variantField[1].read(bytes, offset);
270
256
  offset = vOffset;
@@ -273,7 +259,10 @@ function getDataEnumDecoder(variants, config = {}) {
273
259
  });
274
260
  }
275
261
  function getDataEnumCodec(variants, config = {}) {
276
- return combineCodec(getDataEnumEncoder(variants, config), getDataEnumDecoder(variants, config));
262
+ return combineCodec(
263
+ getDataEnumEncoder(variants, config),
264
+ getDataEnumDecoder(variants, config)
265
+ );
277
266
  }
278
267
  function getDataEnumFixedSize(variants, prefix) {
279
268
  if (variants.length === 0)
@@ -295,9 +284,10 @@ function getDataEnumMaxSize(variants, prefix) {
295
284
  function getVariantDiscriminator(variants, variant) {
296
285
  const discriminator = variants.findIndex(([key]) => variant.__kind === key);
297
286
  if (discriminator < 0) {
298
- throw new Error(
299
- `Invalid data enum variant. Expected one of [${variants.map(([key]) => key).join(", ")}], got "${variant.__kind}".`
300
- );
287
+ throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_DATA_ENUM_VARIANT, {
288
+ value: variant.__kind,
289
+ variants: variants.map(([key]) => key)
290
+ });
301
291
  }
302
292
  return discriminator;
303
293
  }
@@ -362,8 +352,8 @@ function getNullableEncoder(item, config = {}) {
362
352
  const fixed = config.fixed ?? false;
363
353
  const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
364
354
  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.");
355
+ assertIsFixedSize(item);
356
+ assertIsFixedSize(prefix);
367
357
  const fixedSize = prefix.fixedSize + item.fixedSize;
368
358
  return createEncoder({
369
359
  fixedSize,
@@ -394,8 +384,8 @@ function getNullableDecoder(item, config = {}) {
394
384
  let fixedSize = null;
395
385
  const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
396
386
  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.");
387
+ assertIsFixedSize(item);
388
+ assertIsFixedSize(prefix);
399
389
  fixedSize = prefix.fixedSize + item.fixedSize;
400
390
  }
401
391
  return createDecoder({
@@ -419,14 +409,17 @@ function getNullableCodec(item, config = {}) {
419
409
  }
420
410
  function getScalarEnumEncoder(constructor, config = {}) {
421
411
  const prefix = config.size ?? getU8Encoder();
422
- const { minRange, maxRange, stringValues, enumKeys, enumValues } = getScalarEnumStats(constructor);
412
+ const { minRange, maxRange, allStringInputs, enumKeys, enumValues } = getScalarEnumStats(constructor);
423
413
  return mapEncoder(prefix, (value) => {
424
414
  const isInvalidNumber = typeof value === "number" && (value < minRange || value > maxRange);
425
- const isInvalidString = typeof value === "string" && !stringValues.includes(value);
415
+ const isInvalidString = typeof value === "string" && !allStringInputs.includes(value);
426
416
  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
- );
417
+ throw new SolanaError(SOLANA_ERROR__CODECS__INVALID_SCALAR_ENUM_VARIANT, {
418
+ maxRange,
419
+ minRange,
420
+ value,
421
+ variants: allStringInputs
422
+ });
430
423
  }
431
424
  if (typeof value === "number")
432
425
  return value;
@@ -438,34 +431,40 @@ function getScalarEnumEncoder(constructor, config = {}) {
438
431
  }
439
432
  function getScalarEnumDecoder(constructor, config = {}) {
440
433
  const prefix = config.size ?? getU8Decoder();
441
- const { minRange, maxRange, isNumericEnum, enumValues } = getScalarEnumStats(constructor);
434
+ const { minRange, maxRange, enumKeys } = getScalarEnumStats(constructor);
442
435
  return mapDecoder(prefix, (value) => {
443
436
  const valueAsNumber = Number(value);
444
437
  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
- );
438
+ throw new SolanaError(SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, {
439
+ discriminator: valueAsNumber,
440
+ maxRange,
441
+ minRange
442
+ });
448
443
  }
449
- return isNumericEnum ? valueAsNumber : enumValues[valueAsNumber];
444
+ return constructor[enumKeys[valueAsNumber]];
450
445
  });
451
446
  }
452
447
  function getScalarEnumCodec(constructor, config = {}) {
453
448
  return combineCodec(getScalarEnumEncoder(constructor, config), getScalarEnumDecoder(constructor, config));
454
449
  }
455
450
  function getScalarEnumStats(constructor) {
456
- const enumKeys = Object.keys(constructor);
457
- const enumValues = Object.values(constructor);
458
- const isNumericEnum = enumValues.some((v) => typeof v === "number");
451
+ const numericValues = Object.values(constructor).filter((v) => typeof v === "number");
452
+ const deduplicatedConstructor = Object.fromEntries(
453
+ Object.entries(constructor).slice(numericValues.length)
454
+ );
455
+ const enumKeys = Object.keys(deduplicatedConstructor);
456
+ const enumValues = Object.values(deduplicatedConstructor);
459
457
  const minRange = 0;
460
- const maxRange = isNumericEnum ? enumValues.length / 2 - 1 : enumValues.length - 1;
461
- const stringValues = isNumericEnum ? [...enumKeys] : [.../* @__PURE__ */ new Set([...enumKeys, ...enumValues])];
458
+ const maxRange = enumValues.length - 1;
459
+ const allStringInputs = [
460
+ .../* @__PURE__ */ new Set([...enumKeys, ...enumValues.filter((v) => typeof v === "string")])
461
+ ];
462
462
  return {
463
+ allStringInputs,
463
464
  enumKeys,
464
465
  enumValues,
465
- isNumericEnum,
466
466
  maxRange,
467
- minRange,
468
- stringValues
467
+ minRange
469
468
  };
470
469
  }
471
470
  function getSetEncoder(item, config = {}) {
@@ -512,7 +511,10 @@ function getStructDecoder(fields) {
512
511
  });
513
512
  }
514
513
  function getStructCodec(fields) {
515
- return combineCodec(getStructEncoder(fields), getStructDecoder(fields));
514
+ return combineCodec(
515
+ getStructEncoder(fields),
516
+ getStructDecoder(fields)
517
+ );
516
518
  }
517
519
  function getUnitEncoder() {
518
520
  return createEncoder({