@solana/options 2.0.0-20241006045741

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.
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2023 Solana Labs, Inc
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,234 @@
1
+ [![npm][npm-image]][npm-url]
2
+ [![npm-downloads][npm-downloads-image]][npm-url]
3
+ [![semantic-release][semantic-release-image]][semantic-release-url]
4
+ <br />
5
+ [![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]
6
+
7
+ [code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
8
+ [code-style-prettier-url]: https://github.com/prettier/prettier
9
+ [npm-downloads-image]: https://img.shields.io/npm/dm/@solana/options/rc.svg?style=flat
10
+ [npm-image]: https://img.shields.io/npm/v/@solana/options/rc.svg?style=flat
11
+ [npm-url]: https://www.npmjs.com/package/@solana/options/v/rc
12
+ [semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
13
+ [semantic-release-url]: https://github.com/semantic-release/semantic-release
14
+
15
+ # @solana/options
16
+
17
+ This package allows us to manage and serialize Rust-like Option types in JavaScript. It can be used standalone, but it is also exported as part of the Solana JavaScript SDK [`@solana/web3.js@rc`](https://github.com/solana-labs/solana-web3.js/tree/master/packages/library).
18
+
19
+ This package is also part of the [`@solana/codecs` package](https://github.com/solana-labs/solana-web3.js/tree/master/packages/codecs) which acts as an entry point for all codec packages as well as for their documentation.
20
+
21
+ ## Creating options
22
+
23
+ In Rust, we define optional values as an `Option<T>` type which can either be `Some(T)` or `None`. This is usually represented as `T | null` in the JavaScript world. The issue with this approach is it doesn't work with nested options. For instance, an `Option<Option<T>>` in Rust would become a `T | null | null` in JavaScript which is equivalent to `T | null`. That means, there is no way for us to represent the `Some(None)` value in JavaScript or any other nested option.
24
+
25
+ To solve this issue, this library provides an `Option<T>` union type that works very similarly to the Rust `Option<T>` type. It is defined as follows:
26
+
27
+ ```ts
28
+ type Option<T> = Some<T> | None;
29
+ type Some<T> = { __option: 'Some'; value: T };
30
+ type None = { __option: 'None' };
31
+ ```
32
+
33
+ To improve the developer experience, helper functions are available to help you create options. The type `T` of the option can either be inferred by TypeScript or explicitly provided.
34
+
35
+ ```ts
36
+ // Create an option with a value.
37
+ some('Hello World');
38
+ some<number | string>(123);
39
+
40
+ // Create an empty option.
41
+ none();
42
+ none<number | string>();
43
+ ```
44
+
45
+ ## Option helpers
46
+
47
+ This library also provides helper functions to help us identify and manage `Option` types.
48
+
49
+ For instance, you can use the `isSome` and `isNone` type guards to check whether a given `Option` is of the desired type.
50
+
51
+ ```ts
52
+ isSome(some('Hello World')); // true
53
+ isSome(none()); // false
54
+
55
+ isNone(some('Hello World')); // false
56
+ isNone(none()); // true
57
+ ```
58
+
59
+ If you are given a type `T | null`, you may also use the `wrapNullable` helper function to transform it into an `Option<T>` type.
60
+
61
+ ```ts
62
+ wrapNullable('Hello world'); // Some<string>
63
+ wrapNullable(null); // None
64
+ ```
65
+
66
+ ## Unwrapping options
67
+
68
+ Several helpers are available to help you unwrap your options and access their potential value. For instance, the `unwrapOption` function transforms an `Option<T>` type into `T` if the value exits and `null` otherwise.
69
+
70
+ ```ts
71
+ unwrapOption(some('Hello World')); // "Hello World"
72
+ unwrapOption(none()); // null
73
+ ```
74
+
75
+ If `null` isn’t the value you want to use for `None` options, you may provide a custom fallback function as the second argument. Its return value will be assigned to `None` options.
76
+
77
+ ```ts
78
+ unwrapOption(some('Hello World'), () => 'Default'); // "Hello World"
79
+ unwrapOption(none(), () => 'Default'); // "Default"
80
+ ```
81
+
82
+ Note that this `unwrapOption` function does not recursively unwrap nested options. You may use the `unwrapOptionRecursively` function for that purpose instead.
83
+
84
+ ```ts
85
+ unwrapOptionRecursively(some(some(some('Hello World')))); // "Hello World"
86
+ unwrapOptionRecursively(some(some(none<string>()))); // null
87
+ ```
88
+
89
+ The `unwrapOptionRecursively` function also walks any object and array it encounters and recursively unwraps any option it identifies in its journey without mutating any object or array.
90
+
91
+ ```ts
92
+ unwrapOptionRecursively({
93
+ a: 'hello',
94
+ b: none(),
95
+ c: [{ c1: some(42) }, { c2: none() }],
96
+ });
97
+ // { a: "hello", b: null, c: [{ c1: 42 }, { c2: null }] }
98
+ ```
99
+
100
+ The `unwrapOptionRecursively` also accepts a fallback function as a second argument to provide custom values for `None` options.
101
+
102
+ ```ts
103
+ unwrapOptionRecursively(
104
+ {
105
+ a: 'hello',
106
+ b: none(),
107
+ c: [{ c1: some(42) }, { c2: none() }],
108
+ },
109
+ () => 'Default',
110
+ );
111
+ // { a: "hello", b: "Default", c: [{ c1: 42 }, { c2: "Default" }] }
112
+ ```
113
+
114
+ ## Option codec
115
+
116
+ The `getOptionCodec` function behaves exactly the same as the [`getNullableCodec`](https://github.com/solana-labs/solana-web3.js/tree/master/packages/codecs-data-structures#nullable-codec) except that it encodes `Option<T>` types instead of `T | null` types.
117
+
118
+ Namely, it accepts a codec of type `T` and returns a codec of type `Option<T>`. Note that, when encoding, `T` or `null` may also be provided directly as input and will be interpreted as `Some(T)` or `None` respectively. However, when decoding, the output will always be an `Option<T>` type.
119
+
120
+ It stores whether or not the item exists as a boolean prefix using a `u8` by default.
121
+
122
+ ```ts
123
+ const stringCodec = addCodecSizePrefix(getUtf8Codec(), getU32Codec());
124
+
125
+ getOptionCodec(stringCodec).encode('Hi');
126
+ getOptionCodec(stringCodec).encode(some('Hi'));
127
+ // 0x01020000004869
128
+ // | | └-- utf8 string content ("Hi").
129
+ // | └-- u32 string prefix (2 characters).
130
+ // └-- 1-byte prefix (Some).
131
+
132
+ getOptionCodec(stringCodec).encode(null);
133
+ getOptionCodec(stringCodec).encode(none());
134
+ // 0x00
135
+ // └-- 1-byte prefix (None).
136
+ ```
137
+
138
+ You may provide a number codec as the `prefix` option of the `getOptionCodec` function to configure how to store the boolean prefix.
139
+
140
+ ```ts
141
+ const u32OptionStringCodec = getOptionCodec(stringCodec, {
142
+ prefix: getU32Codec(),
143
+ });
144
+
145
+ u32OptionStringCodec.encode(some('Hi'));
146
+ // 0x01000000020000004869
147
+ // └------┘ 4-byte prefix (Some).
148
+
149
+ u32OptionStringCodec.encode(none());
150
+ // 0x00000000
151
+ // └------┘ 4-byte prefix (None).
152
+ ```
153
+
154
+ Additionally, if the item is a `FixedSizeCodec`, you may set the `noneValue` option to `"zeroes"` to also make the returned Option codec a `FixedSizeCodec`. To do so, it will pad `None` values with zeroes to match the length of existing values.
155
+
156
+ ```ts
157
+ const codec = getOptionCodec(
158
+ fixCodecSize(getUtf8Codec(), 8), // Only works with fixed-size items.
159
+ { noneValue: 'zeroes' },
160
+ );
161
+
162
+ codec.encode(some('Hi'));
163
+ // 0x014869000000000000
164
+ // | └-- 8-byte utf8 string content ("Hi").
165
+ // └-- 1-byte prefix (Some).
166
+
167
+ codec.encode(none());
168
+ // 0x000000000000000000
169
+ // | └-- 8-byte of padding to make a fixed-size codec.
170
+ // └-- 1-byte prefix (None).
171
+ ```
172
+
173
+ The `noneValue` option can also be set to an explicit byte array to use as the padding for `None` values. Note that, in this case, the returned codec will not be a `FixedSizeCodec` as the byte array representing `None` values may be of any length.
174
+
175
+ ```ts
176
+ const codec = getOptionCodec(getUtf8Codec(), {
177
+ noneValue: new Uint8Array([255]), // 0xff means None.
178
+ });
179
+
180
+ codec.encode(some('Hi'));
181
+ // 0x014869
182
+ // | └-- 2-byte utf8 string content ("Hi").
183
+ // └-- 1-byte prefix (Some).
184
+
185
+ codec.encode(none());
186
+ // 0x00ff
187
+ // | └-- 1-byte representing None (0xff).
188
+ // └-- 1-byte prefix (None).
189
+ ```
190
+
191
+ Last but not least, the `prefix` option of the `getOptionCodec` function can also be set to `null`, meaning no prefix will be used to determine whether the item exists. In this case, the codec will rely on the `noneValue` option to determine whether the item is `None`.
192
+
193
+ ```ts
194
+ const codecWithZeroNoneValue = getOptionCodec(getU16Codec(), {
195
+ noneValue: 'zeroes', // 0x0000 means None.
196
+ prefix: null,
197
+ });
198
+ codecWithZeroNoneValue.encode(some(42)); // 0x2a00
199
+ codecWithZeroNoneValue.encode(none()); // 0x0000
200
+
201
+ const codecWithCustomNoneValue = getOptionCodec(getU16Codec(), {
202
+ noneValue: new Uint8Array([255]), // 0xff means None.
203
+ prefix: null,
204
+ });
205
+ codecWithCustomNoneValue.encode(some(42)); // 0x2a00
206
+ codecWithCustomNoneValue.encode(none()); // 0xff
207
+ ```
208
+
209
+ Finally, note that if `prefix` is set to `null` and no `noneValue` is provided, the codec assume that the item exists if and only if some remaining bytes are available to decode. This could be useful to describe data structures that may or may not have additional data to the end of the buffer.
210
+
211
+ ```ts
212
+ const codec = getOptionCodec(getU16Codec(), { prefix: null });
213
+ codec.encode(some(42)); // 0x2a00
214
+ codec.encode(none()); // Encodes nothing.
215
+ codec.decode(new Uint8Array([42, 0])); // some(42)
216
+ codec.decode(new Uint8Array([])); // none()
217
+ ```
218
+
219
+ To recap, here are all the possible configurations of the `getOptionCodec` function, using a `u16` codec as an example.
220
+
221
+ | `encode(some(42))` / `encode(none())` | No `noneValue` (default) | `noneValue: "zeroes"` | Custom `noneValue` (`0xff`) |
222
+ | ------------------------------------- | ------------------------ | --------------------------- | --------------------------- |
223
+ | `u8` prefix (default) | `0x012a00` / `0x00` | `0x012a00` / `0x000000` | `0x012a00` / `0x00ff` |
224
+ | Custom `prefix` (`u16`) | `0x01002a00` / `0x0000` | `0x01002a00` / `0x00000000` | `0x01002a00` / `0x0000ff` |
225
+ | No `prefix` | `0x2a00` / `0x` | `0x2a00` / `0x0000` | `0x2a00` / `0xff` |
226
+
227
+ Separate `getOptionEncoder` and `getOptionDecoder` functions are also available.
228
+
229
+ ```ts
230
+ const bytes = getOptionEncoder(getU32Encoder()).encode(some(42));
231
+ const value = getOptionDecoder(getU32Decoder()).decode(bytes);
232
+ ```
233
+
234
+ To read more about the available codecs and how to use them, check out the documentation of the main [`@solana/codecs` package](https://github.com/solana-labs/solana-web3.js/tree/master/packages/codecs).
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ var codecsCore = require('@solana/codecs-core');
4
+ var codecsDataStructures = require('@solana/codecs-data-structures');
5
+ var codecsNumbers = require('@solana/codecs-numbers');
6
+
7
+ // src/option.ts
8
+ var some = (value) => ({ __option: "Some", value });
9
+ var none = () => ({ __option: "None" });
10
+ var isOption = (input) => !!(input && typeof input === "object" && "__option" in input && (input.__option === "Some" && "value" in input || input.__option === "None"));
11
+ var isSome = (option) => option.__option === "Some";
12
+ var isNone = (option) => option.__option === "None";
13
+
14
+ // src/unwrap-option.ts
15
+ function unwrapOption(option, fallback) {
16
+ if (isSome(option)) return option.value;
17
+ return fallback ? fallback() : null;
18
+ }
19
+ var wrapNullable = (nullable) => nullable !== null ? some(nullable) : none();
20
+
21
+ // src/option-codec.ts
22
+ function getOptionEncoder(item, config = {}) {
23
+ const prefix = (() => {
24
+ if (config.prefix === null) {
25
+ return codecsCore.transformEncoder(codecsDataStructures.getUnitEncoder(), (_boolean) => void 0);
26
+ }
27
+ return codecsDataStructures.getBooleanEncoder({ size: config.prefix ?? codecsNumbers.getU8Encoder() });
28
+ })();
29
+ const noneValue = (() => {
30
+ if (config.noneValue === "zeroes") {
31
+ codecsCore.assertIsFixedSize(item);
32
+ return codecsCore.fixEncoderSize(codecsDataStructures.getUnitEncoder(), item.fixedSize);
33
+ }
34
+ if (!config.noneValue) {
35
+ return codecsDataStructures.getUnitEncoder();
36
+ }
37
+ return codecsDataStructures.getConstantEncoder(config.noneValue);
38
+ })();
39
+ return codecsDataStructures.getUnionEncoder(
40
+ [
41
+ codecsCore.transformEncoder(codecsDataStructures.getTupleEncoder([prefix, noneValue]), (_value) => [
42
+ false,
43
+ void 0
44
+ ]),
45
+ codecsCore.transformEncoder(codecsDataStructures.getTupleEncoder([prefix, item]), (value) => [
46
+ true,
47
+ isOption(value) && isSome(value) ? value.value : value
48
+ ])
49
+ ],
50
+ (variant) => {
51
+ const option = isOption(variant) ? variant : wrapNullable(variant);
52
+ return Number(isSome(option));
53
+ }
54
+ );
55
+ }
56
+ function getOptionDecoder(item, config = {}) {
57
+ const prefix = (() => {
58
+ if (config.prefix === null) {
59
+ return codecsCore.transformDecoder(codecsDataStructures.getUnitDecoder(), () => false);
60
+ }
61
+ return codecsDataStructures.getBooleanDecoder({ size: config.prefix ?? codecsNumbers.getU8Decoder() });
62
+ })();
63
+ const noneValue = (() => {
64
+ if (config.noneValue === "zeroes") {
65
+ codecsCore.assertIsFixedSize(item);
66
+ return codecsCore.fixDecoderSize(codecsDataStructures.getUnitDecoder(), item.fixedSize);
67
+ }
68
+ if (!config.noneValue) {
69
+ return codecsDataStructures.getUnitDecoder();
70
+ }
71
+ return codecsDataStructures.getConstantDecoder(config.noneValue);
72
+ })();
73
+ return codecsDataStructures.getUnionDecoder(
74
+ [
75
+ codecsCore.transformDecoder(codecsDataStructures.getTupleDecoder([prefix, noneValue]), () => none()),
76
+ codecsCore.transformDecoder(codecsDataStructures.getTupleDecoder([prefix, item]), ([, value]) => some(value))
77
+ ],
78
+ (bytes, offset) => {
79
+ if (config.prefix === null && !config.noneValue) {
80
+ return Number(offset < bytes.length);
81
+ }
82
+ if (config.prefix === null && config.noneValue != null) {
83
+ const zeroValue = config.noneValue === "zeroes" ? new Uint8Array(noneValue.fixedSize).fill(0) : config.noneValue;
84
+ return codecsCore.containsBytes(bytes, zeroValue, offset) ? 0 : 1;
85
+ }
86
+ return Number(prefix.read(bytes, offset)[0]);
87
+ }
88
+ );
89
+ }
90
+ function getOptionCodec(item, config = {}) {
91
+ return codecsCore.combineCodec(
92
+ getOptionEncoder(item, config),
93
+ getOptionDecoder(item, config)
94
+ );
95
+ }
96
+
97
+ // src/unwrap-option-recursively.ts
98
+ function unwrapOptionRecursively(input, fallback) {
99
+ if (!input || ArrayBuffer.isView(input)) {
100
+ return input;
101
+ }
102
+ const next = (x) => fallback ? unwrapOptionRecursively(x, fallback) : unwrapOptionRecursively(x);
103
+ if (isOption(input)) {
104
+ if (isSome(input)) return next(input.value);
105
+ return fallback ? fallback() : null;
106
+ }
107
+ if (Array.isArray(input)) {
108
+ return input.map(next);
109
+ }
110
+ if (typeof input === "object") {
111
+ return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, next(v)]));
112
+ }
113
+ return input;
114
+ }
115
+
116
+ exports.getOptionCodec = getOptionCodec;
117
+ exports.getOptionDecoder = getOptionDecoder;
118
+ exports.getOptionEncoder = getOptionEncoder;
119
+ exports.isNone = isNone;
120
+ exports.isOption = isOption;
121
+ exports.isSome = isSome;
122
+ exports.none = none;
123
+ exports.some = some;
124
+ exports.unwrapOption = unwrapOption;
125
+ exports.unwrapOptionRecursively = unwrapOptionRecursively;
126
+ exports.wrapNullable = wrapNullable;
127
+ //# sourceMappingURL=index.browser.cjs.map
128
+ //# sourceMappingURL=index.browser.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/option.ts","../src/unwrap-option.ts","../src/option-codec.ts","../src/unwrap-option-recursively.ts"],"names":["transformEncoder","getUnitEncoder","getBooleanEncoder","getU8Encoder","assertIsFixedSize","fixEncoderSize","getConstantEncoder","getUnionEncoder","getTupleEncoder","transformDecoder","getUnitDecoder","getBooleanDecoder","getU8Decoder","fixDecoderSize","getConstantDecoder","getUnionDecoder","getTupleDecoder","containsBytes","combineCodec"],"mappings":"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","file":"index.browser.cjs","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> = None | Some<T>;\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 { 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 containsBytes,\n Decoder,\n Encoder,\n fixDecoderSize,\n FixedSizeCodec,\n FixedSizeDecoder,\n FixedSizeEncoder,\n fixEncoderSize,\n ReadonlyUint8Array,\n transformDecoder,\n transformEncoder,\n VariableSizeCodec,\n VariableSizeDecoder,\n VariableSizeEncoder,\n} from '@solana/codecs-core';\nimport {\n getBooleanDecoder,\n getBooleanEncoder,\n getConstantDecoder,\n getConstantEncoder,\n getTupleDecoder,\n getTupleEncoder,\n getUnionDecoder,\n getUnionEncoder,\n getUnitDecoder,\n getUnitEncoder,\n} from '@solana/codecs-data-structures';\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, none, Option, OptionOrNullable, Some, some } from './option';\nimport { wrapNullable } from './unwrap-option';\n\n/** Defines the config for Option codecs. */\nexport type OptionCodecConfig<TPrefix extends NumberCodec | NumberDecoder | NumberEncoder> = {\n /**\n * Defines how the `None` value should be represented.\n *\n * By default, no none value is used. This means a `None` value will be\n * represented by the absence of the item.\n *\n * When `'zeroes'` is provided, a `None` value will skip the bytes that would\n * have been used for the item. Note that this returns a fixed-size codec\n * and thus will only work if the item codec is of fixed size.\n *\n * When a custom byte array is provided, a `None` value will be represented\n * by the provided byte array. Note that this returns a variable-size codec\n * since the byte array representing `None` does not need to match the size\n * of the item codec.\n *\n * @defaultValue No none value is used.\n */\n noneValue?: ReadonlyUint8Array | 'zeroes';\n\n /**\n * The codec to use for the boolean prefix, if any.\n *\n * By default a `u8` number is used as a prefix to determine if the value is `None`.\n * The value `0` is encoded for `None` and `1` if the value is present.\n * This can be set to any number codec to customize the prefix.\n *\n * When `null` is provided, no prefix is used and the `noneValue` is used to\n * determine if the value is `None`. If no `noneValue` is provided, then the\n * absence of any bytes is used to determine if the value is `None`.\n *\n * @defaultValue `u8` prefix.\n */\n prefix?: TPrefix | null;\n};\n\n/**\n * Creates a encoder for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeEncoder<TFrom, TSize>,\n config: OptionCodecConfig<NumberEncoder> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeEncoder<OptionOrNullable<TFrom>, TSize>;\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom>,\n config: OptionCodecConfig<FixedSizeNumberEncoder> & { noneValue: 'zeroes' },\n): FixedSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom>,\n config: OptionCodecConfig<NumberEncoder> & { noneValue: 'zeroes' },\n): VariableSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config?: OptionCodecConfig<NumberEncoder> & { noneValue?: ReadonlyUint8Array },\n): VariableSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config: OptionCodecConfig<NumberEncoder> = {},\n): Encoder<OptionOrNullable<TFrom>> {\n const prefix = (() => {\n if (config.prefix === null) {\n return transformEncoder(getUnitEncoder(), (_boolean: boolean) => undefined);\n }\n return getBooleanEncoder({ size: config.prefix ?? getU8Encoder() });\n })();\n const noneValue = (() => {\n if (config.noneValue === 'zeroes') {\n assertIsFixedSize(item);\n return fixEncoderSize(getUnitEncoder(), item.fixedSize);\n }\n if (!config.noneValue) {\n return getUnitEncoder();\n }\n return getConstantEncoder(config.noneValue);\n })();\n\n return getUnionEncoder(\n [\n transformEncoder(getTupleEncoder([prefix, noneValue]), (_value: None | null): [boolean, void] => [\n false,\n undefined,\n ]),\n transformEncoder(getTupleEncoder([prefix, item]), (value: Some<TFrom> | TFrom): [boolean, TFrom] => [\n true,\n isOption(value) && isSome(value) ? value.value : value,\n ]),\n ],\n variant => {\n const option = isOption<TFrom>(variant) ? variant : wrapNullable(variant);\n return Number(isSome(option));\n },\n );\n}\n\n/**\n * Creates a decoder for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeDecoder<TTo, TSize>,\n config: OptionCodecConfig<NumberDecoder> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeDecoder<Option<TTo>, TSize>;\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo>,\n config: OptionCodecConfig<FixedSizeNumberDecoder> & { noneValue: 'zeroes' },\n): FixedSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo>,\n config: OptionCodecConfig<NumberDecoder> & { noneValue: 'zeroes' },\n): VariableSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config?: OptionCodecConfig<NumberDecoder> & { noneValue?: ReadonlyUint8Array },\n): VariableSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config: OptionCodecConfig<NumberDecoder> = {},\n): Decoder<Option<TTo>> {\n const prefix = (() => {\n if (config.prefix === null) {\n return transformDecoder(getUnitDecoder(), () => false);\n }\n return getBooleanDecoder({ size: config.prefix ?? getU8Decoder() });\n })();\n const noneValue = (() => {\n if (config.noneValue === 'zeroes') {\n assertIsFixedSize(item);\n return fixDecoderSize(getUnitDecoder(), item.fixedSize);\n }\n if (!config.noneValue) {\n return getUnitDecoder();\n }\n return getConstantDecoder(config.noneValue);\n })();\n\n return getUnionDecoder(\n [\n transformDecoder(getTupleDecoder([prefix, noneValue]), () => none<TTo>()),\n transformDecoder(getTupleDecoder([prefix, item]), ([, value]) => some(value)),\n ],\n (bytes, offset) => {\n if (config.prefix === null && !config.noneValue) {\n return Number(offset < bytes.length);\n }\n if (config.prefix === null && config.noneValue != null) {\n const zeroValue =\n config.noneValue === 'zeroes' ? new Uint8Array(noneValue.fixedSize).fill(0) : config.noneValue;\n return containsBytes(bytes, zeroValue, offset) ? 0 : 1;\n }\n return Number(prefix.read(bytes, offset)[0]);\n },\n );\n}\n\n/**\n * Creates a codec for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeCodec<TFrom, TTo, TSize>,\n config: OptionCodecConfig<NumberCodec> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>, TSize>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo>,\n config: OptionCodecConfig<FixedSizeNumberCodec> & { noneValue: 'zeroes' },\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo>,\n config: OptionCodecConfig<NumberCodec> & { noneValue: 'zeroes' },\n): VariableSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: Codec<TFrom, TTo>,\n config?: OptionCodecConfig<NumberCodec> & { noneValue?: ReadonlyUint8Array },\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 type ConfigCast = OptionCodecConfig<NumberCodec> & { noneValue?: ReadonlyUint8Array };\n return combineCodec(\n getOptionEncoder<TFrom>(item, config as ConfigCast),\n getOptionDecoder<TTo>(item, config as ConfigCast),\n );\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 | Date\n | Int8Array\n | Int16Array\n | Int32Array\n | Uint8Array\n | Uint16Array\n | Uint32Array\n | bigint\n | boolean\n | number\n | string\n | symbol\n | null\n | undefined;\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> =\n 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"]}
@@ -0,0 +1,116 @@
1
+ import { transformEncoder, assertIsFixedSize, fixEncoderSize, transformDecoder, fixDecoderSize, containsBytes, combineCodec } from '@solana/codecs-core';
2
+ import { getUnitEncoder, getBooleanEncoder, getConstantEncoder, getUnionEncoder, getTupleEncoder, getUnitDecoder, getBooleanDecoder, getConstantDecoder, getUnionDecoder, getTupleDecoder } from '@solana/codecs-data-structures';
3
+ import { getU8Encoder, getU8Decoder } from '@solana/codecs-numbers';
4
+
5
+ // src/option.ts
6
+ var some = (value) => ({ __option: "Some", value });
7
+ var none = () => ({ __option: "None" });
8
+ var isOption = (input) => !!(input && typeof input === "object" && "__option" in input && (input.__option === "Some" && "value" in input || input.__option === "None"));
9
+ var isSome = (option) => option.__option === "Some";
10
+ var isNone = (option) => option.__option === "None";
11
+
12
+ // src/unwrap-option.ts
13
+ function unwrapOption(option, fallback) {
14
+ if (isSome(option)) return option.value;
15
+ return fallback ? fallback() : null;
16
+ }
17
+ var wrapNullable = (nullable) => nullable !== null ? some(nullable) : none();
18
+
19
+ // src/option-codec.ts
20
+ function getOptionEncoder(item, config = {}) {
21
+ const prefix = (() => {
22
+ if (config.prefix === null) {
23
+ return transformEncoder(getUnitEncoder(), (_boolean) => void 0);
24
+ }
25
+ return getBooleanEncoder({ size: config.prefix ?? getU8Encoder() });
26
+ })();
27
+ const noneValue = (() => {
28
+ if (config.noneValue === "zeroes") {
29
+ assertIsFixedSize(item);
30
+ return fixEncoderSize(getUnitEncoder(), item.fixedSize);
31
+ }
32
+ if (!config.noneValue) {
33
+ return getUnitEncoder();
34
+ }
35
+ return getConstantEncoder(config.noneValue);
36
+ })();
37
+ return getUnionEncoder(
38
+ [
39
+ transformEncoder(getTupleEncoder([prefix, noneValue]), (_value) => [
40
+ false,
41
+ void 0
42
+ ]),
43
+ transformEncoder(getTupleEncoder([prefix, item]), (value) => [
44
+ true,
45
+ isOption(value) && isSome(value) ? value.value : value
46
+ ])
47
+ ],
48
+ (variant) => {
49
+ const option = isOption(variant) ? variant : wrapNullable(variant);
50
+ return Number(isSome(option));
51
+ }
52
+ );
53
+ }
54
+ function getOptionDecoder(item, config = {}) {
55
+ const prefix = (() => {
56
+ if (config.prefix === null) {
57
+ return transformDecoder(getUnitDecoder(), () => false);
58
+ }
59
+ return getBooleanDecoder({ size: config.prefix ?? getU8Decoder() });
60
+ })();
61
+ const noneValue = (() => {
62
+ if (config.noneValue === "zeroes") {
63
+ assertIsFixedSize(item);
64
+ return fixDecoderSize(getUnitDecoder(), item.fixedSize);
65
+ }
66
+ if (!config.noneValue) {
67
+ return getUnitDecoder();
68
+ }
69
+ return getConstantDecoder(config.noneValue);
70
+ })();
71
+ return getUnionDecoder(
72
+ [
73
+ transformDecoder(getTupleDecoder([prefix, noneValue]), () => none()),
74
+ transformDecoder(getTupleDecoder([prefix, item]), ([, value]) => some(value))
75
+ ],
76
+ (bytes, offset) => {
77
+ if (config.prefix === null && !config.noneValue) {
78
+ return Number(offset < bytes.length);
79
+ }
80
+ if (config.prefix === null && config.noneValue != null) {
81
+ const zeroValue = config.noneValue === "zeroes" ? new Uint8Array(noneValue.fixedSize).fill(0) : config.noneValue;
82
+ return containsBytes(bytes, zeroValue, offset) ? 0 : 1;
83
+ }
84
+ return Number(prefix.read(bytes, offset)[0]);
85
+ }
86
+ );
87
+ }
88
+ function getOptionCodec(item, config = {}) {
89
+ return combineCodec(
90
+ getOptionEncoder(item, config),
91
+ getOptionDecoder(item, config)
92
+ );
93
+ }
94
+
95
+ // src/unwrap-option-recursively.ts
96
+ function unwrapOptionRecursively(input, fallback) {
97
+ if (!input || ArrayBuffer.isView(input)) {
98
+ return input;
99
+ }
100
+ const next = (x) => fallback ? unwrapOptionRecursively(x, fallback) : unwrapOptionRecursively(x);
101
+ if (isOption(input)) {
102
+ if (isSome(input)) return next(input.value);
103
+ return fallback ? fallback() : null;
104
+ }
105
+ if (Array.isArray(input)) {
106
+ return input.map(next);
107
+ }
108
+ if (typeof input === "object") {
109
+ return Object.fromEntries(Object.entries(input).map(([k, v]) => [k, next(v)]));
110
+ }
111
+ return input;
112
+ }
113
+
114
+ export { getOptionCodec, getOptionDecoder, getOptionEncoder, isNone, isOption, isSome, none, some, unwrapOption, unwrapOptionRecursively, wrapNullable };
115
+ //# sourceMappingURL=index.browser.mjs.map
116
+ //# sourceMappingURL=index.browser.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/option.ts","../src/unwrap-option.ts","../src/option-codec.ts","../src/unwrap-option-recursively.ts"],"names":[],"mappings":";;;;;AAkCO,IAAM,OAAO,CAAI,KAAA,MAAyB,EAAE,QAAA,EAAU,QAAQ,KAAM,EAAA,EAAA;AAOpE,IAAM,IAAO,GAAA,OAAqB,EAAE,QAAA,EAAU,MAAO,EAAA,EAAA;AAKrD,IAAM,WAAW,CAAc,KAAA,KAClC,CAAC,EACG,SACA,OAAO,KAAA,KAAU,QACjB,IAAA,UAAA,IAAc,UACZ,KAAM,CAAA,QAAA,KAAa,UAAU,OAAW,IAAA,KAAA,IAAU,MAAM,QAAa,KAAA,MAAA,CAAA,EAAA;AAMxE,IAAM,MAAS,GAAA,CAAI,MAAyC,KAAA,MAAA,CAAO,QAAa,KAAA,OAAA;AAKhF,IAAM,MAAS,GAAA,CAAI,MAAsC,KAAA,MAAA,CAAO,QAAa,KAAA,OAAA;;;ACtD7E,SAAS,YAAA,CAA0B,QAAmB,QAA2B,EAAA;AACpF,EAAA,IAAI,MAAO,CAAA,MAAM,CAAG,EAAA,OAAO,MAAO,CAAA,KAAA,CAAA;AAClC,EAAO,OAAA,QAAA,GAAW,UAAc,GAAA,IAAA,CAAA;AACpC,CAAA;AAKa,IAAA,YAAA,GAAe,CAAI,QAAmC,KAAA,QAAA,KAAa,OAAO,IAAK,CAAA,QAAQ,IAAI,IAAQ,GAAA;;;ACwFzG,SAAS,gBACZ,CAAA,IAAA,EACA,MAA2C,GAAA,EACX,EAAA;AAChC,EAAA,MAAM,UAAU,MAAM;AAClB,IAAI,IAAA,MAAA,CAAO,WAAW,IAAM,EAAA;AACxB,MAAA,OAAO,gBAAiB,CAAA,cAAA,EAAkB,EAAA,CAAC,aAAsB,KAAS,CAAA,CAAA,CAAA;AAAA,KAC9E;AACA,IAAA,OAAO,kBAAkB,EAAE,IAAA,EAAM,OAAO,MAAU,IAAA,YAAA,IAAgB,CAAA,CAAA;AAAA,GACnE,GAAA,CAAA;AACH,EAAA,MAAM,aAAa,MAAM;AACrB,IAAI,IAAA,MAAA,CAAO,cAAc,QAAU,EAAA;AAC/B,MAAA,iBAAA,CAAkB,IAAI,CAAA,CAAA;AACtB,MAAA,OAAO,cAAe,CAAA,cAAA,EAAkB,EAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,KAC1D;AACA,IAAI,IAAA,CAAC,OAAO,SAAW,EAAA;AACnB,MAAA,OAAO,cAAe,EAAA,CAAA;AAAA,KAC1B;AACA,IAAO,OAAA,kBAAA,CAAmB,OAAO,SAAS,CAAA,CAAA;AAAA,GAC3C,GAAA,CAAA;AAEH,EAAO,OAAA,eAAA;AAAA,IACH;AAAA,MACI,gBAAA,CAAiB,gBAAgB,CAAC,MAAA,EAAQ,SAAS,CAAC,CAAA,EAAG,CAAC,MAAyC,KAAA;AAAA,QAC7F,KAAA;AAAA,QACA,KAAA,CAAA;AAAA,OACH,CAAA;AAAA,MACD,gBAAA,CAAiB,gBAAgB,CAAC,MAAA,EAAQ,IAAI,CAAC,CAAA,EAAG,CAAC,KAAiD,KAAA;AAAA,QAChG,IAAA;AAAA,QACA,SAAS,KAAK,CAAA,IAAK,OAAO,KAAK,CAAA,GAAI,MAAM,KAAQ,GAAA,KAAA;AAAA,OACpD,CAAA;AAAA,KACL;AAAA,IACA,CAAW,OAAA,KAAA;AACP,MAAA,MAAM,SAAS,QAAgB,CAAA,OAAO,CAAI,GAAA,OAAA,GAAU,aAAa,OAAO,CAAA,CAAA;AACxE,MAAO,OAAA,MAAA,CAAO,MAAO,CAAA,MAAM,CAAC,CAAA,CAAA;AAAA,KAChC;AAAA,GACJ,CAAA;AACJ,CAAA;AAwBO,SAAS,gBACZ,CAAA,IAAA,EACA,MAA2C,GAAA,EACvB,EAAA;AACpB,EAAA,MAAM,UAAU,MAAM;AAClB,IAAI,IAAA,MAAA,CAAO,WAAW,IAAM,EAAA;AACxB,MAAA,OAAO,gBAAiB,CAAA,cAAA,EAAkB,EAAA,MAAM,KAAK,CAAA,CAAA;AAAA,KACzD;AACA,IAAA,OAAO,kBAAkB,EAAE,IAAA,EAAM,OAAO,MAAU,IAAA,YAAA,IAAgB,CAAA,CAAA;AAAA,GACnE,GAAA,CAAA;AACH,EAAA,MAAM,aAAa,MAAM;AACrB,IAAI,IAAA,MAAA,CAAO,cAAc,QAAU,EAAA;AAC/B,MAAA,iBAAA,CAAkB,IAAI,CAAA,CAAA;AACtB,MAAA,OAAO,cAAe,CAAA,cAAA,EAAkB,EAAA,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,KAC1D;AACA,IAAI,IAAA,CAAC,OAAO,SAAW,EAAA;AACnB,MAAA,OAAO,cAAe,EAAA,CAAA;AAAA,KAC1B;AACA,IAAO,OAAA,kBAAA,CAAmB,OAAO,SAAS,CAAA,CAAA;AAAA,GAC3C,GAAA,CAAA;AAEH,EAAO,OAAA,eAAA;AAAA,IACH;AAAA,MACI,gBAAA,CAAiB,gBAAgB,CAAC,MAAA,EAAQ,SAAS,CAAC,CAAA,EAAG,MAAM,IAAA,EAAW,CAAA;AAAA,MACxE,gBAAiB,CAAA,eAAA,CAAgB,CAAC,MAAA,EAAQ,IAAI,CAAC,CAAA,EAAG,CAAC,GAAG,KAAK,CAAM,KAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,KAChF;AAAA,IACA,CAAC,OAAO,MAAW,KAAA;AACf,MAAA,IAAI,MAAO,CAAA,MAAA,KAAW,IAAQ,IAAA,CAAC,OAAO,SAAW,EAAA;AAC7C,QAAO,OAAA,MAAA,CAAO,MAAS,GAAA,KAAA,CAAM,MAAM,CAAA,CAAA;AAAA,OACvC;AACA,MAAA,IAAI,MAAO,CAAA,MAAA,KAAW,IAAQ,IAAA,MAAA,CAAO,aAAa,IAAM,EAAA;AACpD,QAAA,MAAM,SACF,GAAA,MAAA,CAAO,SAAc,KAAA,QAAA,GAAW,IAAI,UAAA,CAAW,SAAU,CAAA,SAAS,CAAE,CAAA,IAAA,CAAK,CAAC,CAAA,GAAI,MAAO,CAAA,SAAA,CAAA;AACzF,QAAA,OAAO,aAAc,CAAA,KAAA,EAAO,SAAW,EAAA,MAAM,IAAI,CAAI,GAAA,CAAA,CAAA;AAAA,OACzD;AACA,MAAA,OAAO,OAAO,MAAO,CAAA,IAAA,CAAK,OAAO,MAAM,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA;AAAA,KAC/C;AAAA,GACJ,CAAA;AACJ,CAAA;AAwBO,SAAS,cACZ,CAAA,IAAA,EACA,MAAyC,GAAA,EACE,EAAA;AAE3C,EAAO,OAAA,YAAA;AAAA,IACH,gBAAA,CAAwB,MAAM,MAAoB,CAAA;AAAA,IAClD,gBAAA,CAAsB,MAAM,MAAoB,CAAA;AAAA,GACpD,CAAA;AACJ,CAAA;;;ACtLO,SAAS,uBAAA,CAAqC,OAAU,QAA2C,EAAA;AAEtG,EAAA,IAAI,CAAC,KAAA,IAAS,WAAY,CAAA,MAAA,CAAO,KAAK,CAAG,EAAA;AACrC,IAAO,OAAA,KAAA,CAAA;AAAA,GACX;AAEA,EAAM,MAAA,IAAA,GAAO,CAAI,CACZ,KAAA,QAAA,GAAW,wBAAwB,CAAG,EAAA,QAAQ,CAAI,GAAA,uBAAA,CAAwB,CAAC,CAAA,CAAA;AAGhF,EAAI,IAAA,QAAA,CAAS,KAAK,CAAG,EAAA;AACjB,IAAA,IAAI,OAAO,KAAK,CAAA,EAAU,OAAA,IAAA,CAAK,MAAM,KAAK,CAAA,CAAA;AAC1C,IAAQ,OAAA,QAAA,GAAW,UAAa,GAAA,IAAA,CAAA;AAAA,GACpC;AAGA,EAAI,IAAA,KAAA,CAAM,OAAQ,CAAA,KAAK,CAAG,EAAA;AACtB,IAAO,OAAA,KAAA,CAAM,IAAI,IAAI,CAAA,CAAA;AAAA,GACzB;AACA,EAAI,IAAA,OAAO,UAAU,QAAU,EAAA;AAC3B,IAAA,OAAO,OAAO,WAAY,CAAA,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,CAAG,EAAA,CAAC,MAAM,CAAC,CAAA,EAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA,CAAA;AAAA,GACjF;AACA,EAAO,OAAA,KAAA,CAAA;AACX","file":"index.browser.mjs","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> = None | Some<T>;\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 { 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 containsBytes,\n Decoder,\n Encoder,\n fixDecoderSize,\n FixedSizeCodec,\n FixedSizeDecoder,\n FixedSizeEncoder,\n fixEncoderSize,\n ReadonlyUint8Array,\n transformDecoder,\n transformEncoder,\n VariableSizeCodec,\n VariableSizeDecoder,\n VariableSizeEncoder,\n} from '@solana/codecs-core';\nimport {\n getBooleanDecoder,\n getBooleanEncoder,\n getConstantDecoder,\n getConstantEncoder,\n getTupleDecoder,\n getTupleEncoder,\n getUnionDecoder,\n getUnionEncoder,\n getUnitDecoder,\n getUnitEncoder,\n} from '@solana/codecs-data-structures';\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, none, Option, OptionOrNullable, Some, some } from './option';\nimport { wrapNullable } from './unwrap-option';\n\n/** Defines the config for Option codecs. */\nexport type OptionCodecConfig<TPrefix extends NumberCodec | NumberDecoder | NumberEncoder> = {\n /**\n * Defines how the `None` value should be represented.\n *\n * By default, no none value is used. This means a `None` value will be\n * represented by the absence of the item.\n *\n * When `'zeroes'` is provided, a `None` value will skip the bytes that would\n * have been used for the item. Note that this returns a fixed-size codec\n * and thus will only work if the item codec is of fixed size.\n *\n * When a custom byte array is provided, a `None` value will be represented\n * by the provided byte array. Note that this returns a variable-size codec\n * since the byte array representing `None` does not need to match the size\n * of the item codec.\n *\n * @defaultValue No none value is used.\n */\n noneValue?: ReadonlyUint8Array | 'zeroes';\n\n /**\n * The codec to use for the boolean prefix, if any.\n *\n * By default a `u8` number is used as a prefix to determine if the value is `None`.\n * The value `0` is encoded for `None` and `1` if the value is present.\n * This can be set to any number codec to customize the prefix.\n *\n * When `null` is provided, no prefix is used and the `noneValue` is used to\n * determine if the value is `None`. If no `noneValue` is provided, then the\n * absence of any bytes is used to determine if the value is `None`.\n *\n * @defaultValue `u8` prefix.\n */\n prefix?: TPrefix | null;\n};\n\n/**\n * Creates a encoder for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeEncoder<TFrom, TSize>,\n config: OptionCodecConfig<NumberEncoder> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeEncoder<OptionOrNullable<TFrom>, TSize>;\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom>,\n config: OptionCodecConfig<FixedSizeNumberEncoder> & { noneValue: 'zeroes' },\n): FixedSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: FixedSizeEncoder<TFrom>,\n config: OptionCodecConfig<NumberEncoder> & { noneValue: 'zeroes' },\n): VariableSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config?: OptionCodecConfig<NumberEncoder> & { noneValue?: ReadonlyUint8Array },\n): VariableSizeEncoder<OptionOrNullable<TFrom>>;\nexport function getOptionEncoder<TFrom>(\n item: Encoder<TFrom>,\n config: OptionCodecConfig<NumberEncoder> = {},\n): Encoder<OptionOrNullable<TFrom>> {\n const prefix = (() => {\n if (config.prefix === null) {\n return transformEncoder(getUnitEncoder(), (_boolean: boolean) => undefined);\n }\n return getBooleanEncoder({ size: config.prefix ?? getU8Encoder() });\n })();\n const noneValue = (() => {\n if (config.noneValue === 'zeroes') {\n assertIsFixedSize(item);\n return fixEncoderSize(getUnitEncoder(), item.fixedSize);\n }\n if (!config.noneValue) {\n return getUnitEncoder();\n }\n return getConstantEncoder(config.noneValue);\n })();\n\n return getUnionEncoder(\n [\n transformEncoder(getTupleEncoder([prefix, noneValue]), (_value: None | null): [boolean, void] => [\n false,\n undefined,\n ]),\n transformEncoder(getTupleEncoder([prefix, item]), (value: Some<TFrom> | TFrom): [boolean, TFrom] => [\n true,\n isOption(value) && isSome(value) ? value.value : value,\n ]),\n ],\n variant => {\n const option = isOption<TFrom>(variant) ? variant : wrapNullable(variant);\n return Number(isSome(option));\n },\n );\n}\n\n/**\n * Creates a decoder for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeDecoder<TTo, TSize>,\n config: OptionCodecConfig<NumberDecoder> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeDecoder<Option<TTo>, TSize>;\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo>,\n config: OptionCodecConfig<FixedSizeNumberDecoder> & { noneValue: 'zeroes' },\n): FixedSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: FixedSizeDecoder<TTo>,\n config: OptionCodecConfig<NumberDecoder> & { noneValue: 'zeroes' },\n): VariableSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config?: OptionCodecConfig<NumberDecoder> & { noneValue?: ReadonlyUint8Array },\n): VariableSizeDecoder<Option<TTo>>;\nexport function getOptionDecoder<TTo>(\n item: Decoder<TTo>,\n config: OptionCodecConfig<NumberDecoder> = {},\n): Decoder<Option<TTo>> {\n const prefix = (() => {\n if (config.prefix === null) {\n return transformDecoder(getUnitDecoder(), () => false);\n }\n return getBooleanDecoder({ size: config.prefix ?? getU8Decoder() });\n })();\n const noneValue = (() => {\n if (config.noneValue === 'zeroes') {\n assertIsFixedSize(item);\n return fixDecoderSize(getUnitDecoder(), item.fixedSize);\n }\n if (!config.noneValue) {\n return getUnitDecoder();\n }\n return getConstantDecoder(config.noneValue);\n })();\n\n return getUnionDecoder(\n [\n transformDecoder(getTupleDecoder([prefix, noneValue]), () => none<TTo>()),\n transformDecoder(getTupleDecoder([prefix, item]), ([, value]) => some(value)),\n ],\n (bytes, offset) => {\n if (config.prefix === null && !config.noneValue) {\n return Number(offset < bytes.length);\n }\n if (config.prefix === null && config.noneValue != null) {\n const zeroValue =\n config.noneValue === 'zeroes' ? new Uint8Array(noneValue.fixedSize).fill(0) : config.noneValue;\n return containsBytes(bytes, zeroValue, offset) ? 0 : 1;\n }\n return Number(prefix.read(bytes, offset)[0]);\n },\n );\n}\n\n/**\n * Creates a codec for an optional value using the `Option<T>` type.\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, TSize extends number>(\n item: FixedSizeCodec<TFrom, TTo, TSize>,\n config: OptionCodecConfig<NumberCodec> & { noneValue: 'zeroes'; prefix: null },\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>, TSize>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo>,\n config: OptionCodecConfig<FixedSizeNumberCodec> & { noneValue: 'zeroes' },\n): FixedSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: FixedSizeCodec<TFrom, TTo>,\n config: OptionCodecConfig<NumberCodec> & { noneValue: 'zeroes' },\n): VariableSizeCodec<OptionOrNullable<TFrom>, Option<TTo>>;\nexport function getOptionCodec<TFrom, TTo extends TFrom = TFrom>(\n item: Codec<TFrom, TTo>,\n config?: OptionCodecConfig<NumberCodec> & { noneValue?: ReadonlyUint8Array },\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 type ConfigCast = OptionCodecConfig<NumberCodec> & { noneValue?: ReadonlyUint8Array };\n return combineCodec(\n getOptionEncoder<TFrom>(item, config as ConfigCast),\n getOptionDecoder<TTo>(item, config as ConfigCast),\n );\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 | Date\n | Int8Array\n | Int16Array\n | Int32Array\n | Uint8Array\n | Uint16Array\n | Uint32Array\n | bigint\n | boolean\n | number\n | string\n | symbol\n | null\n | undefined;\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> =\n 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"]}