@solana/codecs-data-structures 8.3.0 → 8.4.0-canary-20260918134912

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,6 +1,6 @@
1
- import { createEncoder, getEncodedSize, createDecoder, combineCodec, assertByteArrayHasEnoughBytesForCodec, transformEncoder, transformDecoder, containsBytes, isFixedSize, assertIsFixedSize, fixEncoderSize, fixDecoderSize } from '@solana/codecs-core';
1
+ import { createEncoder, getEncodedSize, createDecoder, containsBytes, combineCodec, assertByteArrayHasEnoughBytesForCodec, transformEncoder, transformDecoder, isFixedSize, assertIsFixedSize, fixEncoderSize, fixDecoderSize } 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__INVALID_CONSTANT, SOLANA_ERROR__CODECS__UNION_VARIANT_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_DISCRIMINATED_UNION_VARIANT, SOLANA_ERROR__CODECS__CANNOT_USE_LEXICAL_VALUES_AS_ENUM_DISCRIMINATORS, SOLANA_ERROR__CODECS__INVALID_ENUM_VARIANT, SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_LITERAL_UNION_VARIANT, SOLANA_ERROR__CODECS__LITERAL_UNION_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_PATTERN_MATCH_VALUE, SOLANA_ERROR__CODECS__INVALID_PATTERN_MATCH_BYTES } from '@solana/errors';
3
+ import { SolanaError, SOLANA_ERROR__CODECS__INVALID_NUMBER_OF_ITEMS, SOLANA_ERROR__CODECS__SENTINEL_MISSING_AT_END_OF_BYTES, SOLANA_ERROR__CODECS__SENTINEL_MUST_NOT_BE_EMPTY, SOLANA_ERROR__CODECS__INVALID_CONSTANT, SOLANA_ERROR__CODECS__UNION_VARIANT_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_DISCRIMINATED_UNION_VARIANT, SOLANA_ERROR__CODECS__CANNOT_USE_LEXICAL_VALUES_AS_ENUM_DISCRIMINATORS, SOLANA_ERROR__CODECS__INVALID_ENUM_VARIANT, SOLANA_ERROR__CODECS__ENUM_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_LITERAL_UNION_VARIANT, SOLANA_ERROR__CODECS__LITERAL_UNION_DISCRIMINATOR_OUT_OF_RANGE, SOLANA_ERROR__CODECS__INVALID_PATTERN_MATCH_VALUE, SOLANA_ERROR__CODECS__INVALID_PATTERN_MATCH_BYTES } from '@solana/errors';
4
4
 
5
5
  // src/array.ts
