@btc-vision/btc-runtime 1.5.0 → 1.5.2

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.
@@ -0,0 +1,58 @@
1
+ import { i128, u128, u256 } from '@btc-vision/as-bignum/assembly';
2
+ import { ICodec } from '../interfaces/ICodec';
3
+ import { BytesWriter } from '../../buffer/BytesWriter';
4
+ import { BytesReader } from '../../buffer/BytesReader';
5
+ import { idOfI128, idOfU128, idOfU256 } from './Ids';
6
+
7
+ /**
8
+ * A generic NumericCodec<T> that handles:
9
+ * - `u256` from @btc-vision/as-bignum (big-endian)
10
+ * - Any built-in integer type (i32, u32, i64, etc.) also stored big-endian
11
+ */
12
+ export class NumericCodec<T> implements ICodec<T> {
13
+ public encode(value: T): Uint8Array {
14
+ const id = idof<T>();
15
+ switch (id) {
16
+ case idOfU256: {
17
+ // T is `u256`
18
+ const val = changetype<u256>(value);
19
+ return val.toUint8Array(true); // big-endian
20
+ }
21
+ case idOfU128: {
22
+ // T is `u128`
23
+ const val = changetype<u128>(value);
24
+ return val.toUint8Array(true); // big-endian
25
+ }
26
+ case idOfI128: {
27
+ // T is `i128`
28
+ const val = changetype<i128>(value);
29
+ return val.toUint8Array(true); // big-endian
30
+ }
31
+ default: {
32
+ const writer = new BytesWriter(sizeof<T>());
33
+ writer.write<T>(value);
34
+
35
+ return writer.getBuffer();
36
+ }
37
+ }
38
+ }
39
+
40
+ public decode(buffer: Uint8Array): T {
41
+ const id = idof<T>();
42
+ switch (id) {
43
+ case idOfU256:
44
+ // T is `u256`
45
+ return changetype<T>(u256.fromBytes(buffer, true));
46
+ case idOfU128:
47
+ // T is `u128`
48
+ return changetype<T>(u128.fromBytes(buffer, true));
49
+ case idOfI128:
50
+ // T is `i128`
51
+ return changetype<T>(i128.fromBytes(buffer, true));
52
+ default: {
53
+ const writer = new BytesReader(buffer);
54
+ return writer.read<T>();
55
+ }
56
+ }
57
+ }
58
+ }
@@ -0,0 +1,24 @@
1
+ import { ICodec } from '../interfaces/ICodec';
2
+ import { VariableBytesCodec } from './VariableBytesCodec';
3
+
4
+ class IStringCodec implements ICodec<string> {
5
+ public encode(value: string): Uint8Array {
6
+ // Convert string -> UTF8 bytes
7
+ const utf8 = String.UTF8.encode(value, false);
8
+
9
+ // Pass to variable-bytes
10
+ return VariableBytesCodec.encode(Uint8Array.wrap(utf8));
11
+ }
12
+
13
+ public decode(buffer: Uint8Array): string {
14
+ const raw = VariableBytesCodec.decode(buffer);
15
+ if (raw.length == 0) {
16
+ return '';
17
+ }
18
+
19
+ return String.UTF8.decode(raw.buffer, false);
20
+ }
21
+ }
22
+
23
+ export const idOfStringCodec = idof<IStringCodec>();
24
+ export const StringCodec = new IStringCodec();
@@ -0,0 +1,20 @@
1
+ import { u256 } from '@btc-vision/as-bignum/assembly';
2
+ import { ICodec } from '../interfaces/ICodec';
3
+
4
+ class _U256Codec implements ICodec<u256> {
5
+ public encode(value: u256): Uint8Array {
6
+ // big-endian
7
+ return value.toUint8Array(true);
8
+ }
9
+
10
+ public decode(buffer: Uint8Array): u256 {
11
+ if (buffer.length == 0) {
12
+ return u256.Zero;
13
+ }
14
+
15
+ return u256.fromUint8ArrayBE(buffer);
16
+ }
17
+ }
18
+
19
+ export const idOfU256Codec = idof<_U256Codec>();
20
+ export const U256Codec = new _U256Codec();
@@ -0,0 +1,134 @@
1
+ import { ICodec } from '../interfaces/ICodec';
2
+ import { PointerManager } from '../PointerManager';
3
+ import { Blockchain } from '../../env';
4
+ import { bigEndianAdd } from '../../math/bytes';
5
+
6
+ /**
7
+ * A generic codec to store an arbitrary-length byte array ("payload") in chunked 32-byte slots.
8
+ * Layout:
9
+ * - chunk 0 (pointer+0):
10
+ * first 4 bytes = length (u32 big-endian),
11
+ * next 28 bytes = partial data
12
+ * - chunk i>0 (pointer + i): 32 bytes of subsequent data
13
+ */
14
+ export class IVariableBytesCodec implements ICodec<Uint8Array> {
15
+ public encode(value: Uint8Array): Uint8Array {
16
+ const length = value.length;
17
+
18
+ // Number of bytes that fit in "the first chunk" = 28 (since 4 bytes used by length)
19
+ const firstChunkDataLen = length < 28 ? length : 28;
20
+ let remaining = length - firstChunkDataLen;
21
+
22
+ // If remaining > 0, each chunk is 32 bytes.
23
+ // So total chunks needed = 1 (for first chunk) + ceil(remaining / 32).
24
+ const additionalChunks: u32 = remaining == 0 ? 0 : ((remaining + 32 - 1) / 32);
25
+ const totalChunks: u32 = 1 + additionalChunks;
26
+
27
+ // 1) Allocate `totalChunks` from PointerManager
28
+ const pointerBytes = PointerManager.allocateSlots(totalChunks);
29
+
30
+ // 2) Write chunk 0: length + up to 28 bytes
31
+ const chunk0 = new Uint8Array(32);
32
+
33
+ // store length in big-endian (4 bytes)
34
+ chunk0[0] = <u8>((length >> 24) & 0xff);
35
+ chunk0[1] = <u8>((length >> 16) & 0xff);
36
+ chunk0[2] = <u8>((length >> 8) & 0xff);
37
+ chunk0[3] = <u8>(length & 0xff);
38
+
39
+ for (let i = 0; i < firstChunkDataLen; i++) {
40
+ chunk0[4 + i] = value[i];
41
+ }
42
+
43
+ // store chunk0
44
+ Blockchain.setStorageAt(pointerBytes, chunk0);
45
+
46
+ // 3) Write subsequent chunks
47
+ let offset: u32 = firstChunkDataLen;
48
+ for (let i: u64 = 1; i < u64(totalChunks); i++) {
49
+ const chunk = new Uint8Array(32);
50
+ const chunkSize: u32 = remaining < 32 ? remaining : 32;
51
+
52
+ for (let j: u32 = 0; j < chunkSize; j++) {
53
+ chunk[j] = value[offset + j];
54
+ }
55
+
56
+ offset += chunkSize;
57
+ remaining -= chunkSize;
58
+
59
+ // compute pointer + i in big-endian
60
+ const chunkPointer = bigEndianAdd(pointerBytes, i);
61
+ Blockchain.setStorageAt(chunkPointer, chunk);
62
+ }
63
+
64
+ // 4) Return the pointer as the "encoded" data (32 bytes).
65
+ return pointerBytes;
66
+ }
67
+
68
+ public decode(buffer: Uint8Array): Uint8Array {
69
+ // If buffer is 0 or all zero => means no data
70
+ if (buffer.length == 0 || isAllZero(buffer)) {
71
+ return new Uint8Array(0);
72
+ }
73
+
74
+ const pointer = buffer; // the pointer (32 bytes)
75
+
76
+ // chunk0
77
+ const chunk0 = Blockchain.getStorageAt(pointer);
78
+ if (chunk0.length == 0) {
79
+ // No data stored => empty
80
+ return new Uint8Array(32);
81
+ }
82
+
83
+ // read length from first 4 bytes
84
+ const b0 = <u32>chunk0[0];
85
+ const b1 = <u32>chunk0[1];
86
+ const b2 = <u32>chunk0[2];
87
+ const b3 = <u32>chunk0[3];
88
+ const length = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
89
+
90
+ if (length == 0) {
91
+ return new Uint8Array(0);
92
+ }
93
+
94
+ // read the data
95
+ const out = new Uint8Array(length);
96
+ const firstChunkLen = length < 28 ? length : 28;
97
+
98
+ // copy from chunk0
99
+ for (let i: u32 = 0; i < firstChunkLen; i++) {
100
+ out[i] = chunk0[4 + i];
101
+ }
102
+
103
+ let offset = firstChunkLen;
104
+ let remaining = length - firstChunkLen;
105
+
106
+ // read subsequent chunks
107
+ let chunkIndex: u64 = 1;
108
+ while (remaining > 0) {
109
+ const chunkPointer = bigEndianAdd(pointer, chunkIndex);
110
+ const chunkData = Blockchain.getStorageAt(chunkPointer);
111
+ const chunkSize: u32 = remaining < 32 ? remaining : 32;
112
+
113
+ for (let j: u32 = 0; j < chunkSize; j++) {
114
+ out[offset + j] = chunkData[j];
115
+ }
116
+
117
+ offset += chunkSize;
118
+ remaining -= chunkSize;
119
+ chunkIndex++;
120
+ }
121
+
122
+ return out;
123
+ }
124
+ }
125
+
126
+ function isAllZero(arr: Uint8Array): bool {
127
+ for (let i = 0; i < arr.length; i++) {
128
+ if (arr[i] != 0) return false;
129
+ }
130
+ return true;
131
+ }
132
+
133
+ export const idOfVariableBytes = idof<IVariableBytesCodec>();
134
+ export const VariableBytesCodec = new IVariableBytesCodec();
@@ -0,0 +1,12 @@
1
+ export interface ICodec<T> {
2
+ /**
3
+ * Encode in-memory `value` into a buffer that will be stored in blockchain storage.
4
+ * Possibly a single 32-byte chunk or a pointer if more is needed.
5
+ */
6
+ encode(value: T): Uint8Array;
7
+
8
+ /**
9
+ * Decode a buffer from storage into an in-memory `T`.
10
+ */
11
+ decode(buffer: Uint8Array): T;
12
+ }
@@ -0,0 +1,227 @@
1
+ import { Blockchain } from '../../env';
2
+ import { BytesWriter } from '../../buffer/BytesWriter';
3
+ import { BytesReader } from '../../buffer/BytesReader';
4
+ import { encodePointerUnknownLength } from '../../math/abi';
5
+
6
+ import { i128, u128, u256 } from '@btc-vision/as-bignum/assembly';
7
+ import { idOfAddress, idOfI128, idOfString, idOfU128, idOfU256, idOfUint8Array } from '../codecs/Ids';
8
+
9
+ import { AddressCodec } from '../codecs/AddressCodec';
10
+ import { BooleanCodec } from '../codecs/BooleanCodec';
11
+ import { StringCodec } from '../codecs/StringCodec';
12
+ import { VariableBytesCodec } from '../codecs/VariableBytesCodec';
13
+ import { U256Codec } from '../codecs/U256Codec';
14
+
15
+ import { Address } from '../../types/Address';
16
+ import { Revert } from '../../types/Revert';
17
+
18
+ /**
19
+ * A reflection-based StorageMap<K, V>.
20
+ * - `pointer` => a u16 "namespace"
21
+ * - `set(key, value)` => store bytes
22
+ * - `get(key)` => decode bytes
23
+ *
24
+ * This version uses a chain of `if/else` for each possible type T,
25
+ * so the compiler doesn't complain about mismatched returns.
26
+ */
27
+ @final
28
+ export class StorageMap<K, V> {
29
+ private readonly pointer: u16;
30
+
31
+ constructor(pointer: u16) {
32
+ this.pointer = pointer;
33
+ }
34
+
35
+ // ----------------------------------------------------------
36
+ // PUBLIC API
37
+ // ----------------------------------------------------------
38
+
39
+ public set(key: K, value: V): this {
40
+ const storageKey = this.getStorageKey(key);
41
+ this.storeValue<V>(storageKey, value);
42
+ return this;
43
+ }
44
+
45
+ public get(key: K): V {
46
+ const storageKey = this.getStorageKey(key);
47
+ return this.decodeValue<V>(storageKey);
48
+ }
49
+
50
+ public has(key: K): bool {
51
+ const storageKey = this.getStorageKey(key);
52
+ return Blockchain.hasStorageAt(storageKey);
53
+ }
54
+
55
+ @unsafe
56
+ public delete(key: K): bool {
57
+ const storageKey = this.getStorageKey(key);
58
+ if (!Blockchain.hasStorageAt(storageKey)) {
59
+ return false;
60
+ }
61
+
62
+ Blockchain.setStorageAt(storageKey, new Uint8Array(0));
63
+ return true;
64
+ }
65
+
66
+ @unsafe
67
+ public clear(): void {
68
+ // Not implemented: we'd need key-tracking to remove them all
69
+ throw new Error('clear() not implemented; no key-tracking logic here.');
70
+ }
71
+
72
+ // ----------------------------------------------------------
73
+ // INTERNAL: Derive the final storage key
74
+ // ----------------------------------------------------------
75
+
76
+ private getStorageKey(k: K): Uint8Array {
77
+ // 1) encode the key
78
+ const keyBytes = this.encodeValue<K>(k);
79
+
80
+ // 2) transform with pointer
81
+ return encodePointerUnknownLength(this.pointer, keyBytes);
82
+ }
83
+
84
+ // ----------------------------------------------------------
85
+ // ENCODE / DECODE
86
+ // ----------------------------------------------------------
87
+
88
+ /**
89
+ * Retrieve the value of type P from the given storage pointer (32 bytes).
90
+ * If it's a variable-length type, we decode from pointer-based approach
91
+ * (like VariableBytesCodec or StringCodec).
92
+ * Otherwise, we get the raw from storage and decode.
93
+ */
94
+ private decodeValue<P>(pointer: Uint8Array): P {
95
+ // For some types like `Uint8Array` or `string`, we might want
96
+ // to treat the pointer as an allocated "variable" location.
97
+ const typeId = idof<P>();
98
+
99
+ // For variable-length things:
100
+ if (typeId == idOfUint8Array) {
101
+ // decode variable bytes from pointer
102
+ const arr = VariableBytesCodec.decode(pointer);
103
+ return changetype<P>(arr);
104
+ }
105
+ if (typeId == idOfString) {
106
+ const str = StringCodec.decode(pointer);
107
+ return changetype<P>(str);
108
+ }
109
+
110
+ // For everything else, we read raw from storage
111
+ const raw = Blockchain.getStorageAt(pointer);
112
+
113
+ return this.decodeBytesAsType<P>(raw);
114
+ }
115
+
116
+ /**
117
+ * Store a value of type P at the given storage key.
118
+ * - Some types (uint8array, string) -> chunked (pointer-based).
119
+ * - Others -> direct bytes in that slot.
120
+ */
121
+ private storeValue<P>(storageKey: Uint8Array, value: P): void {
122
+ const raw = this.encodeValue<P>(value);
123
+ Blockchain.setStorageAt(storageKey, raw);
124
+ }
125
+
126
+ // ----------------------------------------------------------
127
+ // decodeBytesAsType: interpret raw bytes as type P
128
+ // ----------------------------------------------------------
129
+
130
+ private decodeBytesAsType<P>(raw: Uint8Array): P {
131
+ // isInteger => built-in numeric types (i32, u32, etc.)
132
+ if (isInteger<P>()) {
133
+ if (raw.length < <i32>sizeof<P>()) {
134
+ return changetype<P>(0);
135
+ }
136
+
137
+ const reader = new BytesReader(raw);
138
+ return reader.read<P>();
139
+ }
140
+
141
+ // isBoolean => decode with BooleanCodec
142
+ if (isBoolean<P>()) {
143
+ const boolVal = BooleanCodec.decode(raw);
144
+ return changetype<P>(boolVal);
145
+ }
146
+
147
+ const typeId = idof<P>();
148
+
149
+ // u256
150
+ if (typeId == idOfU256) {
151
+ const decoded = U256Codec.decode(raw);
152
+ return changetype<P>(decoded);
153
+ }
154
+
155
+ // i128
156
+ if (typeId == idOfI128) {
157
+ const val = i128.fromUint8ArrayBE(raw);
158
+ return changetype<P>(val);
159
+ }
160
+
161
+ // u128
162
+ if (typeId == idOfU128) {
163
+ const val = u128.fromUint8ArrayBE(raw);
164
+ return changetype<P>(val);
165
+ }
166
+
167
+ // Address
168
+ if (typeId == idOfAddress) {
169
+ const addr = AddressCodec.decode(raw);
170
+ return changetype<P>(addr);
171
+ }
172
+
173
+ throw new Revert(`Unsupported type ${typeId}`);
174
+ }
175
+
176
+ // ----------------------------------------------------------
177
+ // encodeValue<P>: convert a value of type P into raw bytes
178
+ // ----------------------------------------------------------
179
+
180
+ private encodeValue<P>(value: P): Uint8Array {
181
+ // built-in integer => write with BytesWriter
182
+ if (isInteger<P>()) {
183
+ const writer = new BytesWriter(sizeof<P>());
184
+ writer.write<P>(value);
185
+ return writer.getBuffer();
186
+ }
187
+
188
+ // bool => BooleanCodec
189
+ if (isBoolean<P>()) {
190
+ return BooleanCodec.encode(changetype<bool>(value));
191
+ }
192
+
193
+ // Check reflection for bigger types
194
+ if (value instanceof Uint8Array) {
195
+ return VariableBytesCodec.encode(value);
196
+ }
197
+
198
+ if (isString<P>()) {
199
+ const strVal = changetype<string>(value);
200
+ return StringCodec.encode(strVal);
201
+ }
202
+
203
+ if (value instanceof u256) {
204
+ return U256Codec.encode(changetype<u256>(value));
205
+ }
206
+
207
+ if (value instanceof u128) {
208
+ // store big-endian
209
+ const uval = changetype<u128>(value);
210
+ return uval.toUint8Array(true);
211
+ }
212
+
213
+ if (value instanceof i128) {
214
+ const ival = changetype<i128>(value);
215
+ return ival.toUint8Array(true);
216
+ }
217
+
218
+ if (value instanceof Address) {
219
+ return AddressCodec.encode(changetype<Address>(value));
220
+ }
221
+
222
+ // If nested map => handle in a custom branch (not shown here):
223
+ // if (value instanceof StorageMap<...>) { ... }
224
+
225
+ throw new Revert('encodeValue: Unsupported type');
226
+ }
227
+ }
@@ -0,0 +1,57 @@
1
+ import { ICodec } from '../interfaces/ICodec';
2
+ import { BytesWriter } from '../../buffer/BytesWriter';
3
+ import { encodePointerUnknownLength } from '../../math/abi';
4
+ import { Blockchain } from '../../env';
5
+
6
+
7
+ export class StorageSet<T> {
8
+ private readonly pointer: u16;
9
+ private readonly parentKey: Uint8Array;
10
+
11
+ private elementCodec: ICodec<T>;
12
+
13
+ constructor(pointer: u16, parentKey: Uint8Array, elementCodec: ICodec<T>) {
14
+ this.pointer = pointer;
15
+ this.parentKey = parentKey;
16
+ this.elementCodec = elementCodec;
17
+ }
18
+
19
+ public add(value: T): void {
20
+ const storageKey = this.getStorageKey(value);
21
+
22
+ // A 1-byte array with a single 0x01 is enough to mark presence
23
+ const flag = new Uint8Array(1);
24
+ flag[31] = 1;
25
+
26
+ Blockchain.setStorageAt(storageKey, flag);
27
+ }
28
+
29
+ public has(value: T): bool {
30
+ const storageKey = this.getStorageKey(value);
31
+ return Blockchain.hasStorageAt(storageKey);
32
+ }
33
+
34
+ public delete(value: T): bool {
35
+ const storageKey = this.getStorageKey(value);
36
+ if (!Blockchain.hasStorageAt(storageKey)) {
37
+ return false;
38
+ }
39
+
40
+ Blockchain.setStorageAt(storageKey, new Uint8Array(32));
41
+ return true;
42
+ }
43
+
44
+ @unsafe
45
+ public clear(): void {
46
+ throw new Error('clear() not implemented.');
47
+ }
48
+
49
+ private getStorageKey(value: T): Uint8Array {
50
+ const encoded = this.elementCodec.encode(value);
51
+ const writer = new BytesWriter(this.parentKey.length + encoded.length);
52
+ writer.writeBytes(this.parentKey);
53
+ writer.writeBytes(encoded);
54
+
55
+ return encodePointerUnknownLength(this.pointer, writer.getBuffer());
56
+ }
57
+ }
@@ -0,0 +1,12 @@
1
+ import { Calldata } from '../types';
2
+
3
+ export class Plugin {
4
+ public onDeployment(_calldata: Calldata): void {
5
+ }
6
+
7
+ public onExecutionStarted(): void {
8
+ }
9
+
10
+ public onExecutionCompleted(): void {
11
+ }
12
+ }
@@ -35,7 +35,7 @@ export class StoredAddressArray {
35
35
  constructor(public pointer: u16, public subPointer: Uint8Array) {
36
36
  assert(
37
37
  subPointer.length <= 30,
38
- `You must pass a 30 bytes sub-pointer. (AddressArray, got ${this.subPointer.length})`,
38
+ `You must pass a 30 bytes sub-pointer. (AddressArray, got ${subPointer.length})`,
39
39
  );
40
40
 
41
41
  // Construct base pointer as a 32-byte array
@@ -1,122 +0,0 @@
1
- import { Revert } from '../types/Revert';
2
- import { ArrayBuffer } from 'arraybuffer';
3
-
4
- export class FastUint8Array {
5
- public length: i32;
6
- private ptr: usize;
7
-
8
- [key: number]: u8;
9
-
10
- constructor(length: i32) {
11
- if (length < 0) {
12
- throw new Revert('Negative length in FastUint8Array constructor');
13
- }
14
-
15
- this.length = length;
16
- this.ptr = __alloc(<usize>length);
17
- }
18
-
19
- public static fromUint8Array(arr: Uint8Array): FastUint8Array {
20
- const buffer = new FastUint8Array(arr.length);
21
- for (let i: u32 = 0; i < arr.length; i++) {
22
- buffer[i] = arr[i];
23
- }
24
-
25
- return buffer;
26
- }
27
-
28
- toArrayBuffer(): ArrayBuffer {
29
- const arr = new Uint8Array(this.length);
30
- for (let i: u32 = 0; i < arr.length; i++) {
31
- arr[i] = this[i];
32
- }
33
-
34
- return arr.buffer;
35
- }
36
-
37
- /**
38
- * Fills the buffer with a specified byte value.
39
- */
40
- fill(value: u8): void {
41
- memory.fill(this.ptr, value, <usize>this.length);
42
- }
43
-
44
- /**
45
- * Copies bytes from another FastUint8Array into this one, starting at `destOffset`.
46
- */
47
- copyFrom(source: FastUint8Array, destOffset: i32 = 0): void {
48
- if (destOffset < 0) {
49
- throw new Revert(`Negative destOffset in copyFrom: ${destOffset}`);
50
- }
51
-
52
- let maxBytes = source.length;
53
- const destRemaining = this.length - destOffset;
54
- if (destRemaining < maxBytes) {
55
- maxBytes = destRemaining;
56
- }
57
-
58
- if (maxBytes <= 0) return;
59
-
60
- memory.copy(
61
- this.ptr + <usize>destOffset,
62
- source.ptr,
63
- <usize>maxBytes,
64
- );
65
- }
66
-
67
- free(): void {
68
- if (this.ptr != 0) {
69
- __free(this.ptr);
70
- this.ptr = 0;
71
- this.length = 0;
72
- }
73
- }
74
-
75
- /**
76
- * Safe read operator: buffer[i]
77
- * Throws on out-of-bounds.
78
- */
79
- @operator('[]')
80
- private __get(index: i32): u8 {
81
- if (<u32>index >= <u32>this.length) {
82
- throw new Revert('Index out of range in __get');
83
- }
84
- return load<u8>(this.ptr + <usize>index);
85
- }
86
-
87
- /**
88
- * Safe write operator: buffer[i] = value
89
- * Throws on out-of-bounds.
90
- */
91
- @operator('[]=')
92
- private __set(index: i32, value: u8): void {
93
- if (<u32>index >= <u32>this.length) {
94
- throw new Revert('Index out of range in __set');
95
- }
96
- store<u8>(this.ptr + <usize>index, value);
97
- }
98
-
99
- /**
100
- * Braces read operator: buffer{i}
101
- * Now also throws on out-of-bounds for safety.
102
- */
103
- @operator('{}')
104
- private __uget(index: i32): u8 {
105
- if (<u32>index >= <u32>this.length) {
106
- throw new Revert('Index out of range in __uget');
107
- }
108
- return load<u8>(this.ptr + <usize>index);
109
- }
110
-
111
- /**
112
- * Braces write operator: buffer{i} = value
113
- * Now also throws on out-of-bounds.
114
- */
115
- @operator('{}=')
116
- private __uset(index: i32, value: u8): void {
117
- if (<u32>index >= <u32>this.length) {
118
- throw new Revert('Index out of range in __uset');
119
- }
120
- store<u8>(this.ptr + <usize>index, value);
121
- }
122
- }