@solana/options 2.0.0-experimental.c8d8b83 → 2.0.0-experimental.c9bd7fa

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.
@@ -21,58 +21,54 @@ this.globalThis.solanaWeb3 = (function (exports) {
21
21
  throw new Error(`Codec [${codecDescription}] expected ${expected} bytes, got ${bytesLength}.`);
22
22
  }
23
23
  }
24
- function assertFixedSizeCodec(data, message) {
25
- if (data.fixedSize === null) {
26
- throw new Error(message ?? "Expected a fixed-size codec, got a variable-size one.");
27
- }
24
+ function getEncodedSize(value, encoder) {
25
+ return "fixedSize" in encoder ? encoder.fixedSize : encoder.getSizeFromValue(value);
26
+ }
27
+ function createEncoder(encoder) {
28
+ return Object.freeze({
29
+ ...encoder,
30
+ encode: (value) => {
31
+ const bytes = new Uint8Array(getEncodedSize(value, encoder));
32
+ encoder.write(value, bytes, 0);
33
+ return bytes;
34
+ }
35
+ });
28
36
  }
29
- var mergeBytes = (byteArrays) => {
30
- const nonEmptyByteArrays = byteArrays.filter((arr) => arr.length);
31
- if (nonEmptyByteArrays.length === 0) {
32
- return byteArrays.length ? byteArrays[0] : new Uint8Array();
37
+ function createDecoder(decoder) {
38
+ return Object.freeze({
39
+ ...decoder,
40
+ decode: (bytes, offset = 0) => decoder.read(bytes, offset)[0]
41
+ });
42
+ }
43
+ function isFixedSize(codec) {
44
+ return "fixedSize" in codec && typeof codec.fixedSize === "number";
45
+ }
46
+ function assertIsFixedSize(codec, message) {
47
+ if (!isFixedSize(codec)) {
48
+ throw new Error(message != null ? message : "Expected a fixed-size codec, got a variable-size one.");
33
49
  }
34
- if (nonEmptyByteArrays.length === 1) {
35
- return nonEmptyByteArrays[0];
50
+ }
51
+ function combineCodec(encoder, decoder) {
52
+ if (isFixedSize(encoder) !== isFixedSize(decoder)) {
53
+ throw new Error(`Encoder and decoder must either both be fixed-size or variable-size.`);
36
54
  }
37
- const totalLength = nonEmptyByteArrays.reduce((total, arr) => total + arr.length, 0);
38
- const result = new Uint8Array(totalLength);
39
- let offset = 0;
40
- nonEmptyByteArrays.forEach((arr) => {
41
- result.set(arr, offset);
42
- offset += arr.length;
43
- });
44
- return result;
45
- };
46
- var padBytes = (bytes, length) => {
47
- if (bytes.length >= length)
48
- return bytes;
49
- const paddedBytes = new Uint8Array(length).fill(0);
50
- paddedBytes.set(bytes);
51
- return paddedBytes;
52
- };
53
- var fixBytes = (bytes, length) => padBytes(bytes.length <= length ? bytes : bytes.slice(0, length), length);
54
- function combineCodec(encoder, decoder, description) {
55
- if (encoder.fixedSize !== decoder.fixedSize) {
55
+ if (isFixedSize(encoder) && isFixedSize(decoder) && encoder.fixedSize !== decoder.fixedSize) {
56
56
  throw new Error(
57
57
  `Encoder and decoder must have the same fixed size, got [${encoder.fixedSize}] and [${decoder.fixedSize}].`
58
58
  );
59
59
  }
60
- if (encoder.maxSize !== decoder.maxSize) {
60
+ if (!isFixedSize(encoder) && !isFixedSize(decoder) && encoder.maxSize !== decoder.maxSize) {
61
61
  throw new Error(
62
62
  `Encoder and decoder must have the same max size, got [${encoder.maxSize}] and [${decoder.maxSize}].`
63
63
  );
64
64
  }
65
- if (description === void 0 && encoder.description !== decoder.description) {
66
- throw new Error(
67
- `Encoder and decoder must have the same description, got [${encoder.description}] and [${decoder.description}]. Pass a custom description as a third argument if you want to override the description and bypass this error.`
68
- );
69
- }
70
65
  return {
66
+ ...decoder,
67
+ ...encoder,
71
68
  decode: decoder.decode,
72
- description: description ?? encoder.description,
73
69
  encode: encoder.encode,
74
- fixedSize: encoder.fixedSize,
75
- maxSize: encoder.maxSize
70
+ read: decoder.read,
71
+ write: encoder.write
76
72
  };
77
73
  }
78
74
 
@@ -84,66 +80,48 @@ this.globalThis.solanaWeb3 = (function (exports) {
84
80
  );
85
81
  }
86
82
  }
87
- function sharedNumberFactory(input) {
88
- let littleEndian;
89
- let defaultDescription = input.name;
90
- if (input.size > 1) {
91
- littleEndian = !("endian" in input.options) || input.options.endian === 0;
92
- defaultDescription += littleEndian ? "(le)" : "(be)";
93
- }
94
- return {
95
- description: input.options.description ?? defaultDescription,
96
- fixedSize: input.size,
97
- littleEndian,
98
- maxSize: input.size
99
- };
83
+ function isLittleEndian(config) {
84
+ return (config == null ? void 0 : config.endian) === 1 ? false : true;
100
85
  }
101
86
  function numberEncoderFactory(input) {
102
- const codecData = sharedNumberFactory(input);
103
- return {
104
- description: codecData.description,
105
- encode(value) {
87
+ return createEncoder({
88
+ fixedSize: input.size,
89
+ write(value, bytes, offset) {
106
90
  if (input.range) {
107
91
  assertNumberIsBetweenForCodec(input.name, input.range[0], input.range[1], value);
108
92
  }
109
93
  const arrayBuffer = new ArrayBuffer(input.size);
110
- input.set(new DataView(arrayBuffer), value, codecData.littleEndian);
111
- return new Uint8Array(arrayBuffer);
112
- },
113
- fixedSize: codecData.fixedSize,
114
- maxSize: codecData.maxSize
115
- };
94
+ input.set(new DataView(arrayBuffer), value, isLittleEndian(input.config));
95
+ bytes.set(new Uint8Array(arrayBuffer), offset);
96
+ return offset + input.size;
97
+ }
98
+ });
116
99
  }
117
100
  function numberDecoderFactory(input) {
118
- const codecData = sharedNumberFactory(input);
119
- return {
120
- decode(bytes, offset = 0) {
121
- assertByteArrayIsNotEmptyForCodec(codecData.description, bytes, offset);
122
- assertByteArrayHasEnoughBytesForCodec(codecData.description, input.size, bytes, offset);
101
+ return createDecoder({
102
+ fixedSize: input.size,
103
+ read(bytes, offset = 0) {
104
+ assertByteArrayIsNotEmptyForCodec(input.name, bytes, offset);
105
+ assertByteArrayHasEnoughBytesForCodec(input.name, input.size, bytes, offset);
123
106
  const view = new DataView(toArrayBuffer(bytes, offset, input.size));
124
- return [input.get(view, codecData.littleEndian), offset + input.size];
125
- },
126
- description: codecData.description,
127
- fixedSize: codecData.fixedSize,
128
- maxSize: codecData.maxSize
129
- };
107
+ return [input.get(view, isLittleEndian(input.config)), offset + input.size];
108
+ }
109
+ });
130
110
  }
131
111
  function toArrayBuffer(bytes, offset, length) {
132
- const bytesOffset = bytes.byteOffset + (offset ?? 0);
133
- const bytesLength = length ?? bytes.byteLength;
112
+ const bytesOffset = bytes.byteOffset + (offset != null ? offset : 0);
113
+ const bytesLength = length != null ? length : bytes.byteLength;
134
114
  return bytes.buffer.slice(bytesOffset, bytesOffset + bytesLength);
135
115
  }
136
- var getU8Encoder = (options = {}) => numberEncoderFactory({
116
+ var getU8Encoder = () => numberEncoderFactory({
137
117
  name: "u8",
138
- options,
139
118
  range: [0, Number("0xff")],
140
119
  set: (view, value) => view.setUint8(0, value),
141
120
  size: 1
142
121
  });
143
- var getU8Decoder = (options = {}) => numberDecoderFactory({
122
+ var getU8Decoder = () => numberDecoderFactory({
144
123
  get: (view) => view.getUint8(0),
145
124
  name: "u8",
146
- options,
147
125
  size: 1
148
126
  });
149
127
 
@@ -156,61 +134,78 @@ this.globalThis.solanaWeb3 = (function (exports) {
156
134
  var wrapNullable = (nullable) => nullable !== null ? some(nullable) : none();
157
135
 
158
136
  // src/option-codec.ts
159
- function sumCodecSizes(sizes) {
160
- return sizes.reduce((all, size) => all === null || size === null ? null : all + size, 0);
161
- }
162
- function optionCodecHelper(item, prefix, fixed, description) {
163
- let descriptionSuffix = `; ${prefix.description}`;
164
- let fixedSize = item.fixedSize === 0 ? prefix.fixedSize : null;
165
- if (fixed) {
166
- assertFixedSizeCodec(item, "Fixed options can only be used with fixed-size codecs.");
167
- assertFixedSizeCodec(prefix, "Fixed options can only be used with fixed-size prefix.");
168
- descriptionSuffix += "; fixed";
169
- fixedSize = prefix.fixedSize + item.fixedSize;
137
+ function getOptionEncoder(item, config = {}) {
138
+ var _a, _b, _c;
139
+ const prefix = (_a = config.prefix) != null ? _a : getU8Encoder();
140
+ const fixed = (_b = config.fixed) != null ? _b : false;
141
+ const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
142
+ if (fixed || isZeroSizeItem) {
143
+ assertIsFixedSize(item, "Fixed options can only be used with fixed-size codecs.");
144
+ assertIsFixedSize(prefix, "Fixed options can only be used with fixed-size prefix.");
145
+ const fixedSize = prefix.fixedSize + item.fixedSize;
146
+ return createEncoder({
147
+ fixedSize,
148
+ write: (optionOrNullable, bytes, offset) => {
149
+ const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
150
+ const prefixOffset = prefix.write(Number(isSome(option)), bytes, offset);
151
+ if (isSome(option)) {
152
+ item.write(option.value, bytes, prefixOffset);
153
+ }
154
+ return offset + fixedSize;
155
+ }
156
+ });
170
157
  }
171
- return {
172
- description: description ?? `option(${item.description + descriptionSuffix})`,
173
- fixedSize,
174
- maxSize: sumCodecSizes([prefix.maxSize, item.maxSize])
175
- };
176
- }
177
- function getOptionEncoder(item, options = {}) {
178
- const prefix = options.prefix ?? getU8Encoder();
179
- const fixed = options.fixed ?? false;
180
- return {
181
- ...optionCodecHelper(item, prefix, fixed, options.description),
182
- encode: (optionOrNullable) => {
158
+ return createEncoder({
159
+ getSizeFromValue: (optionOrNullable) => {
160
+ const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
161
+ return getEncodedSize(Number(isSome(option)), prefix) + (isSome(option) ? getEncodedSize(option.value, item) : 0);
162
+ },
163
+ maxSize: (_c = sumCodecSizes([prefix, item].map(getMaxSize))) != null ? _c : void 0,
164
+ write: (optionOrNullable, bytes, offset) => {
183
165
  const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
184
- const prefixByte = prefix.encode(Number(isSome(option)));
185
- let itemBytes = isSome(option) ? item.encode(option.value) : new Uint8Array();
186
- itemBytes = fixed ? fixBytes(itemBytes, item.fixedSize) : itemBytes;
187
- return mergeBytes([prefixByte, itemBytes]);
166
+ offset = prefix.write(Number(isSome(option)), bytes, offset);
167
+ if (isSome(option)) {
168
+ offset = item.write(option.value, bytes, offset);
169
+ }
170
+ return offset;
188
171
  }
189
- };
172
+ });
190
173
  }
191
- function getOptionDecoder(item, options = {}) {
192
- const prefix = options.prefix ?? getU8Decoder();
193
- const fixed = options.fixed ?? false;
194
- return {
195
- ...optionCodecHelper(item, prefix, fixed, options.description),
196
- decode: (bytes, offset = 0) => {
174
+ function getOptionDecoder(item, config = {}) {
175
+ var _a, _b, _c;
176
+ const prefix = (_a = config.prefix) != null ? _a : getU8Decoder();
177
+ const fixed = (_b = config.fixed) != null ? _b : false;
178
+ let fixedSize = null;
179
+ const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
180
+ if (fixed || isZeroSizeItem) {
181
+ assertIsFixedSize(item, "Fixed options can only be used with fixed-size codecs.");
182
+ assertIsFixedSize(prefix, "Fixed options can only be used with fixed-size prefix.");
183
+ fixedSize = prefix.fixedSize + item.fixedSize;
184
+ }
185
+ return createDecoder({
186
+ ...fixedSize === null ? { maxSize: (_c = sumCodecSizes([prefix, item].map(getMaxSize))) != null ? _c : void 0 } : { fixedSize },
187
+ read: (bytes, offset) => {
197
188
  if (bytes.length - offset <= 0) {
198
189
  return [none(), offset];
199
190
  }
200
- const fixedOffset = offset + (prefix.fixedSize ?? 0) + (item.fixedSize ?? 0);
201
- const [isSome2, prefixOffset] = prefix.decode(bytes, offset);
202
- offset = prefixOffset;
191
+ const [isSome2, prefixOffset] = prefix.read(bytes, offset);
203
192
  if (isSome2 === 0) {
204
- return [none(), fixed ? fixedOffset : offset];
193
+ return [none(), fixedSize !== null ? offset + fixedSize : prefixOffset];
205
194
  }
206
- const [value, newOffset] = item.decode(bytes, offset);
207
- offset = newOffset;
208
- return [some(value), fixed ? fixedOffset : offset];
195
+ const [value, newOffset] = item.read(bytes, prefixOffset);
196
+ return [some(value), fixedSize !== null ? offset + fixedSize : newOffset];
209
197
  }
210
- };
198
+ });
199
+ }
200
+ function getOptionCodec(item, config = {}) {
201
+ return combineCodec(getOptionEncoder(item, config), getOptionDecoder(item, config));
202
+ }
203
+ function sumCodecSizes(sizes) {
204
+ return sizes.reduce((all, size) => all === null || size === null ? null : all + size, 0);
211
205
  }
212
- function getOptionCodec(item, options = {}) {
213
- return combineCodec(getOptionEncoder(item, options), getOptionDecoder(item, options));
206
+ function getMaxSize(codec) {
207
+ var _a;
208
+ return isFixedSize(codec) ? codec.fixedSize : (_a = codec.maxSize) != null ? _a : null;
214
209
  }
215
210
 
216
211
  // src/unwrap-option-recursively.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/option.ts","../../codecs-core/src/assertions.ts","../../codecs-core/src/bytes.ts","../../codecs-core/src/combine-codec.ts","../../codecs-numbers/src/assertions.ts","../../codecs-numbers/src/f32.ts","../../codecs-numbers/src/utils.ts","../../codecs-numbers/src/u16.ts","../../codecs-numbers/src/u32.ts","../src/unwrap-option.ts","../src/option-codec.ts","../src/unwrap-option-recursively.ts"],"names":["combineCodec","isSome"],"mappings":"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","sourcesContent":["/**\n * An implementation of the Rust Option type in JavaScript.\n * It can be one of the following:\n * - <code>{@link Some}<T></code>: Meaning there is a value of type T.\n * - <code>{@link None}</code>: Meaning there is no value.\n */\nexport type Option<T> = Some<T> | None;\n\n/**\n * Defines a looser type that can be used when serializing an {@link Option}.\n * This allows us to pass null or the Option value directly whilst still\n * supporting the Option type for use-cases that need more type safety.\n */\nexport type OptionOrNullable<T> = Option<T> | T | null;\n\n/**\n * Represents an option of type `T` that has a value.\n *\n * @see {@link Option}\n */\nexport type Some<T> = Readonly<{ __option: 'Some'; value: T }>;\n\n/**\n * Represents an option of type `T` that has no value.\n *\n * @see {@link Option}\n */\nexport type None = Readonly<{ __option: 'None' }>;\n\n/**\n * Creates a new {@link Option} of type `T` that has a value.\n *\n * @see {@link Option}\n */\nexport const some = <T>(value: T): Option<T> => ({ __option: 'Some', value });\n\n/**\n * Creates a new {@link Option} of type `T` that has no value.\n *\n * @see {@link Option}\n */\nexport const none = <T>(): Option<T> => ({ __option: 'None' });\n\n/**\n * Whether the given data is an {@link Option}.\n */\nexport const isOption = <T = unknown>(input: unknown): input is Option<T> =>\n !!(\n input &&\n typeof input === 'object' &&\n '__option' in input &&\n ((input.__option === 'Some' && 'value' in input) || input.__option === 'None')\n );\n\n/**\n * Whether the given {@link Option} is a {@link Some}.\n */\nexport const isSome = <T>(option: Option<T>): option is Some<T> => option.__option === 'Some';\n\n/**\n * Whether the given {@link Option} is a {@link None}.\n */\nexport const isNone = <T>(option: Option<T>): option is None => option.__option === 'None';\n","import { CodecData } from './codec';\n\n/**\n * Asserts that a given byte array is not empty.\n */\nexport function assertByteArrayIsNotEmptyForCodec(codecDescription: string, bytes: Uint8Array, offset = 0) {\n if (bytes.length - offset <= 0) {\n // TODO: Coded error.\n throw new Error(`Codec [${codecDescription}] cannot decode empty byte arrays.`);\n }\n}\n\n/**\n * Asserts that a given byte array has enough bytes to decode.\n */\nexport function assertByteArrayHasEnoughBytesForCodec(\n codecDescription: string,\n expected: number,\n bytes: Uint8Array,\n offset = 0\n) {\n const bytesLength = bytes.length - offset;\n if (bytesLength < expected) {\n // TODO: Coded error.\n throw new Error(`Codec [${codecDescription}] expected ${expected} bytes, got ${bytesLength}.`);\n }\n}\n\n/**\n * Asserts that a given codec is fixed-size codec.\n */\nexport function assertFixedSizeCodec(\n data: Pick<CodecData, 'fixedSize'>,\n message?: string\n): asserts data is { fixedSize: number } {\n if (data.fixedSize === null) {\n // TODO: Coded error.\n throw new Error(message ?? 'Expected a fixed-size codec, got a variable-size one.');\n }\n}\n","/**\n * Concatenates an array of `Uint8Array`s into a single `Uint8Array`.\n * Reuses the original byte array when applicable.\n */\nexport const mergeBytes = (byteArrays: Uint8Array[]): Uint8Array => {\n const nonEmptyByteArrays = byteArrays.filter(arr => arr.length);\n if (nonEmptyByteArrays.length === 0) {\n return byteArrays.length ? byteArrays[0] : new Uint8Array();\n }\n\n if (nonEmptyByteArrays.length === 1) {\n return nonEmptyByteArrays[0];\n }\n\n const totalLength = nonEmptyByteArrays.reduce((total, arr) => total + arr.length, 0);\n const result = new Uint8Array(totalLength);\n let offset = 0;\n nonEmptyByteArrays.forEach(arr => {\n result.set(arr, offset);\n offset += arr.length;\n });\n return result;\n};\n\n/**\n * Pads a `Uint8Array` with zeroes to the specified length.\n * If the array is longer than the specified length, it is returned as-is.\n */\nexport const padBytes = (bytes: Uint8Array, length: number): Uint8Array => {\n if (bytes.length >= length) return bytes;\n const paddedBytes = new Uint8Array(length).fill(0);\n paddedBytes.set(bytes);\n return paddedBytes;\n};\n\n/**\n * Fixes a `Uint8Array` to the specified length.\n * If the array is longer than the specified length, it is truncated.\n * If the array is shorter than the specified length, it is padded with zeroes.\n */\nexport const fixBytes = (bytes: Uint8Array, length: number): Uint8Array =>\n padBytes(bytes.length <= length ? bytes : bytes.slice(0, length), length);\n","import { Codec, Decoder, Encoder } from './codec';\n\n/**\n * Combines an encoder and a decoder into a codec.\n * The encoder and decoder must have the same fixed size, max size and description.\n * If a description is provided, it will override the encoder and decoder descriptions.\n */\nexport function combineCodec<From, To extends From = From>(\n encoder: Encoder<From>,\n decoder: Decoder<To>,\n description?: string\n): Codec<From, To> {\n if (encoder.fixedSize !== decoder.fixedSize) {\n // TODO: Coded error.\n throw new Error(\n `Encoder and decoder must have the same fixed size, got [${encoder.fixedSize}] and [${decoder.fixedSize}].`\n );\n }\n\n if (encoder.maxSize !== decoder.maxSize) {\n // TODO: Coded error.\n throw new Error(\n `Encoder and decoder must have the same max size, got [${encoder.maxSize}] and [${decoder.maxSize}].`\n );\n }\n\n if (description === undefined && encoder.description !== decoder.description) {\n // TODO: Coded error.\n throw new Error(\n `Encoder and decoder must have the same description, got [${encoder.description}] and [${decoder.description}]. ` +\n `Pass a custom description as a third argument if you want to override the description and bypass this error.`\n );\n }\n\n return {\n decode: decoder.decode,\n description: description ?? encoder.description,\n encode: encoder.encode,\n fixedSize: encoder.fixedSize,\n maxSize: encoder.maxSize,\n };\n}\n","/**\n * Asserts that a given number is between a given range.\n */\nexport function assertNumberIsBetweenForCodec(\n codecDescription: string,\n min: number | bigint,\n max: number | bigint,\n value: number | bigint\n) {\n if (value < min || value > max) {\n // TODO: Coded error.\n throw new Error(\n `Codec [${codecDescription}] expected number to be in the range [${min}, ${max}], got ${value}.`\n );\n }\n}\n","import { Codec, combineCodec, Decoder, Encoder } from '@solana/codecs-core';\n\nimport { NumberCodecOptions } from './common';\nimport { numberDecoderFactory, numberEncoderFactory } from './utils';\n\nexport const getF32Encoder = (options: NumberCodecOptions = {}): Encoder<number> =>\n numberEncoderFactory({\n name: 'f32',\n options,\n set: (view, value, le) => view.setFloat32(0, value, le),\n size: 4,\n });\n\nexport const getF32Decoder = (options: NumberCodecOptions = {}): Decoder<number> =>\n numberDecoderFactory({\n get: (view, le) => view.getFloat32(0, le),\n name: 'f32',\n options,\n size: 4,\n });\n\nexport const getF32Codec = (options: NumberCodecOptions = {}): Codec<number> =>\n combineCodec(getF32Encoder(options), getF32Decoder(options));\n","import {\n assertByteArrayHasEnoughBytesForCodec,\n assertByteArrayIsNotEmptyForCodec,\n CodecData,\n Decoder,\n Encoder,\n} from '@solana/codecs-core';\n\nimport { assertNumberIsBetweenForCodec } from './assertions';\nimport { Endian, NumberCodecOptions, SingleByteNumberCodecOptions } from './common';\n\ntype NumberFactorySharedInput = {\n name: string;\n size: number;\n options: SingleByteNumberCodecOptions | NumberCodecOptions;\n};\n\ntype NumberFactoryEncoderInput<T> = NumberFactorySharedInput & {\n range?: [number | bigint, number | bigint];\n set: (view: DataView, value: T, littleEndian?: boolean) => void;\n};\n\ntype NumberFactoryDecoderInput<T> = NumberFactorySharedInput & {\n get: (view: DataView, littleEndian?: boolean) => T;\n};\n\nfunction sharedNumberFactory(input: NumberFactorySharedInput): CodecData & { littleEndian: boolean | undefined } {\n let littleEndian: boolean | undefined;\n let defaultDescription: string = input.name;\n\n if (input.size > 1) {\n littleEndian = !('endian' in input.options) || input.options.endian === Endian.LITTLE;\n defaultDescription += littleEndian ? '(le)' : '(be)';\n }\n\n return {\n description: input.options.description ?? defaultDescription,\n fixedSize: input.size,\n littleEndian,\n maxSize: input.size,\n };\n}\n\nexport function numberEncoderFactory<T extends number | bigint>(input: NumberFactoryEncoderInput<T>): Encoder<T> {\n const codecData = sharedNumberFactory(input);\n\n return {\n description: codecData.description,\n encode(value: T): Uint8Array {\n if (input.range) {\n assertNumberIsBetweenForCodec(input.name, input.range[0], input.range[1], value);\n }\n const arrayBuffer = new ArrayBuffer(input.size);\n input.set(new DataView(arrayBuffer), value, codecData.littleEndian);\n return new Uint8Array(arrayBuffer);\n },\n fixedSize: codecData.fixedSize,\n maxSize: codecData.maxSize,\n };\n}\n\nexport function numberDecoderFactory<T extends number | bigint>(input: NumberFactoryDecoderInput<T>): Decoder<T> {\n const codecData = sharedNumberFactory(input);\n\n return {\n decode(bytes, offset = 0): [T, number] {\n assertByteArrayIsNotEmptyForCodec(codecData.description, bytes, offset);\n assertByteArrayHasEnoughBytesForCodec(codecData.description, input.size, bytes, offset);\n const view = new DataView(toArrayBuffer(bytes, offset, input.size));\n return [input.get(view, codecData.littleEndian), offset + input.size];\n },\n description: codecData.description,\n fixedSize: codecData.fixedSize,\n maxSize: codecData.maxSize,\n };\n}\n\n/**\n * Helper function to ensure that the ArrayBuffer is converted properly from a Uint8Array\n * Source: https://stackoverflow.com/questions/37228285/uint8array-to-arraybuffer\n */\nfunction toArrayBuffer(bytes: Uint8Array, offset?: number, length?: number): ArrayBuffer {\n const bytesOffset = bytes.byteOffset + (offset ?? 0);\n const bytesLength = length ?? bytes.byteLength;\n return bytes.buffer.slice(bytesOffset, bytesOffset + bytesLength);\n}\n","import { Codec, combineCodec, Decoder, Encoder } from '@solana/codecs-core';\n\nimport { NumberCodecOptions } from './common';\nimport { numberDecoderFactory, numberEncoderFactory } from './utils';\n\nexport const getU16Encoder = (options: NumberCodecOptions = {}): Encoder<number> =>\n numberEncoderFactory({\n name: 'u16',\n options,\n range: [0, Number('0xffff')],\n set: (view, value, le) => view.setUint16(0, value, le),\n size: 2,\n });\n\nexport const getU16Decoder = (options: NumberCodecOptions = {}): Decoder<number> =>\n numberDecoderFactory({\n get: (view, le) => view.getUint16(0, le),\n name: 'u16',\n options,\n size: 2,\n });\n\nexport const getU16Codec = (options: NumberCodecOptions = {}): Codec<number> =>\n combineCodec(getU16Encoder(options), getU16Decoder(options));\n","import { Codec, combineCodec, Decoder, Encoder } from '@solana/codecs-core';\n\nimport { NumberCodecOptions } from './common';\nimport { numberDecoderFactory, numberEncoderFactory } from './utils';\n\nexport const getU32Encoder = (options: NumberCodecOptions = {}): Encoder<number> =>\n numberEncoderFactory({\n name: 'u32',\n options,\n range: [0, Number('0xffffffff')],\n set: (view, value, le) => view.setUint32(0, value, le),\n size: 4,\n });\n\nexport const getU32Decoder = (options: NumberCodecOptions = {}): Decoder<number> =>\n numberDecoderFactory({\n get: (view, le) => view.getUint32(0, le),\n name: 'u32',\n options,\n size: 4,\n });\n\nexport const getU32Codec = (options: NumberCodecOptions = {}): Codec<number> =>\n combineCodec(getU32Encoder(options), getU32Decoder(options));\n","import { isSome, none, Option, some } from './option';\n\n/**\n * Unwraps the value of an {@link Option} of type `T`\n * or returns a fallback value that defaults to `null`.\n */\nexport function unwrapOption<T>(option: Option<T>): T | null;\nexport function unwrapOption<T, U>(option: Option<T>, fallback: () => U): T | U;\nexport function unwrapOption<T, U = null>(option: Option<T>, fallback?: () => U): T | U {\n if (isSome(option)) return option.value;\n return fallback ? fallback() : (null as U);\n}\n\n/**\n * Wraps a nullable value into an {@link Option}.\n */\nexport const wrapNullable = <T>(nullable: T | null): Option<T> => (nullable !== null ? some(nullable) : none<T>());\n","import {\n assertFixedSizeCodec,\n BaseCodecOptions,\n Codec,\n CodecData,\n combineCodec,\n Decoder,\n Encoder,\n fixBytes,\n mergeBytes,\n} from '@solana/codecs-core';\nimport { getU8Decoder, getU8Encoder, NumberCodec, NumberDecoder, NumberEncoder } from '@solana/codecs-numbers';\n\nimport { isOption, isSome, none, Option, OptionOrNullable, some } from './option';\nimport { wrapNullable } from './unwrap-option';\n\n/** Defines the options for option codecs. */\nexport type OptionCodecOptions<TPrefix extends NumberCodec | NumberEncoder | NumberDecoder> = BaseCodecOptions & {\n /**\n * The codec to use for the boolean prefix.\n * @defaultValue u8 prefix.\n */\n prefix?: TPrefix;\n\n /**\n * Whether the item codec should be of fixed size.\n *\n * When this is true, a `None` value will skip the bytes that would\n * have been used for the item. Note that this will only work if the\n * item codec is of fixed size.\n * @defaultValue `false`\n */\n fixed?: boolean;\n};\n\nfunction sumCodecSizes(sizes: (number | null)[]): number | null {\n return sizes.reduce((all, size) => (all === null || size === null ? null : all + size), 0 as number | null);\n}\n\nfunction optionCodecHelper(item: CodecData, prefix: CodecData, fixed: boolean, description?: string): CodecData {\n let descriptionSuffix = `; ${prefix.description}`;\n let fixedSize = item.fixedSize === 0 ? prefix.fixedSize : null;\n if (fixed) {\n assertFixedSizeCodec(item, 'Fixed options can only be used with fixed-size codecs.');\n assertFixedSizeCodec(prefix, 'Fixed options can only be used with fixed-size prefix.');\n descriptionSuffix += '; fixed';\n fixedSize = prefix.fixedSize + item.fixedSize;\n }\n\n return {\n description: description ?? `option(${item.description + descriptionSuffix})`,\n fixedSize,\n maxSize: sumCodecSizes([prefix.maxSize, item.maxSize]),\n };\n}\n\n/**\n * Creates a encoder for an optional value using `null` as the `None` value.\n *\n * @param item - The encoder to use for the value that may be present.\n * @param options - A set of options for the encoder.\n */\nexport function getOptionEncoder<T>(\n item: Encoder<T>,\n options: OptionCodecOptions<NumberEncoder> = {}\n): Encoder<OptionOrNullable<T>> {\n const prefix = options.prefix ?? getU8Encoder();\n const fixed = options.fixed ?? false;\n return {\n ...optionCodecHelper(item, prefix, fixed, options.description),\n encode: (optionOrNullable: OptionOrNullable<T>) => {\n const option = isOption<T>(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);\n const prefixByte = prefix.encode(Number(isSome(option)));\n let itemBytes = isSome(option) ? item.encode(option.value) : new Uint8Array();\n itemBytes = fixed ? fixBytes(itemBytes, item.fixedSize as number) : itemBytes;\n return mergeBytes([prefixByte, itemBytes]);\n },\n };\n}\n\n/**\n * Creates a decoder for an optional value using `null` as the `None` value.\n *\n * @param item - The decoder to use for the value that may be present.\n * @param options - A set of options for the decoder.\n */\nexport function getOptionDecoder<T>(\n item: Decoder<T>,\n options: OptionCodecOptions<NumberDecoder> = {}\n): Decoder<Option<T>> {\n const prefix = options.prefix ?? getU8Decoder();\n const fixed = options.fixed ?? false;\n return {\n ...optionCodecHelper(item, prefix, fixed, options.description),\n decode: (bytes: Uint8Array, offset = 0) => {\n if (bytes.length - offset <= 0) {\n return [none(), offset];\n }\n const fixedOffset = offset + (prefix.fixedSize ?? 0) + (item.fixedSize ?? 0);\n const [isSome, prefixOffset] = prefix.decode(bytes, offset);\n offset = prefixOffset;\n if (isSome === 0) {\n return [none(), fixed ? fixedOffset : offset];\n }\n const [value, newOffset] = item.decode(bytes, offset);\n offset = newOffset;\n return [some(value), fixed ? fixedOffset : offset];\n },\n };\n}\n\n/**\n * Creates a codec for an optional value using `null` as the `None` value.\n *\n * @param item - The codec to use for the value that may be present.\n * @param options - A set of options for the codec.\n */\nexport function getOptionCodec<T, U extends T = T>(\n item: Codec<T, U>,\n options: OptionCodecOptions<NumberCodec> = {}\n): Codec<OptionOrNullable<T>, Option<U>> {\n return combineCodec(getOptionEncoder<T>(item, options), getOptionDecoder<U>(item, options));\n}\n","import { isOption, isSome, None, Some } from './option';\n\n/**\n * Lists all types that should not be recursively unwrapped.\n *\n * @see {@link UnwrappedOption}\n */\ntype UnUnwrappables =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | undefined\n | null\n | Uint8Array\n | Int8Array\n | Uint16Array\n | Int16Array\n | Uint32Array\n | Int32Array\n | Date;\n\n/**\n * A type that defines the recursive unwrapping of a type `T`\n * such that all nested {@link Option} types are unwrapped.\n *\n * For each nested {@link Option} type, if the option is a {@link Some},\n * it returns the type of its value, otherwise, it returns the provided\n * fallback type `U` which defaults to `null`.\n */\nexport type UnwrappedOption<T, U = null> = T extends Some<infer TValue>\n ? UnwrappedOption<TValue, U>\n : T extends None\n ? U\n : T extends UnUnwrappables\n ? T\n : T extends object\n ? { [key in keyof T]: UnwrappedOption<T[key], U> }\n : T extends Array<infer TItem>\n ? Array<UnwrappedOption<TItem, U>>\n : T;\n\n/**\n * Recursively go through a type `T` such that all\n * nested {@link Option} types are unwrapped.\n *\n * For each nested {@link Option} type, if the option is a {@link Some},\n * it returns its value, otherwise, it returns the provided fallback value\n * which defaults to `null`.\n */\nexport function unwrapOptionRecursively<T>(input: T): UnwrappedOption<T>;\nexport function unwrapOptionRecursively<T, U>(input: T, fallback: () => U): UnwrappedOption<T, U>;\nexport function unwrapOptionRecursively<T, U = null>(input: T, fallback?: () => U): UnwrappedOption<T, U> {\n // Types to bypass.\n if (!input || ArrayBuffer.isView(input)) {\n return input as UnwrappedOption<T, U>;\n }\n\n const next = <X>(x: X) =>\n (fallback ? unwrapOptionRecursively(x, fallback) : unwrapOptionRecursively(x)) as UnwrappedOption<X, U>;\n\n // Handle Option.\n if (isOption(input)) {\n if (isSome(input)) return next(input.value) as UnwrappedOption<T, U>;\n return (fallback ? fallback() : null) as UnwrappedOption<T, U>;\n }\n\n // Walk.\n if (Array.isArray(input)) {\n return input.map(next) as UnwrappedOption<T, U>;\n }\n if (typeof input === 'object') {\n return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, next(v)])) as UnwrappedOption<T, U>;\n }\n return input as UnwrappedOption<T, U>;\n}\n"]}
1
+ {"version":3,"sources":["../src/option.ts","../../codecs-core/src/assertions.ts","../../codecs-core/src/codec.ts","../../codecs-core/src/combine-codec.ts","../../codecs-numbers/src/assertions.ts","../../codecs-numbers/src/f32.ts","../../codecs-numbers/src/utils.ts","../../codecs-numbers/src/u16.ts","../src/unwrap-option.ts","../src/option-codec.ts","../src/unwrap-option-recursively.ts"],"names":["isSome"],"mappings":";AAkCO,IAAM,OAAO,CAAI,WAAyB,EAAE,UAAU,QAAQ,MAAM;AAOpE,IAAM,OAAO,OAAqB,EAAE,UAAU,OAAO;AAKrD,IAAM,WAAW,CAAc,UAClC,CAAC,EACG,SACA,OAAO,UAAU,YACjB,cAAc,UACZ,MAAM,aAAa,UAAU,WAAW,SAAU,MAAM,aAAa;AAMxE,IAAM,SAAS,CAAI,WAAyC,OAAO,aAAa;AAKhF,IAAM,SAAS,CAAI,WAAsC,OAAO,aAAa;;;AC3D7E,SAAS,kCAAkC,kBAA0B,OAAmB,SAAS,GAAG;AACvG,MAAI,MAAM,SAAS,UAAU,GAAG;AAE5B,UAAM,IAAI,MAAM,UAAU,gBAAgB,oCAAoC;EAClF;AACJ;AAKO,SAAS,sCACZ,kBACA,UACA,OACA,SAAS,GACX;AACE,QAAM,cAAc,MAAM,SAAS;AACnC,MAAI,cAAc,UAAU;AAExB,UAAM,IAAI,MAAM,UAAU,gBAAgB,cAAc,QAAQ,eAAe,WAAW,GAAG;EACjG;AACJ;ACuDO,SAAS,eACZ,OACA,SACM;AACN,SAAO,eAAe,UAAU,QAAQ,YAAY,QAAQ,iBAAiB,KAAK;AACtF;AAUO,SAAS,cACZ,SACc;AACd,SAAO,OAAO,OAAO;IACjB,GAAG;IACH,QAAQ,CAAA,UAAS;AACb,YAAM,QAAQ,IAAI,WAAW,eAAe,OAAO,OAAO,CAAC;AAC3D,cAAQ,MAAM,OAAO,OAAO,CAAC;AAC7B,aAAO;IACX;EACJ,CAAC;AACL;AAUO,SAAS,cACZ,SACY;AACZ,SAAO,OAAO,OAAO;IACjB,GAAG;IACH,QAAQ,CAAC,OAAO,SAAS,MAAM,QAAQ,KAAK,OAAO,MAAM,EAAE,CAAC;EAChE,CAAC;AACL;AA0CO,SAAS,YAAY,OAAqF;AAC7G,SAAO,eAAe,SAAS,OAAO,MAAM,cAAc;AAC9D;AAkBO,SAAS,kBACZ,OACA,SACsC;AACtC,MAAI,CAAC,YAAY,KAAK,GAAG;AAErB,UAAM,IAAI,MAAM,4BAAW,uDAAuD;EACtF;AACJ;AClKO,SAAS,aACZ,SACA,SACiB;AACjB,MAAI,YAAY,OAAO,MAAM,YAAY,OAAO,GAAG;AAE/C,UAAM,IAAI,MAAM,sEAAsE;EAC1F;AAEA,MAAI,YAAY,OAAO,KAAK,YAAY,OAAO,KAAK,QAAQ,cAAc,QAAQ,WAAW;AAEzF,UAAM,IAAI;MACN,2DAA2D,QAAQ,SAAS,UAAU,QAAQ,SAAS;IAC3G;EACJ;AAEA,MAAI,CAAC,YAAY,OAAO,KAAK,CAAC,YAAY,OAAO,KAAK,QAAQ,YAAY,QAAQ,SAAS;AAEvF,UAAM,IAAI;MACN,yDAAyD,QAAQ,OAAO,UAAU,QAAQ,OAAO;IACrG;EACJ;AAEA,SAAO;IACH,GAAG;IACH,GAAG;IACH,QAAQ,QAAQ;IAChB,QAAQ,QAAQ;IAChB,MAAM,QAAQ;IACd,OAAO,QAAQ;EACnB;AACJ;;;AClDQ,SAAA,8BAAU,kBAAA,KAAA,KAAA,OAAA;AAAA,MACN,QAAA,OAAU,QAAA,KAAgB;AAC9B,UAAA,IAAA;MACJ,UAAA,gBAAA,yCAAA,GAAA,KAAA,GAAA,UAAA,KAAA;IACJ;;;ACfA,SAAS,eAAA,QAAwE;;;ACAjF,SAAA,qBAAA,OAAA;AACI,SAAA,cAAA;IACA,WAAA,MAAA;IACA,MAAA,OAAA,OAAA,QAAA;AACA,UAAA,MAAA,OAAA;AAIG,sCAAA,MAAA,MAAA,MAAA,MAAA,CAAA,GAAA,MAAA,MAAA,CAAA,GAAA,KAAA;MAoBP;AACI,YAAO,cAAQ,IAAA,YAAwB,MAAA,IAAQ;AACnD,YAAA,IAAA,IAAA,SAAA,WAAA,GAAA,OAAA,eAAA,MAAA,MAAA,CAAA;AAEO,YAAS,IAAA,IAAA,WACZ,WAC8B,GAAA,MAAA;AAC9B,aAAO,SAAA,MAAc;IACjB;EAAiB,CAAA;AAEb;AACI,SAAA,qBAAA,OAAA;AAA+E,SACnF,cAAA;IACA,WAAM,MAAA;IACN,KAAA,OAAU,SAAI,GAAA;AACd,wCAAyB,MAAc,MAAM,OAAA,MAAA;AAC7C,4CAAsB,MAAA,MAAA,MAAA,MAAA,OAAA,MAAA;AAC1B,YAAA,OAAA,IAAA,SAAA,cAAA,OAAA,QAAA,MAAA,IAAA,CAAA;AACH,aAAA,CAAA,MAAA,IAAA,MAAA,eAAA,MAAA,MAAA,CAAA,GAAA,SAAA,MAAA,IAAA;IACL;EAEO,CAAA;AAGH;AAAqB,SACjB,cAAiB,OAAA,QAAA,QAAA;AAAA,QACjB,cAAY,MAA2B,cAAA,0BAAA;AACnC,QAAA,cAAA,0BAAA,MAAA;AACA,SAAA,MAAA,OAAA,MAAA,aAAA,cAA4C,WAAY;AACxD;AClDJ,IACA,eAAM,MAAA,qBAAA;EACN,MAAA;EACA,OAAM,CAAA,GAAA,OAAM,MAAO,CAAA;EACnB,KAAA,CAAM,MAAA,UAAA,KAAA,SAAA,GAAA,KAAA;EACT,MAAA;AAEE,CAAA;AACkB,IACjB,eAAA,MAAA,qBAAA;EACA,KAAK,CAAC,SAAM,KAAO,SAAK,CAAA;EACxB,MAAM;EACN,MAAM;AACV,CAAC;;;ACZE,SAAS,aAA0B,QAAmB,UAA2B;AACpF,MAAI,OAAO,MAAM;AAAG,WAAO,OAAO;AAClC,SAAO,WAAW,SAAS,IAAK;AACpC;AAKO,IAAM,eAAe,CAAI,aAAmC,aAAa,OAAO,KAAK,QAAQ,IAAI,KAAQ;;;ACoDzG,SAAS,iBACZ,MACA,SAA2C,CAAC,GACZ;AAvEpC;AAwEI,QAAM,UAAS,YAAO,WAAP,YAAiB,aAAa;AAC7C,QAAM,SAAQ,YAAO,UAAP,YAAgB;AAE9B,QAAM,iBAAiB,YAAY,IAAI,KAAK,YAAY,MAAM,KAAK,KAAK,cAAc;AACtF,MAAI,SAAS,gBAAgB;AACzB,sBAAkB,MAAM,wDAAwD;AAChF,sBAAkB,QAAQ,wDAAwD;AAClF,UAAM,YAAY,OAAO,YAAY,KAAK;AAC1C,WAAO,cAAc;AAAA,MACjB;AAAA,MACA,OAAO,CAAC,kBAA2C,OAAO,WAAW;AACjE,cAAM,SAAS,SAAgB,gBAAgB,IAAI,mBAAmB,aAAa,gBAAgB;AACnG,cAAM,eAAe,OAAO,MAAM,OAAO,OAAO,MAAM,CAAC,GAAG,OAAO,MAAM;AACvE,YAAI,OAAO,MAAM,GAAG;AAChB,eAAK,MAAM,OAAO,OAAO,OAAO,YAAY;AAAA,QAChD;AACA,eAAO,SAAS;AAAA,MACpB;AAAA,IACJ,CAAC;AAAA,EACL;AAEA,SAAO,cAAc;AAAA,IACjB,kBAAkB,CAAC,qBAA8C;AAC7D,YAAM,SAAS,SAAgB,gBAAgB,IAAI,mBAAmB,aAAa,gBAAgB;AACnG,aACI,eAAe,OAAO,OAAO,MAAM,CAAC,GAAG,MAAM,KAC5C,OAAO,MAAM,IAAI,eAAe,OAAO,OAAO,IAAI,IAAI;AAAA,IAE/D;AAAA,IACA,UAAS,mBAAc,CAAC,QAAQ,IAAI,EAAE,IAAI,UAAU,CAAC,MAA5C,YAAiD;AAAA,IAC1D,OAAO,CAAC,kBAA2C,OAAO,WAAW;AACjE,YAAM,SAAS,SAAgB,gBAAgB,IAAI,mBAAmB,aAAa,gBAAgB;AACnG,eAAS,OAAO,MAAM,OAAO,OAAO,MAAM,CAAC,GAAG,OAAO,MAAM;AAC3D,UAAI,OAAO,MAAM,GAAG;AAChB,iBAAS,KAAK,MAAM,OAAO,OAAO,OAAO,MAAM;AAAA,MACnD;AACA,aAAO;AAAA,IACX;AAAA,EACJ,CAAC;AACL;AAoBO,SAAS,iBACZ,MACA,SAA2C,CAAC,GACxB;AAtIxB;AAuII,QAAM,UAAS,YAAO,WAAP,YAAiB,aAAa;AAC7C,QAAM,SAAQ,YAAO,UAAP,YAAgB;AAE9B,MAAI,YAA2B;AAC/B,QAAM,iBAAiB,YAAY,IAAI,KAAK,YAAY,MAAM,KAAK,KAAK,cAAc;AACtF,MAAI,SAAS,gBAAgB;AACzB,sBAAkB,MAAM,wDAAwD;AAChF,sBAAkB,QAAQ,wDAAwD;AAClF,gBAAY,OAAO,YAAY,KAAK;AAAA,EACxC;AAEA,SAAO,cAAc;AAAA,IACjB,GAAI,cAAc,OACZ,EAAE,UAAS,mBAAc,CAAC,QAAQ,IAAI,EAAE,IAAI,UAAU,CAAC,MAA5C,YAAiD,OAAU,IACtE,EAAE,UAAU;AAAA,IAClB,MAAM,CAAC,OAAmB,WAAW;AACjC,UAAI,MAAM,SAAS,UAAU,GAAG;AAC5B,eAAO,CAAC,KAAK,GAAG,MAAM;AAAA,MAC1B;AACA,YAAM,CAACA,SAAQ,YAAY,IAAI,OAAO,KAAK,OAAO,MAAM;AACxD,UAAIA,YAAW,GAAG;AACd,eAAO,CAAC,KAAK,GAAG,cAAc,OAAO,SAAS,YAAY,YAAY;AAAA,MAC1E;AACA,YAAM,CAAC,OAAO,SAAS,IAAI,KAAK,KAAK,OAAO,YAAY;AACxD,aAAO,CAAC,KAAK,KAAK,GAAG,cAAc,OAAO,SAAS,YAAY,SAAS;AAAA,IAC5E;AAAA,EACJ,CAAC;AACL;AAoBO,SAAS,eACZ,MACA,SAAyC,CAAC,GACC;AAC3C,SAAO,aAAa,iBAAwB,MAAM,MAAgB,GAAG,iBAAsB,MAAM,MAAgB,CAAC;AACtH;AAEA,SAAS,cAAc,OAAyC;AAC5D,SAAO,MAAM,OAAO,CAAC,KAAK,SAAU,QAAQ,QAAQ,SAAS,OAAO,OAAO,MAAM,MAAO,CAAkB;AAC9G;AAEA,SAAS,WAAW,OAAoE;AAjMxF;AAkMI,SAAO,YAAY,KAAK,IAAI,MAAM,aAAY,WAAM,YAAN,YAAiB;AACnE;;;AC9IO,SAAS,wBAAqC,OAAU,UAA2C;AAEtG,MAAI,CAAC,SAAS,YAAY,OAAO,KAAK,GAAG;AACrC,WAAO;AAAA,EACX;AAEA,QAAM,OAAO,CAAI,MACZ,WAAW,wBAAwB,GAAG,QAAQ,IAAI,wBAAwB,CAAC;AAGhF,MAAI,SAAS,KAAK,GAAG;AACjB,QAAI,OAAO,KAAK;AAAG,aAAO,KAAK,MAAM,KAAK;AAC1C,WAAQ,WAAW,SAAS,IAAI;AAAA,EACpC;AAGA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACtB,WAAO,MAAM,IAAI,IAAI;AAAA,EACzB;AACA,MAAI,OAAO,UAAU,UAAU;AAC3B,WAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;AAAA,EACjF;AACA,SAAO;AACX","sourcesContent":["/**\n * An implementation of the Rust Option type in JavaScript.\n * It can be one of the following:\n * - <code>{@link Some}<T></code>: Meaning there is a value of type T.\n * - <code>{@link None}</code>: Meaning there is no value.\n */\nexport type Option<T> = Some<T> | None;\n\n/**\n * Defines a looser type that can be used when serializing an {@link Option}.\n * This allows us to pass null or the Option value directly whilst still\n * supporting the Option type for use-cases that need more type safety.\n */\nexport type OptionOrNullable<T> = Option<T> | T | null;\n\n/**\n * Represents an option of type `T` that has a value.\n *\n * @see {@link Option}\n */\nexport type Some<T> = Readonly<{ __option: 'Some'; value: T }>;\n\n/**\n * Represents an option of type `T` that has no value.\n *\n * @see {@link Option}\n */\nexport type None = Readonly<{ __option: 'None' }>;\n\n/**\n * Creates a new {@link Option} of type `T` that has a value.\n *\n * @see {@link Option}\n */\nexport const some = <T>(value: T): Option<T> => ({ __option: 'Some', value });\n\n/**\n * Creates a new {@link Option} of type `T` that has no value.\n *\n * @see {@link Option}\n */\nexport const none = <T>(): Option<T> => ({ __option: 'None' });\n\n/**\n * Whether the given data is an {@link Option}.\n */\nexport const isOption = <T = unknown>(input: unknown): input is Option<T> =>\n !!(\n input &&\n typeof input === 'object' &&\n '__option' in input &&\n ((input.__option === 'Some' && 'value' in input) || input.__option === 'None')\n );\n\n/**\n * Whether the given {@link Option} is a {@link Some}.\n */\nexport const isSome = <T>(option: Option<T>): option is Some<T> => option.__option === 'Some';\n\n/**\n * Whether the given {@link Option} is a {@link None}.\n */\nexport const isNone = <T>(option: Option<T>): option is None => option.__option === 'None';\n","/**\n * Asserts that a given byte array is not empty.\n */\nexport function assertByteArrayIsNotEmptyForCodec(codecDescription: string, bytes: Uint8Array, offset = 0) {\n if (bytes.length - offset <= 0) {\n // TODO: Coded error.\n throw new Error(`Codec [${codecDescription}] cannot decode empty byte arrays.`);\n }\n}\n\n/**\n * Asserts that a given byte array has enough bytes to decode.\n */\nexport function assertByteArrayHasEnoughBytesForCodec(\n codecDescription: string,\n expected: number,\n bytes: Uint8Array,\n offset = 0,\n) {\n const bytesLength = bytes.length - offset;\n if (bytesLength < expected) {\n // TODO: Coded error.\n throw new Error(`Codec [${codecDescription}] expected ${expected} bytes, got ${bytesLength}.`);\n }\n}\n","/**\n * Defines an offset in bytes.\n */\nexport type Offset = number;\n\ntype BaseEncoder<TFrom> = {\n /** Encode the provided value and return the encoded bytes directly. */\n readonly encode: (value: TFrom) => Uint8Array;\n /**\n * Writes the encoded value into the provided byte array at the given offset.\n * Returns the offset of the next byte after the encoded value.\n */\n readonly write: (value: TFrom, bytes: Uint8Array, offset: Offset) => Offset;\n};\n\nexport type FixedSizeEncoder<TFrom, TSize extends number = number> = BaseEncoder<TFrom> & {\n /** The fixed size of the encoded value in bytes. */\n readonly fixedSize: TSize;\n};\n\nexport type VariableSizeEncoder<TFrom> = BaseEncoder<TFrom> & {\n /** The total size of the encoded value in bytes. */\n readonly getSizeFromValue: (value: TFrom) => number;\n /** The maximum size an encoded value can be in bytes, if applicable. */\n readonly maxSize?: number;\n};\n\n/**\n * An object that can encode a value to a `Uint8Array`.\n */\nexport type Encoder<TFrom> = FixedSizeEncoder<TFrom> | VariableSizeEncoder<TFrom>;\n\ntype BaseDecoder<TTo> = {\n /** Decodes the provided byte array at the given offset (or zero) and returns the value directly. */\n readonly decode: (bytes: Uint8Array, offset?: Offset) => TTo;\n /**\n * Reads the encoded value from the provided byte array at the given offset.\n * Returns the decoded value and the offset of the next byte after the encoded value.\n */\n readonly read: (bytes: Uint8Array, offset: Offset) => [TTo, Offset];\n};\n\nexport type FixedSizeDecoder<TTo, TSize extends number = number> = BaseDecoder<TTo> & {\n /** The fixed size of the encoded value in bytes. */\n readonly fixedSize: TSize;\n};\n\nexport type VariableSizeDecoder<TTo> = BaseDecoder<TTo> & {\n /** The maximum size an encoded value can be in bytes, if applicable. */\n readonly maxSize?: number;\n};\n\n/**\n * An object that can decode a value from a `Uint8Array`.\n */\nexport type Decoder<TTo> = FixedSizeDecoder<TTo> | VariableSizeDecoder<TTo>;\n\nexport type FixedSizeCodec<TFrom, TTo extends TFrom = TFrom, TSize extends number = number> = FixedSizeEncoder<\n TFrom,\n TSize\n> &\n FixedSizeDecoder<TTo, TSize>;\n\nexport type VariableSizeCodec<TFrom, TTo extends TFrom = TFrom> = VariableSizeEncoder<TFrom> & VariableSizeDecoder<TTo>;\n\n/**\n * An object that can encode and decode a value to and from a `Uint8Array`.\n * It supports encoding looser types than it decodes for convenience.\n * For example, a `bigint` encoder will always decode to a `bigint`\n * but can be used to encode a `number`.\n *\n * @typeParam TFrom - The type of the value to encode.\n * @typeParam TTo - The type of the decoded value. Defaults to `TFrom`.\n */\nexport type Codec<TFrom, TTo extends TFrom = TFrom> = FixedSizeCodec<TFrom, TTo> | VariableSizeCodec<TFrom, TTo>;\n\n/**\n * Get the encoded size of a given value in bytes.\n */\nexport function getEncodedSize<TFrom>(\n value: TFrom,\n encoder: { fixedSize: number } | { getSizeFromValue: (value: TFrom) => number },\n): number {\n return 'fixedSize' in encoder ? encoder.fixedSize : encoder.getSizeFromValue(value);\n}\n\n/** Fills the missing `encode` function using the existing `write` function. */\nexport function createEncoder<TFrom, TSize extends number>(\n encoder: Omit<FixedSizeEncoder<TFrom, TSize>, 'encode'>,\n): FixedSizeEncoder<TFrom, TSize>;\nexport function createEncoder<TFrom>(encoder: Omit<VariableSizeEncoder<TFrom>, 'encode'>): VariableSizeEncoder<TFrom>;\nexport function createEncoder<TFrom>(\n encoder: Omit<FixedSizeEncoder<TFrom>, 'encode'> | Omit<VariableSizeEncoder<TFrom>, 'encode'>,\n): Encoder<TFrom>;\nexport function createEncoder<TFrom>(\n encoder: Omit<FixedSizeEncoder<TFrom>, 'encode'> | Omit<VariableSizeEncoder<TFrom>, 'encode'>,\n): Encoder<TFrom> {\n return Object.freeze({\n ...encoder,\n encode: value => {\n const bytes = new Uint8Array(getEncodedSize(value, encoder));\n encoder.write(value, bytes, 0);\n return bytes;\n },\n });\n}\n\n/** Fills the missing `decode` function using the existing `read` function. */\nexport function createDecoder<TTo, TSize extends number>(\n decoder: Omit<FixedSizeDecoder<TTo, TSize>, 'decode'>,\n): FixedSizeDecoder<TTo, TSize>;\nexport function createDecoder<TTo>(decoder: Omit<VariableSizeDecoder<TTo>, 'decode'>): VariableSizeDecoder<TTo>;\nexport function createDecoder<TTo>(\n decoder: Omit<FixedSizeDecoder<TTo>, 'decode'> | Omit<VariableSizeDecoder<TTo>, 'decode'>,\n): Decoder<TTo>;\nexport function createDecoder<TTo>(\n decoder: Omit<FixedSizeDecoder<TTo>, 'decode'> | Omit<VariableSizeDecoder<TTo>, 'decode'>,\n): Decoder<TTo> {\n return Object.freeze({\n ...decoder,\n decode: (bytes, offset = 0) => decoder.read(bytes, offset)[0],\n });\n}\n\n/** Fills the missing `encode` and `decode` function using the existing `write` and `read` functions. */\nexport function createCodec<TFrom, TTo extends TFrom = TFrom, TSize extends number = number>(\n codec: Omit<FixedSizeCodec<TFrom, TTo, TSize>, 'encode' | 'decode'>,\n): FixedSizeCodec<TFrom, TTo, TSize>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec: Omit<VariableSizeCodec<TFrom, TTo>, 'encode' | 'decode'>,\n): VariableSizeCodec<TFrom, TTo>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec:\n | Omit<FixedSizeCodec<TFrom, TTo>, 'encode' | 'decode'>\n | Omit<VariableSizeCodec<TFrom, TTo>, 'encode' | 'decode'>,\n): Codec<TFrom, TTo>;\nexport function createCodec<TFrom, TTo extends TFrom = TFrom>(\n codec:\n | Omit<FixedSizeCodec<TFrom, TTo>, 'encode' | 'decode'>\n | Omit<VariableSizeCodec<TFrom, TTo>, 'encode' | 'decode'>,\n): Codec<TFrom, TTo> {\n return Object.freeze({\n ...codec,\n decode: (bytes, offset = 0) => codec.read(bytes, offset)[0],\n encode: value => {\n const bytes = new Uint8Array(getEncodedSize(value, codec));\n codec.write(value, bytes, 0);\n return bytes;\n },\n });\n}\n\nexport function isFixedSize<TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize> | VariableSizeEncoder<TFrom>,\n): encoder is FixedSizeEncoder<TFrom, TSize>;\nexport function isFixedSize<TTo, TSize extends number>(\n decoder: FixedSizeDecoder<TTo, TSize> | VariableSizeDecoder<TTo>,\n): decoder is FixedSizeDecoder<TTo, TSize>;\nexport function isFixedSize<TFrom, TTo extends TFrom, TSize extends number>(\n codec: FixedSizeCodec<TFrom, TTo, TSize> | VariableSizeCodec<TFrom, TTo>,\n): codec is FixedSizeCodec<TFrom, TTo, TSize>;\nexport function isFixedSize<TSize extends number>(\n codec: { fixedSize: TSize } | { maxSize?: number },\n): codec is { fixedSize: TSize };\nexport function isFixedSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { fixedSize: number } {\n return 'fixedSize' in codec && typeof codec.fixedSize === 'number';\n}\n\nexport function assertIsFixedSize<TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize> | VariableSizeEncoder<TFrom>,\n message?: string,\n): asserts encoder is FixedSizeEncoder<TFrom, TSize>;\nexport function assertIsFixedSize<TTo, TSize extends number>(\n decoder: FixedSizeDecoder<TTo, TSize> | VariableSizeDecoder<TTo>,\n message?: string,\n): asserts decoder is FixedSizeDecoder<TTo, TSize>;\nexport function assertIsFixedSize<TFrom, TTo extends TFrom, TSize extends number>(\n codec: FixedSizeCodec<TFrom, TTo, TSize> | VariableSizeCodec<TFrom, TTo>,\n message?: string,\n): asserts codec is FixedSizeCodec<TFrom, TTo, TSize>;\nexport function assertIsFixedSize<TSize extends number>(\n codec: { fixedSize: TSize } | { maxSize?: number },\n message?: string,\n): asserts codec is { fixedSize: TSize };\nexport function assertIsFixedSize(\n codec: { fixedSize: number } | { maxSize?: number },\n message?: string,\n): asserts codec is { fixedSize: number } {\n if (!isFixedSize(codec)) {\n // TODO: Coded error.\n throw new Error(message ?? 'Expected a fixed-size codec, got a variable-size one.');\n }\n}\n\nexport function isVariableSize<TFrom>(encoder: Encoder<TFrom>): encoder is VariableSizeEncoder<TFrom>;\nexport function isVariableSize<TTo>(decoder: Decoder<TTo>): decoder is VariableSizeDecoder<TTo>;\nexport function isVariableSize<TFrom, TTo extends TFrom>(\n codec: Codec<TFrom, TTo>,\n): codec is VariableSizeCodec<TFrom, TTo>;\nexport function isVariableSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { maxSize?: number };\nexport function isVariableSize(codec: { fixedSize: number } | { maxSize?: number }): codec is { maxSize?: number } {\n return !isFixedSize(codec);\n}\n\nexport function assertIsVariableSize<T>(\n encoder: Encoder<T>,\n message?: string,\n): asserts encoder is VariableSizeEncoder<T>;\nexport function assertIsVariableSize<T>(\n decoder: Decoder<T>,\n message?: string,\n): asserts decoder is VariableSizeDecoder<T>;\nexport function assertIsVariableSize<TFrom, TTo extends TFrom>(\n codec: Codec<TFrom, TTo>,\n message?: string,\n): asserts codec is VariableSizeCodec<TFrom, TTo>;\nexport function assertIsVariableSize(\n codec: { fixedSize: number } | { maxSize?: number },\n message?: string,\n): asserts codec is { maxSize?: number };\nexport function assertIsVariableSize(\n codec: { fixedSize: number } | { maxSize?: number },\n message?: string,\n): asserts codec is { maxSize?: number } {\n if (!isVariableSize(codec)) {\n // TODO: Coded error.\n throw new Error(message ?? 'Expected a variable-size codec, got a fixed-size one.');\n }\n}\n","import {\n Codec,\n Decoder,\n Encoder,\n FixedSizeCodec,\n FixedSizeDecoder,\n FixedSizeEncoder,\n isFixedSize,\n VariableSizeCodec,\n VariableSizeDecoder,\n VariableSizeEncoder,\n} from './codec';\n\n/**\n * Combines an encoder and a decoder into a codec.\n * The encoder and decoder must have the same fixed size, max size and description.\n * If a description is provided, it will override the encoder and decoder descriptions.\n */\nexport function combineCodec<TFrom, TTo extends TFrom, TSize extends number>(\n encoder: FixedSizeEncoder<TFrom, TSize>,\n decoder: FixedSizeDecoder<TTo, TSize>,\n): FixedSizeCodec<TFrom, TTo, TSize>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: VariableSizeEncoder<TFrom>,\n decoder: VariableSizeDecoder<TTo>,\n): VariableSizeCodec<TFrom, TTo>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: Encoder<TFrom>,\n decoder: Decoder<TTo>,\n): Codec<TFrom, TTo>;\nexport function combineCodec<TFrom, TTo extends TFrom>(\n encoder: Encoder<TFrom>,\n decoder: Decoder<TTo>,\n): Codec<TFrom, TTo> {\n if (isFixedSize(encoder) !== isFixedSize(decoder)) {\n // TODO: Coded error.\n throw new Error(`Encoder and decoder must either both be fixed-size or variable-size.`);\n }\n\n if (isFixedSize(encoder) && isFixedSize(decoder) && encoder.fixedSize !== decoder.fixedSize) {\n // TODO: Coded error.\n throw new Error(\n `Encoder and decoder must have the same fixed size, got [${encoder.fixedSize}] and [${decoder.fixedSize}].`,\n );\n }\n\n if (!isFixedSize(encoder) && !isFixedSize(decoder) && encoder.maxSize !== decoder.maxSize) {\n // TODO: Coded error.\n throw new Error(\n `Encoder and decoder must have the same max size, got [${encoder.maxSize}] and [${decoder.maxSize}].`,\n );\n }\n\n return {\n ...decoder,\n ...encoder,\n decode: decoder.decode,\n encode: encoder.encode,\n read: decoder.read,\n write: encoder.write,\n };\n}\n","/**\n * Asserts that a given number is between a given range.\n */\nexport function assertNumberIsBetweenForCodec(\n codecDescription: string,\n min: number | bigint,\n max: number | bigint,\n value: number | bigint,\n) {\n if (value < min || value > max) {\n // TODO: Coded error.\n throw new Error(\n `Codec [${codecDescription}] expected number to be in the range [${min}, ${max}], got ${value}.`,\n );\n }\n}\n","import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';\n\nimport { NumberCodecConfig } from './common';\nimport { numberDecoderFactory, numberEncoderFactory } from './utils';\n\nexport const getF32Encoder = (config: NumberCodecConfig = {}): FixedSizeEncoder<number, 4> =>\n numberEncoderFactory({\n config,\n name: 'f32',\n set: (view, value, le) => view.setFloat32(0, value, le),\n size: 4,\n });\n\nexport const getF32Decoder = (config: NumberCodecConfig = {}): FixedSizeDecoder<number, 4> =>\n numberDecoderFactory({\n config,\n get: (view, le) => view.getFloat32(0, le),\n name: 'f32',\n size: 4,\n });\n\nexport const getF32Codec = (config: NumberCodecConfig = {}): FixedSizeCodec<number, number, 4> =>\n combineCodec(getF32Encoder(config), getF32Decoder(config));\n","import {\n assertByteArrayHasEnoughBytesForCodec,\n assertByteArrayIsNotEmptyForCodec,\n createDecoder,\n createEncoder,\n FixedSizeDecoder,\n FixedSizeEncoder,\n Offset,\n} from '@solana/codecs-core';\n\nimport { assertNumberIsBetweenForCodec } from './assertions';\nimport { Endian, NumberCodecConfig } from './common';\n\ntype NumberFactorySharedInput<TSize extends number> = {\n name: string;\n size: TSize;\n config?: NumberCodecConfig;\n};\n\ntype NumberFactoryEncoderInput<TFrom, TSize extends number> = NumberFactorySharedInput<TSize> & {\n range?: [number | bigint, number | bigint];\n set: (view: DataView, value: TFrom, littleEndian?: boolean) => void;\n};\n\ntype NumberFactoryDecoderInput<TTo, TSize extends number> = NumberFactorySharedInput<TSize> & {\n get: (view: DataView, littleEndian?: boolean) => TTo;\n};\n\nfunction isLittleEndian(config?: NumberCodecConfig): boolean {\n return config?.endian === Endian.BIG ? false : true;\n}\n\nexport function numberEncoderFactory<TFrom extends number | bigint, TSize extends number>(\n input: NumberFactoryEncoderInput<TFrom, TSize>,\n): FixedSizeEncoder<TFrom, TSize> {\n return createEncoder({\n fixedSize: input.size,\n write(value: TFrom, bytes: Uint8Array, offset: Offset): Offset {\n if (input.range) {\n assertNumberIsBetweenForCodec(input.name, input.range[0], input.range[1], value);\n }\n const arrayBuffer = new ArrayBuffer(input.size);\n input.set(new DataView(arrayBuffer), value, isLittleEndian(input.config));\n bytes.set(new Uint8Array(arrayBuffer), offset);\n return offset + input.size;\n },\n });\n}\n\nexport function numberDecoderFactory<TTo extends number | bigint, TSize extends number>(\n input: NumberFactoryDecoderInput<TTo, TSize>,\n): FixedSizeDecoder<TTo, TSize> {\n return createDecoder({\n fixedSize: input.size,\n read(bytes, offset = 0): [TTo, number] {\n assertByteArrayIsNotEmptyForCodec(input.name, bytes, offset);\n assertByteArrayHasEnoughBytesForCodec(input.name, input.size, bytes, offset);\n const view = new DataView(toArrayBuffer(bytes, offset, input.size));\n return [input.get(view, isLittleEndian(input.config)), offset + input.size];\n },\n });\n}\n\n/**\n * Helper function to ensure that the ArrayBuffer is converted properly from a Uint8Array\n * Source: https://stackoverflow.com/questions/37228285/uint8array-to-arraybuffer\n */\nfunction toArrayBuffer(bytes: Uint8Array, offset?: number, length?: number): ArrayBuffer {\n const bytesOffset = bytes.byteOffset + (offset ?? 0);\n const bytesLength = length ?? bytes.byteLength;\n return bytes.buffer.slice(bytesOffset, bytesOffset + bytesLength);\n}\n","import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';\n\nimport { NumberCodecConfig } from './common';\nimport { numberDecoderFactory, numberEncoderFactory } from './utils';\n\nexport const getU16Encoder = (config: NumberCodecConfig = {}): FixedSizeEncoder<number, 2> =>\n numberEncoderFactory({\n config,\n name: 'u16',\n range: [0, Number('0xffff')],\n set: (view, value, le) => view.setUint16(0, value, le),\n size: 2,\n });\n\nexport const getU16Decoder = (config: NumberCodecConfig = {}): FixedSizeDecoder<number, 2> =>\n numberDecoderFactory({\n config,\n get: (view, le) => view.getUint16(0, le),\n name: 'u16',\n size: 2,\n });\n\nexport const getU16Codec = (config: NumberCodecConfig = {}): FixedSizeCodec<number, number, 2> =>\n combineCodec(getU16Encoder(config), getU16Decoder(config));\n","import { isSome, none, Option, some } from './option';\n\n/**\n * Unwraps the value of an {@link Option} of type `T`\n * or returns a fallback value that defaults to `null`.\n */\nexport function unwrapOption<T>(option: Option<T>): T | null;\nexport function unwrapOption<T, U>(option: Option<T>, fallback: () => U): T | U;\nexport function unwrapOption<T, U = null>(option: Option<T>, fallback?: () => U): T | U {\n if (isSome(option)) return option.value;\n return fallback ? fallback() : (null as U);\n}\n\n/**\n * Wraps a nullable value into an {@link Option}.\n */\nexport const wrapNullable = <T>(nullable: T | null): Option<T> => (nullable !== null ? some(nullable) : none<T>());\n","import {\n assertIsFixedSize,\n Codec,\n combineCodec,\n createDecoder,\n createEncoder,\n Decoder,\n Encoder,\n FixedSizeCodec,\n FixedSizeDecoder,\n FixedSizeEncoder,\n getEncodedSize,\n isFixedSize,\n VariableSizeCodec,\n VariableSizeDecoder,\n VariableSizeEncoder,\n} from '@solana/codecs-core';\nimport {\n FixedSizeNumberCodec,\n FixedSizeNumberDecoder,\n FixedSizeNumberEncoder,\n getU8Decoder,\n getU8Encoder,\n NumberCodec,\n NumberDecoder,\n NumberEncoder,\n} from '@solana/codecs-numbers';\n\nimport { isOption, isSome, none, Option, OptionOrNullable, some } from './option';\nimport { wrapNullable } from './unwrap-option';\n\n/** Defines the config for option codecs. */\nexport type OptionCodecConfig<TPrefix extends NumberCodec | NumberEncoder | NumberDecoder> = {\n /**\n * The codec to use for the boolean prefix.\n * @defaultValue u8 prefix.\n */\n prefix?: TPrefix;\n\n /**\n * Whether the item codec should be of fixed size.\n *\n * When this is true, a `None` value will skip the bytes that would\n * have been used for the item. Note that this will only work if the\n * item codec is of fixed size.\n * @defaultValue `false`\n */\n fixed?: boolean;\n};\n\n/**\n * Creates a encoder for an optional value using `null` as the `None` value.\n *\n * @param item - The encoder to use for the value that may be present.\n * @param config - A set of config for the encoder.\n */\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom>,\n config: OptionCodecConfig<FixedSizeNumberEncoder> & { fixed: true },\n): FixedSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom, 0>,\n config?: OptionCodecConfig<FixedSizeNumberEncoder>,\n): FixedSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config?: OptionCodecConfig<NumberEncoder> & { fixed?: false },\n): VariableSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config: OptionCodecConfig<NumberEncoder> = {},\n): Encoder<OptionOrNullable<TFrom>> {\n const prefix = config.prefix ?? getU8Encoder();\n const fixed = config.fixed ?? false;\n\n const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;\n if (fixed || isZeroSizeItem) {\n assertIsFixedSize(item, 'Fixed options can only be used with fixed-size codecs.');\n assertIsFixedSize(prefix, 'Fixed options can only be used with fixed-size prefix.');\n const fixedSize = prefix.fixedSize + item.fixedSize;\n return createEncoder({\n fixedSize,\n write: (optionOrNullable: OptionOrNullable<TFrom>, bytes, offset) => {\n const option = isOption<TFrom>(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);\n const prefixOffset = prefix.write(Number(isSome(option)), bytes, offset);\n if (isSome(option)) {\n item.write(option.value, bytes, prefixOffset);\n }\n return offset + fixedSize;\n },\n });\n }\n\n return createEncoder({\n getSizeFromValue: (optionOrNullable: OptionOrNullable<TFrom>) => {\n const option = isOption<TFrom>(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);\n return (\n getEncodedSize(Number(isSome(option)), prefix) +\n (isSome(option) ? getEncodedSize(option.value, item) : 0)\n );\n },\n maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? undefined,\n write: (optionOrNullable: OptionOrNullable<TFrom>, bytes, offset) => {\n const option = isOption<TFrom>(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);\n offset = prefix.write(Number(isSome(option)), bytes, offset);\n if (isSome(option)) {\n offset = item.write(option.value, bytes, offset);\n }\n return offset;\n },\n });\n}\n\n/**\n * Creates a decoder for an optional value using `null` as the `None` value.\n *\n * @param item - The decoder to use for the value that may be present.\n * @param config - A set of config for the decoder.\n */\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo>,\n config: OptionCodecConfig<FixedSizeNumberDecoder> & { fixed: true },\n): FixedSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo, 0>,\n config?: OptionCodecConfig<FixedSizeNumberDecoder>,\n): FixedSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config?: OptionCodecConfig<NumberDecoder> & { fixed?: false },\n): VariableSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config: OptionCodecConfig<NumberDecoder> = {},\n): Decoder<Option<TTo>> {\n const prefix = config.prefix ?? getU8Decoder();\n const fixed = config.fixed ?? false;\n\n let fixedSize: number | null = null;\n const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;\n if (fixed || isZeroSizeItem) {\n assertIsFixedSize(item, 'Fixed options can only be used with fixed-size codecs.');\n assertIsFixedSize(prefix, 'Fixed options can only be used with fixed-size prefix.');\n fixedSize = prefix.fixedSize + item.fixedSize;\n }\n\n return createDecoder({\n ...(fixedSize === null\n ? { maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? undefined }\n : { fixedSize }),\n read: (bytes: Uint8Array, offset) => {\n if (bytes.length - offset <= 0) {\n return [none(), offset];\n }\n const [isSome, prefixOffset] = prefix.read(bytes, offset);\n if (isSome === 0) {\n return [none(), fixedSize !== null ? offset + fixedSize : prefixOffset];\n }\n const [value, newOffset] = item.read(bytes, prefixOffset);\n return [some(value), fixedSize !== null ? offset + fixedSize : newOffset];\n },\n });\n}\n\n/**\n * Creates a codec for an optional value using `null` as the `None` value.\n *\n * @param item - The codec to use for the value that may be present.\n * @param config - A set of config for the codec.\n */\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo>,\n config: OptionCodecConfig<FixedSizeNumberCodec> & { fixed: true },\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo, 0>,\n config?: OptionCodecConfig<FixedSizeNumberCodec>,\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: Codec<TFrom, TTo>,\n config?: OptionCodecConfig<NumberCodec> & { fixed?: false },\n): VariableSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: Codec<TFrom, TTo>,\n config: OptionCodecConfig<NumberCodec> = {},\n): Codec<OptionOrNullable<TFrom>, Option<TTo>> {\n return combineCodec(getOptionEncoder<TFrom>(item, config as object), getOptionDecoder<TTo>(item, config as object));\n}\n\nfunction sumCodecSizes(sizes: (number | null)[]): number | null {\n return sizes.reduce((all, size) => (all === null || size === null ? null : all + size), 0 as number | null);\n}\n\nfunction getMaxSize(codec: { fixedSize: number } | { maxSize?: number }): number | null {\n return isFixedSize(codec) ? codec.fixedSize : codec.maxSize ?? null;\n}\n","import { isOption, isSome, None, Some } from './option';\n\n/**\n * Lists all types that should not be recursively unwrapped.\n *\n * @see {@link UnwrappedOption}\n */\ntype UnUnwrappables =\n | string\n | number\n | boolean\n | symbol\n | bigint\n | undefined\n | null\n | Uint8Array\n | Int8Array\n | Uint16Array\n | Int16Array\n | Uint32Array\n | Int32Array\n | Date;\n\n/**\n * A type that defines the recursive unwrapping of a type `T`\n * such that all nested {@link Option} types are unwrapped.\n *\n * For each nested {@link Option} type, if the option is a {@link Some},\n * it returns the type of its value, otherwise, it returns the provided\n * fallback type `U` which defaults to `null`.\n */\nexport type UnwrappedOption<T, U = null> = T extends Some<infer TValue>\n ? UnwrappedOption<TValue, U>\n : T extends None\n ? U\n : T extends UnUnwrappables\n ? T\n : T extends object\n ? { [key in keyof T]: UnwrappedOption<T[key], U> }\n : T extends Array<infer TItem>\n ? Array<UnwrappedOption<TItem, U>>\n : T;\n\n/**\n * Recursively go through a type `T` such that all\n * nested {@link Option} types are unwrapped.\n *\n * For each nested {@link Option} type, if the option is a {@link Some},\n * it returns its value, otherwise, it returns the provided fallback value\n * which defaults to `null`.\n */\nexport function unwrapOptionRecursively<T>(input: T): UnwrappedOption<T>;\nexport function unwrapOptionRecursively<T, U>(input: T, fallback: () => U): UnwrappedOption<T, U>;\nexport function unwrapOptionRecursively<T, U = null>(input: T, fallback?: () => U): UnwrappedOption<T, U> {\n // Types to bypass.\n if (!input || ArrayBuffer.isView(input)) {\n return input as UnwrappedOption<T, U>;\n }\n\n const next = <X>(x: X) =>\n (fallback ? unwrapOptionRecursively(x, fallback) : unwrapOptionRecursively(x)) as UnwrappedOption<X, U>;\n\n // Handle Option.\n if (isOption(input)) {\n if (isSome(input)) return next(input.value) as UnwrappedOption<T, U>;\n return (fallback ? fallback() : null) as UnwrappedOption<T, U>;\n }\n\n // Walk.\n if (Array.isArray(input)) {\n return input.map(next) as UnwrappedOption<T, U>;\n }\n if (typeof input === 'object') {\n return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, next(v)])) as UnwrappedOption<T, U>;\n }\n return input as UnwrappedOption<T, U>;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { fixBytes, mergeBytes, combineCodec, assertFixedSizeCodec } from '@solana/codecs-core';
1
+ import { isFixedSize, assertIsFixedSize, createEncoder, getEncodedSize, createDecoder, combineCodec } from '@solana/codecs-core';
2
2
  import { getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
3
3
 
4
4
  // src/option.ts
@@ -17,61 +17,75 @@ function unwrapOption(option, fallback) {
17
17
  var wrapNullable = (nullable) => nullable !== null ? some(nullable) : none();
18
18
 
19
19
  // src/option-codec.ts
20
- function sumCodecSizes(sizes) {
21
- return sizes.reduce((all, size) => all === null || size === null ? null : all + size, 0);
22
- }
23
- function optionCodecHelper(item, prefix, fixed, description) {
24
- let descriptionSuffix = `; ${prefix.description}`;
25
- let fixedSize = item.fixedSize === 0 ? prefix.fixedSize : null;
26
- if (fixed) {
27
- assertFixedSizeCodec(item, "Fixed options can only be used with fixed-size codecs.");
28
- assertFixedSizeCodec(prefix, "Fixed options can only be used with fixed-size prefix.");
29
- descriptionSuffix += "; fixed";
30
- fixedSize = prefix.fixedSize + item.fixedSize;
20
+ function getOptionEncoder(item, config = {}) {
21
+ const prefix = config.prefix ?? getU8Encoder();
22
+ const fixed = config.fixed ?? false;
23
+ const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
24
+ if (fixed || isZeroSizeItem) {
25
+ assertIsFixedSize(item, "Fixed options can only be used with fixed-size codecs.");
26
+ assertIsFixedSize(prefix, "Fixed options can only be used with fixed-size prefix.");
27
+ const fixedSize = prefix.fixedSize + item.fixedSize;
28
+ return createEncoder({
29
+ fixedSize,
30
+ write: (optionOrNullable, bytes, offset) => {
31
+ const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
32
+ const prefixOffset = prefix.write(Number(isSome(option)), bytes, offset);
33
+ if (isSome(option)) {
34
+ item.write(option.value, bytes, prefixOffset);
35
+ }
36
+ return offset + fixedSize;
37
+ }
38
+ });
31
39
  }
32
- return {
33
- description: description ?? `option(${item.description + descriptionSuffix})`,
34
- fixedSize,
35
- maxSize: sumCodecSizes([prefix.maxSize, item.maxSize])
36
- };
37
- }
38
- function getOptionEncoder(item, options = {}) {
39
- const prefix = options.prefix ?? getU8Encoder();
40
- const fixed = options.fixed ?? false;
41
- return {
42
- ...optionCodecHelper(item, prefix, fixed, options.description),
43
- encode: (optionOrNullable) => {
40
+ return createEncoder({
41
+ getSizeFromValue: (optionOrNullable) => {
42
+ const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
43
+ return getEncodedSize(Number(isSome(option)), prefix) + (isSome(option) ? getEncodedSize(option.value, item) : 0);
44
+ },
45
+ maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? void 0,
46
+ write: (optionOrNullable, bytes, offset) => {
44
47
  const option = isOption(optionOrNullable) ? optionOrNullable : wrapNullable(optionOrNullable);
45
- const prefixByte = prefix.encode(Number(isSome(option)));
46
- let itemBytes = isSome(option) ? item.encode(option.value) : new Uint8Array();
47
- itemBytes = fixed ? fixBytes(itemBytes, item.fixedSize) : itemBytes;
48
- return mergeBytes([prefixByte, itemBytes]);
48
+ offset = prefix.write(Number(isSome(option)), bytes, offset);
49
+ if (isSome(option)) {
50
+ offset = item.write(option.value, bytes, offset);
51
+ }
52
+ return offset;
49
53
  }
50
- };
54
+ });
51
55
  }
52
- function getOptionDecoder(item, options = {}) {
53
- const prefix = options.prefix ?? getU8Decoder();
54
- const fixed = options.fixed ?? false;
55
- return {
56
- ...optionCodecHelper(item, prefix, fixed, options.description),
57
- decode: (bytes, offset = 0) => {
56
+ function getOptionDecoder(item, config = {}) {
57
+ const prefix = config.prefix ?? getU8Decoder();
58
+ const fixed = config.fixed ?? false;
59
+ let fixedSize = null;
60
+ const isZeroSizeItem = isFixedSize(item) && isFixedSize(prefix) && item.fixedSize === 0;
61
+ if (fixed || isZeroSizeItem) {
62
+ assertIsFixedSize(item, "Fixed options can only be used with fixed-size codecs.");
63
+ assertIsFixedSize(prefix, "Fixed options can only be used with fixed-size prefix.");
64
+ fixedSize = prefix.fixedSize + item.fixedSize;
65
+ }
66
+ return createDecoder({
67
+ ...fixedSize === null ? { maxSize: sumCodecSizes([prefix, item].map(getMaxSize)) ?? void 0 } : { fixedSize },
68
+ read: (bytes, offset) => {
58
69
  if (bytes.length - offset <= 0) {
59
70
  return [none(), offset];
60
71
  }
61
- const fixedOffset = offset + (prefix.fixedSize ?? 0) + (item.fixedSize ?? 0);
62
- const [isSome2, prefixOffset] = prefix.decode(bytes, offset);
63
- offset = prefixOffset;
72
+ const [isSome2, prefixOffset] = prefix.read(bytes, offset);
64
73
  if (isSome2 === 0) {
65
- return [none(), fixed ? fixedOffset : offset];
74
+ return [none(), fixedSize !== null ? offset + fixedSize : prefixOffset];
66
75
  }
67
- const [value, newOffset] = item.decode(bytes, offset);
68
- offset = newOffset;
69
- return [some(value), fixed ? fixedOffset : offset];
76
+ const [value, newOffset] = item.read(bytes, prefixOffset);
77
+ return [some(value), fixedSize !== null ? offset + fixedSize : newOffset];
70
78
  }
71
- };
79
+ });
80
+ }
81
+ function getOptionCodec(item, config = {}) {
82
+ return combineCodec(getOptionEncoder(item, config), getOptionDecoder(item, config));
83
+ }
84
+ function sumCodecSizes(sizes) {
85
+ return sizes.reduce((all, size) => all === null || size === null ? null : all + size, 0);
72
86
  }
73
- function getOptionCodec(item, options = {}) {
74
- return combineCodec(getOptionEncoder(item, options), getOptionDecoder(item, options));
87
+ function getMaxSize(codec) {
88
+ return isFixedSize(codec) ? codec.fixedSize : codec.maxSize ?? null;
75
89
  }
76
90
 
77
91
  // src/unwrap-option-recursively.ts
@@ -95,5 +109,3 @@ function unwrapOptionRecursively(input, fallback) {
95
109
  }
96
110
 
97
111
  export { getOptionCodec, getOptionDecoder, getOptionEncoder, isNone, isOption, isSome, none, some, unwrapOption, unwrapOptionRecursively, wrapNullable };
98
- //# sourceMappingURL=out.js.map
99
- //# sourceMappingURL=index.native.js.map