6
6
  function assertValidNumberOfItemsForCodec(codecDescription, expected, actual) {
@@ -31,13 +31,15 @@ function getMaxSize(codec) {
31
31
  // src/array.ts
32
32
  function getArrayEncoder(item, config = {}) {
33
33
  const size = config.size ?? getU32Encoder();
34
+ assertValidSize(size);
34
35
  const fixedSize = computeArrayLikeCodecSize(size, getFixedSize(item));
35
36
  const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
36
37
  return createEncoder({
37
38
  ...fixedSize !== null ? { fixedSize } : {
38
39
  getSizeFromValue: (array) => {
39
- const prefixSize = typeof size === "object" ? getEncodedSize(array.length, size) : 0;
40
- return prefixSize + [...array].reduce((all, value) => all + getEncodedSize(value, item), 0);
40
+ const prefixSize = isPrefixSize(size) ? getEncodedSize(array.length, size) : 0;
41
+ const suffixSize = isSentinelSize(size) && size.strategy !== "omitted" ? size.sentinel.length : 0;
42
+ return prefixSize + suffixSize + [...array].reduce((all, value) => all + getEncodedSize(value, item), 0);
41
43
  },
42
44
  maxSize
43
45
  },
@@ -45,18 +47,23 @@ function getArrayEncoder(item, config = {}) {
45
47
  if (typeof size === "number") {
46
48
  assertValidNumberOfItemsForCodec(config.description ?? "array", size, array.length);
47
49
  }
48
- if (typeof size === "object") {
50
+ if (isPrefixSize(size)) {
49
51
  offset = size.write(array.length, bytes, offset);
50
52
  }
51
53
  array.forEach((value) => {
52
54
  offset = item.write(value, bytes, offset);
53
55
  });
56
+ if (isSentinelSize(size) && size.strategy !== "omitted") {
57
+ bytes.set(size.sentinel, offset);
58
+ offset += size.sentinel.length;
59
+ }
54
60
  return offset;
55
61
  }
56
62
  });
57
63
  }
58
64
  function getArrayDecoder(item, config = {}) {
59
65
  const size = config.size ?? getU32Decoder();
66
+ assertValidSize(size);
60
67
  const itemSize = getFixedSize(item);
61
68
  const fixedSize = computeArrayLikeCodecSize(size, itemSize);
62
69
  const maxSize = computeArrayLikeCodecSize(size, getMaxSize(item)) ?? void 0;
@@ -64,7 +71,7 @@ function getArrayDecoder(item, config = {}) {
64
71
  ...fixedSize !== null ? { fixedSize } : { maxSize },
65
72
  read: (bytes, offset) => {
66
73
  const array = [];
67
- if (typeof size === "object" && !config.requireSizePrefix && offset >= bytes.length) {
74
+ if (isPrefixSize(size) && !config.requireSizePrefix && offset >= bytes.length) {
68
75
  return [array, offset];
69
76
  }
70
77
  if (size === "remainder") {
@@ -75,6 +82,29 @@ function getArrayDecoder(item, config = {}) {
75
82
  }
76
83
  return [array, offset];
77
84
  }
85
+ if (isSentinelSize(size)) {
86
+ const { sentinel, strategy = "required" } = size;
87
+ while (true) {
88
+ if (offset + sentinel.length > bytes.length) {
89
+ if (strategy === "required") {
90
+ throw new SolanaError(SOLANA_ERROR__CODECS__SENTINEL_MISSING_AT_END_OF_BYTES, {
91
+ codecDescription: config.description ?? "array",
92
+ hexSentinel: hexBytes(sentinel),
93
+ sentinel
94
+ });
95
+ }
96
+ break;
97
+ }
98
+ if (containsBytes(bytes, sentinel, offset)) {
99
+ offset += sentinel.length;
100
+ break;
101
+ }
102
+ const [value, newOffset2] = item.read(bytes, offset);
103
+ offset = newOffset2;
104
+ array.push(value);
105
+ }
106
+ return [array, offset];
107
+ }
78
108
  const [resolvedSize, newOffset] = typeof size === "number" ? [size, offset] : size.read(bytes, offset);
79
109
  offset = newOffset;
80
110
  for (let i = 0; i < resolvedSize; i += 1) {
@@ -94,6 +124,20 @@ function computeArrayLikeCodecSize(size, itemSize) {
94
124
  if (size === 0) return 0;
95
125
  return itemSize === null ? null : itemSize * size;
96
126
  }
127
+ function isPrefixSize(size) {
128
+ return typeof size === "object" && size !== null && !isSentinelSize(size);
129
+ }
130
+ function isSentinelSize(size) {
131
+ return typeof size === "object" && size !== null && "__kind" in size && size.__kind === "sentinel";
132
+ }
133
+ function assertValidSize(size) {
134
+ if (isSentinelSize(size) && size.sentinel.length === 0) {
135
+ throw new SolanaError(SOLANA_ERROR__CODECS__SENTINEL_MUST_NOT_BE_EMPTY);
136
+ }
137
+ }
138
+ function hexBytes(bytes) {
139
+ return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
140
+ }
97
141
  function getBitArrayEncoder(size, config = {}) {
98
142
  const parsedConfig = typeof config === "boolean" ? { backward: config } : config;
99
143
  const backward = parsedConfig.backward ?? false;