@solana/codecs-numbers 6.3.1 → 6.3.2-canary-20260313112147
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/package.json +5 -4
- package/src/assertions.ts +42 -0
- package/src/common.ts +94 -0
- package/src/f32.ts +104 -0
- package/src/f64.ts +104 -0
- package/src/i128.ts +121 -0
- package/src/i16.ts +105 -0
- package/src/i32.ts +105 -0
- package/src/i64.ts +108 -0
- package/src/i8.ts +91 -0
- package/src/index.ts +25 -0
- package/src/short-u16.ts +158 -0
- package/src/u128.ts +117 -0
- package/src/u16.ts +103 -0
- package/src/u32.ts +103 -0
- package/src/u64.ts +106 -0
- package/src/u8.ts +87 -0
- package/src/utils.ts +63 -0
package/src/i32.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';
|
|
2
|
+
|
|
3
|
+
import { NumberCodecConfig } from './common';
|
|
4
|
+
import { numberDecoderFactory, numberEncoderFactory } from './utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns an encoder for 32-bit signed integers (`i32`).
|
|
8
|
+
*
|
|
9
|
+
* This encoder serializes `i32` values using 4 bytes.
|
|
10
|
+
* Values can be provided as either `number` or `bigint`.
|
|
11
|
+
*
|
|
12
|
+
* For more details, see {@link getI32Codec}.
|
|
13
|
+
*
|
|
14
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
15
|
+
* @returns A `FixedSizeEncoder<number | bigint, 4>` for encoding `i32` values.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* Encoding an `i32` value.
|
|
19
|
+
* ```ts
|
|
20
|
+
* const encoder = getI32Encoder();
|
|
21
|
+
* const bytes = encoder.encode(-42); // 0xd6ffffff
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see {@link getI32Codec}
|
|
25
|
+
*/
|
|
26
|
+
export const getI32Encoder = (config: NumberCodecConfig = {}): FixedSizeEncoder<bigint | number, 4> =>
|
|
27
|
+
numberEncoderFactory({
|
|
28
|
+
config,
|
|
29
|
+
name: 'i32',
|
|
30
|
+
range: [-Number('0x7fffffff') - 1, Number('0x7fffffff')],
|
|
31
|
+
set: (view, value, le) => view.setInt32(0, Number(value), le),
|
|
32
|
+
size: 4,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns a decoder for 32-bit signed integers (`i32`).
|
|
37
|
+
*
|
|
38
|
+
* This decoder deserializes `i32` values from 4 bytes.
|
|
39
|
+
* The decoded value is always a `number`.
|
|
40
|
+
*
|
|
41
|
+
* For more details, see {@link getI32Codec}.
|
|
42
|
+
*
|
|
43
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
44
|
+
* @returns A `FixedSizeDecoder<number, 4>` for decoding `i32` values.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* Decoding an `i32` value.
|
|
48
|
+
* ```ts
|
|
49
|
+
* const decoder = getI32Decoder();
|
|
50
|
+
* const value = decoder.decode(new Uint8Array([0xd6, 0xff, 0xff, 0xff])); // -42
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @see {@link getI32Codec}
|
|
54
|
+
*/
|
|
55
|
+
export const getI32Decoder = (config: NumberCodecConfig = {}): FixedSizeDecoder<number, 4> =>
|
|
56
|
+
numberDecoderFactory({
|
|
57
|
+
config,
|
|
58
|
+
get: (view, le) => view.getInt32(0, le),
|
|
59
|
+
name: 'i32',
|
|
60
|
+
size: 4,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Returns a codec for encoding and decoding 32-bit signed integers (`i32`).
|
|
65
|
+
*
|
|
66
|
+
* This codec serializes `i32` values using 4 bytes.
|
|
67
|
+
* Values can be provided as either `number` or `bigint`, but the decoded value is always a `number`.
|
|
68
|
+
*
|
|
69
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
70
|
+
* @returns A `FixedSizeCodec<number | bigint, number, 4>` for encoding and decoding `i32` values.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* Encoding and decoding an `i32` value.
|
|
74
|
+
* ```ts
|
|
75
|
+
* const codec = getI32Codec();
|
|
76
|
+
* const bytes = codec.encode(-42); // 0xd6ffffff
|
|
77
|
+
* const value = codec.decode(bytes); // -42
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* Using big-endian encoding.
|
|
82
|
+
* ```ts
|
|
83
|
+
* const codec = getI32Codec({ endian: Endian.Big });
|
|
84
|
+
* const bytes = codec.encode(-42); // 0xffffffd6
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @remarks
|
|
88
|
+
* This codec supports values between `-2^31` (`-2,147,483,648`) and `2^31 - 1` (`2,147,483,647`).
|
|
89
|
+
*
|
|
90
|
+
* - If you need a smaller signed integer, consider using {@link getI16Codec} or {@link getI8Codec}.
|
|
91
|
+
* - If you need a larger signed integer, consider using {@link getI64Codec}.
|
|
92
|
+
* - If you need unsigned integers, consider using {@link getU32Codec}.
|
|
93
|
+
*
|
|
94
|
+
* Separate {@link getI32Encoder} and {@link getI32Decoder} functions are available.
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* const bytes = getI32Encoder().encode(-42);
|
|
98
|
+
* const value = getI32Decoder().decode(bytes);
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* @see {@link getI32Encoder}
|
|
102
|
+
* @see {@link getI32Decoder}
|
|
103
|
+
*/
|
|
104
|
+
export const getI32Codec = (config: NumberCodecConfig = {}): FixedSizeCodec<bigint | number, number, 4> =>
|
|
105
|
+
combineCodec(getI32Encoder(config), getI32Decoder(config));
|
package/src/i64.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';
|
|
2
|
+
|
|
3
|
+
import { NumberCodecConfig } from './common';
|
|
4
|
+
import { numberDecoderFactory, numberEncoderFactory } from './utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns an encoder for 64-bit signed integers (`i64`).
|
|
8
|
+
*
|
|
9
|
+
* This encoder serializes `i64` values using 8 bytes.
|
|
10
|
+
* Values can be provided as either `number` or `bigint`.
|
|
11
|
+
*
|
|
12
|
+
* For more details, see {@link getI64Codec}.
|
|
13
|
+
*
|
|
14
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
15
|
+
* @returns A `FixedSizeEncoder<number | bigint, 8>` for encoding `i64` values.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* Encoding an `i64` value.
|
|
19
|
+
* ```ts
|
|
20
|
+
* const encoder = getI64Encoder();
|
|
21
|
+
* const bytes = encoder.encode(-42n); // 0xd6ffffffffffffff
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see {@link getI64Codec}
|
|
25
|
+
*/
|
|
26
|
+
export const getI64Encoder = (config: NumberCodecConfig = {}): FixedSizeEncoder<bigint | number, 8> =>
|
|
27
|
+
numberEncoderFactory({
|
|
28
|
+
config,
|
|
29
|
+
name: 'i64',
|
|
30
|
+
range: [-BigInt('0x7fffffffffffffff') - 1n, BigInt('0x7fffffffffffffff')],
|
|
31
|
+
set: (view, value, le) => view.setBigInt64(0, BigInt(value), le),
|
|
32
|
+
size: 8,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns a decoder for 64-bit signed integers (`i64`).
|
|
37
|
+
*
|
|
38
|
+
* This decoder deserializes `i64` values from 8 bytes.
|
|
39
|
+
* The decoded value is always a `bigint`.
|
|
40
|
+
*
|
|
41
|
+
* For more details, see {@link getI64Codec}.
|
|
42
|
+
*
|
|
43
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
44
|
+
* @returns A `FixedSizeDecoder<bigint, 8>` for decoding `i64` values.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* Decoding an `i64` value.
|
|
48
|
+
* ```ts
|
|
49
|
+
* const decoder = getI64Decoder();
|
|
50
|
+
* const value = decoder.decode(new Uint8Array([
|
|
51
|
+
* 0xd6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
|
52
|
+
* ])); // -42n
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* @see {@link getI64Codec}
|
|
56
|
+
*/
|
|
57
|
+
export const getI64Decoder = (config: NumberCodecConfig = {}): FixedSizeDecoder<bigint, 8> =>
|
|
58
|
+
numberDecoderFactory({
|
|
59
|
+
config,
|
|
60
|
+
get: (view, le) => view.getBigInt64(0, le),
|
|
61
|
+
name: 'i64',
|
|
62
|
+
size: 8,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Returns a codec for encoding and decoding 64-bit signed integers (`i64`).
|
|
67
|
+
*
|
|
68
|
+
* This codec serializes `i64` values using 8 bytes.
|
|
69
|
+
* Values can be provided as either `number` or `bigint`, but the decoded value is always a `bigint`.
|
|
70
|
+
*
|
|
71
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
72
|
+
* @returns A `FixedSizeCodec<number | bigint, bigint, 8>` for encoding and decoding `i64` values.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* Encoding and decoding an `i64` value.
|
|
76
|
+
* ```ts
|
|
77
|
+
* const codec = getI64Codec();
|
|
78
|
+
* const bytes = codec.encode(-42n); // 0xd6ffffffffffffff
|
|
79
|
+
* const value = codec.decode(bytes); // -42n
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* Using big-endian encoding.
|
|
84
|
+
* ```ts
|
|
85
|
+
* const codec = getI64Codec({ endian: Endian.Big });
|
|
86
|
+
* const bytes = codec.encode(-42n); // 0xffffffffffffffd6
|
|
87
|
+
* ```
|
|
88
|
+
*
|
|
89
|
+
* @remarks
|
|
90
|
+
* This codec supports values between `-2^63` and `2^63 - 1`.
|
|
91
|
+
* Since JavaScript `number` cannot safely represent values beyond `2^53 - 1`, the decoded value is always a `bigint`.
|
|
92
|
+
*
|
|
93
|
+
* - If you need a smaller signed integer, consider using {@link getI32Codec} or {@link getI16Codec}.
|
|
94
|
+
* - If you need a larger signed integer, consider using {@link getI128Codec}.
|
|
95
|
+
* - If you need unsigned integers, consider using {@link getU64Codec}.
|
|
96
|
+
*
|
|
97
|
+
* Separate {@link getI64Encoder} and {@link getI64Decoder} functions are available.
|
|
98
|
+
*
|
|
99
|
+
* ```ts
|
|
100
|
+
* const bytes = getI64Encoder().encode(-42);
|
|
101
|
+
* const value = getI64Decoder().decode(bytes);
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @see {@link getI64Encoder}
|
|
105
|
+
* @see {@link getI64Decoder}
|
|
106
|
+
*/
|
|
107
|
+
export const getI64Codec = (config: NumberCodecConfig = {}): FixedSizeCodec<bigint | number, bigint, 8> =>
|
|
108
|
+
combineCodec(getI64Encoder(config), getI64Decoder(config));
|
package/src/i8.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';
|
|
2
|
+
|
|
3
|
+
import { numberDecoderFactory, numberEncoderFactory } from './utils';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Returns an encoder for 8-bit signed integers (`i8`).
|
|
7
|
+
*
|
|
8
|
+
* This encoder serializes `i8` values using 1 byte.
|
|
9
|
+
* Values can be provided as either `number` or `bigint`.
|
|
10
|
+
*
|
|
11
|
+
* For more details, see {@link getI8Codec}.
|
|
12
|
+
*
|
|
13
|
+
* @returns A `FixedSizeEncoder<number | bigint, 1>` for encoding `i8` values.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* Encoding an `i8` value.
|
|
17
|
+
* ```ts
|
|
18
|
+
* const encoder = getI8Encoder();
|
|
19
|
+
* const bytes = encoder.encode(-42); // 0xd6
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* @see {@link getI8Codec}
|
|
23
|
+
*/
|
|
24
|
+
export const getI8Encoder = (): FixedSizeEncoder<bigint | number, 1> =>
|
|
25
|
+
numberEncoderFactory({
|
|
26
|
+
name: 'i8',
|
|
27
|
+
range: [-Number('0x7f') - 1, Number('0x7f')],
|
|
28
|
+
set: (view, value) => view.setInt8(0, Number(value)),
|
|
29
|
+
size: 1,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns a decoder for 8-bit signed integers (`i8`).
|
|
34
|
+
*
|
|
35
|
+
* This decoder deserializes `i8` values from 1 byte.
|
|
36
|
+
* The decoded value is always a `number`.
|
|
37
|
+
*
|
|
38
|
+
* For more details, see {@link getI8Codec}.
|
|
39
|
+
*
|
|
40
|
+
* @returns A `FixedSizeDecoder<number, 1>` for decoding `i8` values.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* Decoding an `i8` value.
|
|
44
|
+
* ```ts
|
|
45
|
+
* const decoder = getI8Decoder();
|
|
46
|
+
* const value = decoder.decode(new Uint8Array([0xd6])); // -42
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @see {@link getI8Codec}
|
|
50
|
+
*/
|
|
51
|
+
export const getI8Decoder = (): FixedSizeDecoder<number, 1> =>
|
|
52
|
+
numberDecoderFactory({
|
|
53
|
+
get: view => view.getInt8(0),
|
|
54
|
+
name: 'i8',
|
|
55
|
+
size: 1,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Returns a codec for encoding and decoding 8-bit signed integers (`i8`).
|
|
60
|
+
*
|
|
61
|
+
* This codec serializes `i8` values using 1 byte.
|
|
62
|
+
* Values can be provided as either `number` or `bigint`, but the decoded value is always a `number`.
|
|
63
|
+
*
|
|
64
|
+
* @returns A `FixedSizeCodec<number | bigint, number, 1>` for encoding and decoding `i8` values.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* Encoding and decoding an `i8` value.
|
|
68
|
+
* ```ts
|
|
69
|
+
* const codec = getI8Codec();
|
|
70
|
+
* const bytes = codec.encode(-42); // 0xd6
|
|
71
|
+
* const value = codec.decode(bytes); // -42
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* This codec supports values between `-2^7` (`-128`) and `2^7 - 1` (`127`).
|
|
76
|
+
*
|
|
77
|
+
* - If you need a larger signed integer, consider using {@link getI16Codec}.
|
|
78
|
+
* - If you need an unsigned integer, consider using {@link getU8Codec}.
|
|
79
|
+
*
|
|
80
|
+
* Separate {@link getI8Encoder} and {@link getI8Decoder} functions are available.
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* const bytes = getI8Encoder().encode(-42);
|
|
84
|
+
* const value = getI8Decoder().decode(bytes);
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @see {@link getI8Encoder}
|
|
88
|
+
* @see {@link getI8Decoder}
|
|
89
|
+
*/
|
|
90
|
+
export const getI8Codec = (): FixedSizeCodec<bigint | number, number, 1> =>
|
|
91
|
+
combineCodec(getI8Encoder(), getI8Decoder());
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package contains codecs for numbers of different sizes and endianness.
|
|
3
|
+
* It can be used standalone, but it is also exported as part of Kit
|
|
4
|
+
* [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
|
|
5
|
+
*
|
|
6
|
+
* This package is also part of the [`@solana/codecs` package](https://github.com/anza-xyz/kit/tree/main/packages/codecs)
|
|
7
|
+
* which acts as an entry point for all codec packages as well as for their documentation.
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
export * from './assertions';
|
|
12
|
+
export * from './common';
|
|
13
|
+
export * from './f32';
|
|
14
|
+
export * from './f64';
|
|
15
|
+
export * from './i128';
|
|
16
|
+
export * from './i16';
|
|
17
|
+
export * from './i32';
|
|
18
|
+
export * from './i64';
|
|
19
|
+
export * from './i8';
|
|
20
|
+
export * from './short-u16';
|
|
21
|
+
export * from './u128';
|
|
22
|
+
export * from './u16';
|
|
23
|
+
export * from './u32';
|
|
24
|
+
export * from './u64';
|
|
25
|
+
export * from './u8';
|
package/src/short-u16.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import {
|
|
2
|
+
combineCodec,
|
|
3
|
+
createDecoder,
|
|
4
|
+
createEncoder,
|
|
5
|
+
Offset,
|
|
6
|
+
ReadonlyUint8Array,
|
|
7
|
+
VariableSizeCodec,
|
|
8
|
+
VariableSizeDecoder,
|
|
9
|
+
VariableSizeEncoder,
|
|
10
|
+
} from '@solana/codecs-core';
|
|
11
|
+
|
|
12
|
+
import { assertNumberIsBetweenForCodec } from './assertions';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Returns an encoder for `shortU16` values.
|
|
16
|
+
*
|
|
17
|
+
* This encoder serializes `shortU16` values using **1 to 3 bytes**.
|
|
18
|
+
* Smaller values use fewer bytes, while larger values take up more space.
|
|
19
|
+
*
|
|
20
|
+
* For more details, see {@link getShortU16Codec}.
|
|
21
|
+
*
|
|
22
|
+
* @returns A `VariableSizeEncoder<number | bigint>` for encoding `shortU16` values.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* Encoding a `shortU16` value.
|
|
26
|
+
* ```ts
|
|
27
|
+
* const encoder = getShortU16Encoder();
|
|
28
|
+
* encoder.encode(42); // 0x2a
|
|
29
|
+
* encoder.encode(128); // 0x8001
|
|
30
|
+
* encoder.encode(16384); // 0x808001
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @see {@link getShortU16Codec}
|
|
34
|
+
*/
|
|
35
|
+
export const getShortU16Encoder = (): VariableSizeEncoder<bigint | number> =>
|
|
36
|
+
createEncoder({
|
|
37
|
+
getSizeFromValue: (value: bigint | number): number => {
|
|
38
|
+
if (value <= 0b01111111) return 1;
|
|
39
|
+
if (value <= 0b0011111111111111) return 2;
|
|
40
|
+
return 3;
|
|
41
|
+
},
|
|
42
|
+
maxSize: 3,
|
|
43
|
+
write: (value: bigint | number, bytes: Uint8Array, offset: Offset): Offset => {
|
|
44
|
+
assertNumberIsBetweenForCodec('shortU16', 0, 65535, value);
|
|
45
|
+
const shortU16Bytes = [0];
|
|
46
|
+
for (let ii = 0; ; ii += 1) {
|
|
47
|
+
// Shift the bits of the value over such that the next 7 bits are at the right edge.
|
|
48
|
+
const alignedValue = Number(value) >> (ii * 7);
|
|
49
|
+
if (alignedValue === 0) {
|
|
50
|
+
// No more bits to consume.
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
// Extract those 7 bits using a mask.
|
|
54
|
+
const nextSevenBits = 0b1111111 & alignedValue;
|
|
55
|
+
shortU16Bytes[ii] = nextSevenBits;
|
|
56
|
+
if (ii > 0) {
|
|
57
|
+
// Set the continuation bit of the previous slice.
|
|
58
|
+
shortU16Bytes[ii - 1] |= 0b10000000;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
bytes.set(shortU16Bytes, offset);
|
|
62
|
+
return offset + shortU16Bytes.length;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns a decoder for `shortU16` values.
|
|
68
|
+
*
|
|
69
|
+
* This decoder deserializes `shortU16` values from **1 to 3 bytes**.
|
|
70
|
+
* The number of bytes used depends on the encoded value.
|
|
71
|
+
*
|
|
72
|
+
* For more details, see {@link getShortU16Codec}.
|
|
73
|
+
*
|
|
74
|
+
* @returns A `VariableSizeDecoder<number>` for decoding `shortU16` values.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* Decoding a `shortU16` value.
|
|
78
|
+
* ```ts
|
|
79
|
+
* const decoder = getShortU16Decoder();
|
|
80
|
+
* decoder.decode(new Uint8Array([0x2a])); // 42
|
|
81
|
+
* decoder.decode(new Uint8Array([0x80, 0x01])); // 128
|
|
82
|
+
* decoder.decode(new Uint8Array([0x80, 0x80, 0x01])); // 16384
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @see {@link getShortU16Codec}
|
|
86
|
+
*/
|
|
87
|
+
export const getShortU16Decoder = (): VariableSizeDecoder<number> =>
|
|
88
|
+
createDecoder({
|
|
89
|
+
maxSize: 3,
|
|
90
|
+
read: (bytes: ReadonlyUint8Array | Uint8Array, offset): [number, Offset] => {
|
|
91
|
+
let value = 0;
|
|
92
|
+
let byteCount = 0;
|
|
93
|
+
while (++byteCount) {
|
|
94
|
+
const byteIndex = byteCount - 1;
|
|
95
|
+
const currentByte = bytes[offset + byteIndex];
|
|
96
|
+
const nextSevenBits = 0b1111111 & currentByte;
|
|
97
|
+
// Insert the next group of seven bits into the correct slot of the output value.
|
|
98
|
+
value |= nextSevenBits << (byteIndex * 7);
|
|
99
|
+
if ((currentByte & 0b10000000) === 0) {
|
|
100
|
+
// This byte does not have its continuation bit set. We're done.
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return [value, offset + byteCount];
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Returns a codec for encoding and decoding `shortU16` values.
|
|
110
|
+
*
|
|
111
|
+
* It serializes unsigned integers using **1 to 3 bytes** based on the encoded value.
|
|
112
|
+
* The larger the value, the more bytes it uses.
|
|
113
|
+
*
|
|
114
|
+
* - If the value is `<= 0x7f` (127), it is stored in a **single byte**
|
|
115
|
+
* and the first bit is set to `0` to indicate the end of the value.
|
|
116
|
+
* - Otherwise, the first bit is set to `1` to indicate that the value continues in the next byte, which follows the same pattern.
|
|
117
|
+
* - This process repeats until the value is fully encoded in up to 3 bytes. The third and last byte, if needed, uses all 8 bits to store the remaining value.
|
|
118
|
+
*
|
|
119
|
+
* In other words, the encoding scheme follows this structure:
|
|
120
|
+
*
|
|
121
|
+
* ```txt
|
|
122
|
+
* 0XXXXXXX <- Values 0 to 127 (1 byte)
|
|
123
|
+
* 1XXXXXXX 0XXXXXXX <- Values 128 to 16,383 (2 bytes)
|
|
124
|
+
* 1XXXXXXX 1XXXXXXX XXXXXXXX <- Values 16,384 to 4,194,303 (3 bytes)
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* @returns A `VariableSizeCodec<number | bigint, number>` for encoding and decoding `shortU16` values.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* Encoding and decoding `shortU16` values.
|
|
131
|
+
* ```ts
|
|
132
|
+
* const codec = getShortU16Codec();
|
|
133
|
+
* const bytes1 = codec.encode(42); // 0x2a
|
|
134
|
+
* const bytes2 = codec.encode(128); // 0x8001
|
|
135
|
+
* const bytes3 = codec.encode(16384); // 0x808001
|
|
136
|
+
*
|
|
137
|
+
* codec.decode(bytes1); // 42
|
|
138
|
+
* codec.decode(bytes2); // 128
|
|
139
|
+
* codec.decode(bytes3); // 16384
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
142
|
+
* @remarks
|
|
143
|
+
* This codec efficiently stores small numbers, making it useful for transactions and compact representations.
|
|
144
|
+
*
|
|
145
|
+
* If you need a fixed-size `u16` codec, consider using {@link getU16Codec}.
|
|
146
|
+
*
|
|
147
|
+
* Separate {@link getShortU16Encoder} and {@link getShortU16Decoder} functions are available.
|
|
148
|
+
*
|
|
149
|
+
* ```ts
|
|
150
|
+
* const bytes = getShortU16Encoder().encode(42);
|
|
151
|
+
* const value = getShortU16Decoder().decode(bytes);
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @see {@link getShortU16Encoder}
|
|
155
|
+
* @see {@link getShortU16Decoder}
|
|
156
|
+
*/
|
|
157
|
+
export const getShortU16Codec = (): VariableSizeCodec<bigint | number, number> =>
|
|
158
|
+
combineCodec(getShortU16Encoder(), getShortU16Decoder());
|
package/src/u128.ts
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { combineCodec, FixedSizeCodec, FixedSizeDecoder, FixedSizeEncoder } from '@solana/codecs-core';
|
|
2
|
+
|
|
3
|
+
import { NumberCodecConfig } from './common';
|
|
4
|
+
import { numberDecoderFactory, numberEncoderFactory } from './utils';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Returns an encoder for 128-bit unsigned integers (`u128`).
|
|
8
|
+
*
|
|
9
|
+
* This encoder serializes `u128` values using sixteen bytes in little-endian format by default.
|
|
10
|
+
* You may specify big-endian storage using the `endian` option.
|
|
11
|
+
*
|
|
12
|
+
* For more details, see {@link getU128Codec}.
|
|
13
|
+
*
|
|
14
|
+
* @param config - Optional settings for endianness.
|
|
15
|
+
* @returns A `FixedSizeEncoder<number | bigint, 16>` for encoding `u128` values.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* Encoding a `u128` value.
|
|
19
|
+
* ```ts
|
|
20
|
+
* const encoder = getU128Encoder();
|
|
21
|
+
* const bytes = encoder.encode(42n); // 0x2a000000000000000000000000000000
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @see {@link getU128Codec}
|
|
25
|
+
*/
|
|
26
|
+
export const getU128Encoder = (config: NumberCodecConfig = {}): FixedSizeEncoder<bigint | number, 16> =>
|
|
27
|
+
numberEncoderFactory({
|
|
28
|
+
config,
|
|
29
|
+
name: 'u128',
|
|
30
|
+
range: [0n, BigInt('0xffffffffffffffffffffffffffffffff')],
|
|
31
|
+
set: (view, value, le) => {
|
|
32
|
+
const leftOffset = le ? 8 : 0;
|
|
33
|
+
const rightOffset = le ? 0 : 8;
|
|
34
|
+
const rightMask = 0xffffffffffffffffn;
|
|
35
|
+
view.setBigUint64(leftOffset, BigInt(value) >> 64n, le);
|
|
36
|
+
view.setBigUint64(rightOffset, BigInt(value) & rightMask, le);
|
|
37
|
+
},
|
|
38
|
+
size: 16,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Returns a decoder for 128-bit unsigned integers (`u128`).
|
|
43
|
+
*
|
|
44
|
+
* This decoder deserializes `u128` values from sixteen bytes in little-endian format by default.
|
|
45
|
+
* You may specify big-endian storage using the `endian` option.
|
|
46
|
+
*
|
|
47
|
+
* For more details, see {@link getU128Codec}.
|
|
48
|
+
*
|
|
49
|
+
* @param config - Optional settings for endianness.
|
|
50
|
+
* @returns A `FixedSizeDecoder<bigint, 16>` for decoding `u128` values.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* Decoding a `u128` value.
|
|
54
|
+
* ```ts
|
|
55
|
+
* const decoder = getU128Decoder();
|
|
56
|
+
* const value = decoder.decode(new Uint8Array([0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])); // 42n
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @see {@link getU128Codec}
|
|
60
|
+
*/
|
|
61
|
+
export const getU128Decoder = (config: NumberCodecConfig = {}): FixedSizeDecoder<bigint, 16> =>
|
|
62
|
+
numberDecoderFactory({
|
|
63
|
+
config,
|
|
64
|
+
get: (view, le) => {
|
|
65
|
+
const leftOffset = le ? 8 : 0;
|
|
66
|
+
const rightOffset = le ? 0 : 8;
|
|
67
|
+
const left = view.getBigUint64(leftOffset, le);
|
|
68
|
+
const right = view.getBigUint64(rightOffset, le);
|
|
69
|
+
return (left << 64n) + right;
|
|
70
|
+
},
|
|
71
|
+
name: 'u128',
|
|
72
|
+
size: 16,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Returns a codec for encoding and decoding 128-bit unsigned integers (`u128`).
|
|
77
|
+
*
|
|
78
|
+
* This codec serializes `u128` values using 16 bytes.
|
|
79
|
+
* Values can be provided as either `number` or `bigint`, but the decoded value is always a `bigint`.
|
|
80
|
+
*
|
|
81
|
+
* @param config - Optional configuration to specify endianness (little by default).
|
|
82
|
+
* @returns A `FixedSizeCodec<number | bigint, bigint, 16>` for encoding and decoding `u128` values.
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* Encoding and decoding a `u128` value.
|
|
86
|
+
* ```ts
|
|
87
|
+
* const codec = getU128Codec();
|
|
88
|
+
* const bytes = codec.encode(42); // 0x2a000000000000000000000000000000
|
|
89
|
+
* const value = codec.decode(bytes); // 42n
|
|
90
|
+
* ```
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* Using big-endian encoding.
|
|
94
|
+
* ```ts
|
|
95
|
+
* const codec = getU128Codec({ endian: Endian.Big });
|
|
96
|
+
* const bytes = codec.encode(42); // 0x0000000000000000000000000000002a
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @remarks
|
|
100
|
+
* This codec supports values between `0` and `2^128 - 1`.
|
|
101
|
+
* Since JavaScript `number` cannot safely represent values beyond `2^53 - 1`, the decoded value is always a `bigint`.
|
|
102
|
+
*
|
|
103
|
+
* - If you need a smaller unsigned integer, consider using {@link getU64Codec} or {@link getU32Codec}.
|
|
104
|
+
* - If you need signed integers, consider using {@link getI128Codec}.
|
|
105
|
+
*
|
|
106
|
+
* Separate {@link getU128Encoder} and {@link getU128Decoder} functions are available.
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* const bytes = getU128Encoder().encode(42);
|
|
110
|
+
* const value = getU128Decoder().decode(bytes);
|
|
111
|
+
* ```
|
|
112
|
+
*
|
|
113
|
+
* @see {@link getU128Encoder}
|
|
114
|
+
* @see {@link getU128Decoder}
|
|
115
|
+
*/
|
|
116
|
+
export const getU128Codec = (config: NumberCodecConfig = {}): FixedSizeCodec<bigint | number, bigint, 16> =>
|
|
117
|
+
combineCodec(getU128Encoder(config), getU128Decoder(config));
|