MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1#include <stdlib.h>
2#include <stdio.h>
3#include <string.h>
4#include <ctype.h>
5
6#include "ant.h"
7#include "ptr.h"
8#include "utf8.h"
9#include "utils.h"
10#include "errors.h"
11#include "base64.h"
12#include "internal.h"
13#include "runtime.h"
14#include "gc/roots.h"
15#include "descriptors.h"
16
17#include "silver/engine.h"
18#include "modules/bigint.h"
19#include "modules/buffer.h"
20#include "modules/symbol.h"
21
22#define BUFFER_REGISTRY_INITIAL_CAP 64
23
24// Node compatibility exports only
25// Ant does not enforce these as allocation limits
26#define BUFFER_COMPAT_MAX_LENGTH 4294967296.0
27#define BUFFER_COMPAT_MAX_STRING_LENGTH 536870888.0
28#define BUFFER_COMPAT_INSPECT_MAX_BYTES 50.0
29
30static size_t ta_metadata_bytes = 0;
31static size_t buffer_registry_count = 0;
32static size_t buffer_registry_cap = 0;
33
34static ArrayBufferData **buffer_registry = NULL;
35static ant_value_t g_typedarray_iter_proto = 0;
36
37enum {
38 BUFFER_ARRAYBUFFER_NATIVE_TAG = 0x41425546u, // ABUF
39 BUFFER_TYPEDARRAY_NATIVE_TAG = 0x54594152u, // TYAR
40 BUFFER_DATAVIEW_NATIVE_TAG = 0x44564957u, // DVIW
41};
42
43static void *ta_meta_alloc(size_t size) {
44 void *ptr = ant_calloc(size);
45 if (!ptr) return NULL;
46 ta_metadata_bytes += size;
47 return ptr;
48}
49
50static void ta_meta_free(void *ptr, size_t size) {
51 if (!ptr) return;
52 if (ta_metadata_bytes >= size) ta_metadata_bytes -= size;
53 else ta_metadata_bytes = 0;
54 free(ptr);
55}
56
57ArrayBufferData *buffer_get_arraybuffer_data(ant_value_t value) {
58 if (!is_object_type(value) || buffer_is_dataview(value)) return NULL;
59 return (ArrayBufferData *)js_get_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG);
60}
61
62TypedArrayData *buffer_get_typedarray_data(ant_value_t value) {
63 if (vtype(value) == T_TYPEDARRAY)
64 return (TypedArrayData *)js_gettypedarray(value);
65 if (!is_object_type(value)) return NULL;
66 return (TypedArrayData *)js_get_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG);
67}
68
69DataViewData *buffer_get_dataview_data(ant_value_t value) {
70 if (!is_object_type(value)) return NULL;
71 return (DataViewData *)js_get_native(value, BUFFER_DATAVIEW_NATIVE_TAG);
72}
73
74static void arraybuffer_finalize(ant_t *js, ant_object_t *obj) {
75 ant_value_t value = js_obj_from_ptr(obj);
76 ArrayBufferData *data = (ArrayBufferData *)js_get_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG);
77 if (!data) return;
78 js_clear_native(value, BUFFER_ARRAYBUFFER_NATIVE_TAG);
79 free_array_buffer_data(data);
80}
81
82static void typedarray_finalize(ant_t *js, ant_object_t *obj) {
83 ant_value_t value = js_obj_from_ptr(obj);
84 TypedArrayData *ta_data = (TypedArrayData *)js_get_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG);
85 if (!ta_data) return;
86 js_clear_native(value, BUFFER_TYPEDARRAY_NATIVE_TAG);
87
88 if (ta_data->buffer) free_array_buffer_data(ta_data->buffer);
89 ta_meta_free(ta_data, sizeof(*ta_data));
90}
91
92static void dataview_finalize(ant_t *js, ant_object_t *obj) {
93 ant_value_t value = js_obj_from_ptr(obj);
94 DataViewData *dv_data = (DataViewData *)js_get_native(value, BUFFER_DATAVIEW_NATIVE_TAG);
95 if (!dv_data) return;
96 js_clear_native(value, BUFFER_DATAVIEW_NATIVE_TAG);
97
98 if (dv_data->buffer) free_array_buffer_data(dv_data->buffer);
99 ta_meta_free(dv_data, sizeof(*dv_data));
100}
101
102bool buffer_is_dataview(ant_value_t obj) {
103 return js_check_brand(obj, BRAND_DATAVIEW);
104}
105
106bool buffer_is_binary_source(ant_value_t value) {
107 if (vtype(value) == T_TYPEDARRAY) return true;
108 if (!is_object_type(value)) return false;
109 if (buffer_is_dataview(value)) return true;
110 return buffer_get_typedarray_data(value) != NULL || buffer_get_arraybuffer_data(value) != NULL;
111}
112
113bool buffer_source_get_bytes(ant_t *js, ant_value_t value, const uint8_t **out, size_t *len) {
114 if (out) *out = NULL;
115 if (len) *len = 0;
116 if (!buffer_is_binary_source(value)) return false;
117
118 TypedArrayData *ta = buffer_get_typedarray_data(value);
119
120 if (ta) {
121 if (!ta->buffer || ta->buffer->is_detached) { *out = NULL; *len = 0; return true; }
122 *out = ta->buffer->data + ta->byte_offset;
123 *len = ta->byte_length;
124 return true;
125 }
126
127 ArrayBufferData *ab = buffer_get_arraybuffer_data(value);
128 if (ab) {
129 if (ab->is_detached) { *out = NULL; *len = 0; return true; }
130 *out = ab->data;
131 *len = ab->length;
132 return true;
133 }
134
135 if (buffer_is_dataview(value)) {
136 DataViewData *dv = buffer_get_dataview_data(value);
137 if (!dv || !dv->buffer || dv->buffer->is_detached) { *out = NULL; *len = 0; return true; }
138 *out = dv->buffer->data + dv->byte_offset;
139 *len = dv->byte_length;
140 return true;
141 }
142
143 return false;
144}
145
146static bool typedarray_read_value(ant_t *js, const TypedArrayData *ta_data, size_t index, ant_value_t *out) {
147 if (!out || !ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) {
148 return false;
149 }
150
151 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
152 switch (ta_data->type) {
153 case TYPED_ARRAY_INT8: *out = js_mknum((double)((int8_t *)data)[index]); return true;
154 case TYPED_ARRAY_UINT8:
155 case TYPED_ARRAY_UINT8_CLAMPED: *out = js_mknum((double)data[index]); return true;
156 case TYPED_ARRAY_INT16: *out = js_mknum((double)((int16_t *)data)[index]); return true;
157 case TYPED_ARRAY_UINT16: *out = js_mknum((double)((uint16_t *)data)[index]); return true;
158 case TYPED_ARRAY_INT32: *out = js_mknum((double)((int32_t *)data)[index]); return true;
159 case TYPED_ARRAY_UINT32: *out = js_mknum((double)((uint32_t *)data)[index]); return true;
160 case TYPED_ARRAY_FLOAT16: *out = js_mknum(half_to_double(((uint16_t *)data)[index])); return true;
161 case TYPED_ARRAY_FLOAT32: *out = js_mknum((double)((float *)data)[index]); return true;
162 case TYPED_ARRAY_FLOAT64: *out = js_mknum(((double *)data)[index]); return true;
163 case TYPED_ARRAY_BIGINT64: *out = bigint_from_int64(js, ((int64_t *)data)[index]); return !is_err(*out);
164 case TYPED_ARRAY_BIGUINT64: *out = bigint_from_uint64(js, ((uint64_t *)data)[index]); return !is_err(*out);
165 default: return false;
166 }
167}
168
169static bool advance_typedarray(ant_t *js, js_iter_t *it, ant_value_t *out) {
170 ant_value_t iter = it->iterator;
171 ant_value_t ta_obj = js_get_slot(iter, SLOT_DATA);
172 ant_value_t state_v = js_get_slot(iter, SLOT_ITER_STATE);
173 uint32_t state = (vtype(state_v) == T_NUM) ? (uint32_t)js_getnum(state_v) : 0;
174
175 uint32_t kind = ITER_STATE_KIND(state);
176 uint32_t idx = ITER_STATE_INDEX(state);
177
178 TypedArrayData *ta = buffer_get_typedarray_data(ta_obj);
179 if (!ta || !ta->buffer || ta->buffer->is_detached || idx >= (uint32_t)ta->length) return false;
180
181 ant_value_t value;
182 if (!typedarray_read_value(js, ta, idx, &value)) return false;
183
184 switch (kind) {
185 case ARR_ITER_KEYS:
186 *out = js_mknum((double)idx);
187 break;
188 case ARR_ITER_ENTRIES: {
189 ant_value_t pair = js_mkarr(js);
190 js_arr_push(js, pair, js_mknum((double)idx));
191 js_arr_push(js, pair, value);
192 *out = pair;
193 break;
194 }
195 default:
196 *out = value;
197 break;
198 }
199
200 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(kind, idx + 1)));
201 return true;
202}
203
204static ant_value_t ta_iter_next(ant_t *js, ant_value_t *args, int nargs) {
205 js_iter_t it = { .iterator = js->this_val };
206 ant_value_t value;
207 return js_iter_result(js, advance_typedarray(js, &it, &value), value);
208}
209
210static ant_value_t ta_values(ant_t *js, ant_value_t *args, int nargs) {
211 ant_value_t iter = js_mkobj(js);
212 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val);
213 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_VALUES, 0)));
214 js_set_proto_init(iter, g_typedarray_iter_proto);
215 return iter;
216}
217
218static ant_value_t ta_keys(ant_t *js, ant_value_t *args, int nargs) {
219 ant_value_t iter = js_mkobj(js);
220 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val);
221 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_KEYS, 0)));
222 js_set_proto_init(iter, g_typedarray_iter_proto);
223 return iter;
224}
225
226static ant_value_t ta_entries(ant_t *js, ant_value_t *args, int nargs) {
227 ant_value_t iter = js_mkobj(js);
228 js_set_slot_wb(js, iter, SLOT_DATA, js->this_val);
229 js_set_slot(iter, SLOT_ITER_STATE, js_mknum((double)ITER_STATE_PACK(ARR_ITER_ENTRIES, 0)));
230 js_set_proto_init(iter, g_typedarray_iter_proto);
231 return iter;
232}
233
234static void register_buffer(ArrayBufferData *data) {
235 if (!data) return;
236
237 if (!buffer_registry) {
238 buffer_registry = calloc(BUFFER_REGISTRY_INITIAL_CAP, sizeof(ArrayBufferData *));
239 if (!buffer_registry) return;
240 buffer_registry_cap = BUFFER_REGISTRY_INITIAL_CAP;
241 }
242
243 if (buffer_registry_count >= buffer_registry_cap) {
244 size_t new_cap = buffer_registry_cap * 2;
245 ArrayBufferData **new_reg = realloc(buffer_registry, new_cap * sizeof(ArrayBufferData *));
246 if (!new_reg) return;
247 buffer_registry = new_reg;
248 buffer_registry_cap = new_cap;
249 }
250
251 buffer_registry[buffer_registry_count++] = data;
252}
253
254static void unregister_buffer(ArrayBufferData *data) {
255 if (!data || !buffer_registry) return;
256
257 for (size_t i = 0; i < buffer_registry_count; i++) {
258 if (buffer_registry[i] == data) {
259 buffer_registry[i] = buffer_registry[--buffer_registry_count];
260 return;
261 }}
262}
263
264static inline ssize_t normalize_index(ssize_t idx, ssize_t len) {
265 if (idx < 0) idx += len;
266 if (idx < 0) return 0;
267 if (idx > len) return len;
268 return idx;
269}
270
271ArrayBufferData *create_array_buffer_data(size_t length) {
272 ArrayBufferData *data = ant_calloc(sizeof(ArrayBufferData) + length);
273 if (!data) return NULL;
274
275 data->data = (uint8_t *)(data + 1);
276 memset(data->data, 0, length);
277
278 data->length = length;
279 data->capacity = length;
280 data->ref_count = 1;
281 data->is_shared = 0;
282 data->is_detached = 0;
283
284 register_buffer(data);
285 return data;
286}
287
288static ArrayBufferData *create_shared_array_buffer_data(size_t length) {
289 ArrayBufferData *data = create_array_buffer_data(length);
290 if (data) data->is_shared = 1;
291 return data;
292}
293
294void free_array_buffer_data(ArrayBufferData *data) {
295 if (!data) return;
296 data->ref_count--;
297 if (data->ref_count <= 0) {
298 unregister_buffer(data);
299 free(data);
300 }
301}
302
303static size_t get_element_size(TypedArrayType type) {
304 static const void *dispatch[] = {
305 &&L_1, &&L_1, &&L_1, &&L_2, &&L_2,
306 &&L_4, &&L_4, &&L_2, &&L_4, &&L_8, &&L_8, &&L_8
307 };
308
309 if (type > TYPED_ARRAY_BIGUINT64) goto L_1;
310 goto *dispatch[type];
311
312 L_1: return 1;
313 L_2: return 2;
314 L_4: return 4;
315 L_8: return 8;
316}
317
318const char *buffer_typedarray_type_name(TypedArrayType type) {
319 static const char *const names[] = {
320 "Int8Array",
321 "Uint8Array",
322 "Uint8ClampedArray",
323 "Int16Array",
324 "Uint16Array",
325 "Int32Array",
326 "Uint32Array",
327 "Float16Array",
328 "Float32Array",
329 "Float64Array",
330 "BigInt64Array",
331 "BigUint64Array",
332 };
333
334 int i = (int)type;
335 if (i < 0 || i >= (int)(sizeof(names) / sizeof(names[0]))) return "Uint8Array";
336 return names[i];
337}
338
339static ant_value_t create_typed_array_like(
340 ant_t *js,
341 ant_value_t this_val,
342 TypedArrayType type,
343 ArrayBufferData *buffer,
344 size_t byte_offset,
345 size_t length
346) {
347 ant_value_t ab_obj = create_arraybuffer_obj(js, buffer);
348 ant_value_t out = create_typed_array_with_buffer(
349 js,type, buffer, byte_offset,
350 length, buffer_typedarray_type_name(type), ab_obj
351 );
352
353 if (is_err(out)) return out;
354 ant_value_t proto = js_get_proto(js, this_val);
355 if (is_special_object(proto)) js_set_proto_init(out, proto);
356
357 return out;
358}
359
360static ant_value_t js_arraybuffer_constructor(ant_t *js, ant_value_t *args, int nargs) {
361 if (vtype(js->new_target) == T_UNDEF) {
362 return js_mkerr_typed(js, JS_ERR_TYPE, "ArrayBuffer constructor requires 'new'");
363 }
364 size_t length = 0;
365 if (nargs > 0 && vtype(args[0]) == T_NUM) {
366 length = (size_t)js_getnum(args[0]);
367 }
368
369 ArrayBufferData *data = create_array_buffer_data(length);
370 if (!data) {
371 return js_mkerr(js, "Failed to allocate ArrayBuffer");
372 }
373
374 ant_value_t obj = js_mkobj(js);
375 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11);
376
377 if (is_special_object(proto)) js_set_proto_init(obj, proto);
378 js_set_native(obj, data, BUFFER_ARRAYBUFFER_NATIVE_TAG);
379 js_set(js, obj, "byteLength", js_mknum((double)length));
380 js_set_finalizer(obj, arraybuffer_finalize);
381
382 return obj;
383}
384
385// ArrayBuffer.prototype.slice(begin, end)
386static ant_value_t js_arraybuffer_slice(ant_t *js, ant_value_t *args, int nargs) {
387 ant_value_t this_val = js_getthis(js);
388 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val);
389 if (!data) return js_mkerr(js, "Invalid ArrayBuffer");
390 if (data->is_detached) return js_mkerr(js, "Cannot slice a detached ArrayBuffer");
391
392 ssize_t len = (ssize_t)data->length;
393 ssize_t begin = 0, end = len;
394 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]);
395 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]);
396
397 begin = normalize_index(begin, len);
398 end = normalize_index(end, len);
399 if (end < begin) end = begin;
400
401 size_t new_length = (size_t)(end - begin);
402 ArrayBufferData *new_data = create_array_buffer_data(new_length);
403 if (!new_data) return js_mkerr(js, "Failed to allocate new ArrayBuffer");
404
405 memcpy(new_data->data, data->data + begin, new_length);
406
407 ant_value_t new_obj = js_mkobj(js);
408 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11);
409
410 if (is_special_object(proto)) js_set_proto_init(new_obj, proto);
411 js_set_native(new_obj, new_data, BUFFER_ARRAYBUFFER_NATIVE_TAG);
412 js_set(js, new_obj, "byteLength", js_mknum((double)new_length));
413 js_set_finalizer(new_obj, arraybuffer_finalize);
414
415 return new_obj;
416}
417
418// ArrayBuffer.prototype.transfer(newLength)
419static ant_value_t js_arraybuffer_transfer(ant_t *js, ant_value_t *args, int nargs) {
420 ant_value_t this_val = js_getthis(js);
421 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val);
422 if (!data) return js_mkerr(js, "Invalid ArrayBuffer");
423
424 if (data->is_detached) {
425 return js_mkerr(js, "Cannot transfer a detached ArrayBuffer");
426 }
427
428 if (data->is_shared) {
429 return js_mkerr(js, "Cannot transfer a SharedArrayBuffer");
430 }
431
432 size_t new_length = data->length;
433 if (nargs > 0 && vtype(args[0]) == T_NUM) {
434 new_length = (size_t)js_getnum(args[0]);
435 }
436
437 ArrayBufferData *new_data = create_array_buffer_data(new_length);
438 if (!new_data) return js_mkerr(js, "Failed to allocate new ArrayBuffer");
439
440 size_t copy_length = data->length < new_length ? data->length : new_length;
441 memcpy(new_data->data, data->data, copy_length);
442
443 data->is_detached = 1;
444 data->length = 0;
445 js_set(js, this_val, "byteLength", js_mknum(0));
446
447 ant_value_t new_obj = js_mkobj(js);
448 ant_value_t proto = js_get_ctor_proto(js, "ArrayBuffer", 11);
449
450 if (is_special_object(proto)) js_set_proto_init(new_obj, proto);
451 js_set_native(new_obj, new_data, BUFFER_ARRAYBUFFER_NATIVE_TAG);
452 js_set(js, new_obj, "byteLength", js_mknum((double)new_length));
453 js_set_finalizer(new_obj, arraybuffer_finalize);
454
455 return new_obj;
456}
457
458// ArrayBuffer.prototype.transferToFixedLength(newLength)
459static ant_value_t js_arraybuffer_transferToFixedLength(ant_t *js, ant_value_t *args, int nargs) {
460 return js_arraybuffer_transfer(js, args, nargs);
461}
462
463// ArrayBuffer.prototype.detached getter
464static ant_value_t js_arraybuffer_detached_getter(ant_t *js, ant_value_t *args, int nargs) {
465 ant_value_t this_val = js_getthis(js);
466 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val);
467 if (!data) return js_false;
468
469 return js_bool(data->is_detached);
470}
471
472static ant_value_t js_arraybuffer_byteLength_getter(ant_t *js, ant_value_t *args, int nargs) {
473 (void)args; (void)nargs;
474 ant_value_t this_val = js_getthis(js);
475 ArrayBufferData *data = buffer_get_arraybuffer_data(this_val);
476 if (!data || data->is_detached) return js_mknum(0);
477 return js_mknum((double)data->length);
478}
479
480// ArrayBuffer.isView(value)
481static ant_value_t js_arraybuffer_isView(ant_t *js, ant_value_t *args, int nargs) {
482 if (nargs < 1) return js_false;
483 return js_bool(buffer_is_dataview(args[0]) || buffer_get_typedarray_data(args[0]) != NULL);
484}
485
486static ant_value_t buffer_require_bigint_value(ant_t *js, ant_value_t value) {
487 if (vtype(value) == T_BIGINT) return value;
488 if (is_object_type(value)) {
489 ant_value_t primitive = js_get_slot(value, SLOT_PRIMITIVE);
490 if (vtype(primitive) == T_BIGINT) return primitive;
491 }
492 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt");
493}
494
495static ant_value_t typedarray_write_value(ant_t *js, TypedArrayData *ta_data, size_t index, ant_value_t value) {
496 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) {
497 return js_mkundef();
498 }
499
500 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
501 switch (ta_data->type) {
502 case TYPED_ARRAY_INT8: ((int8_t *)data)[index] = (int8_t)js_to_number(js, value); return js_mkundef();
503 case TYPED_ARRAY_UINT8: data[index] = (uint8_t)js_to_number(js, value); return js_mkundef();
504 case TYPED_ARRAY_UINT8_CLAMPED: data[index] = (uint8_t)js_to_number(js, value); return js_mkundef();
505 case TYPED_ARRAY_INT16: ((int16_t *)data)[index] = (int16_t)js_to_number(js, value); return js_mkundef();
506 case TYPED_ARRAY_UINT16: ((uint16_t *)data)[index] = (uint16_t)js_to_number(js, value); return js_mkundef();
507 case TYPED_ARRAY_INT32: ((int32_t *)data)[index] = (int32_t)js_to_number(js, value); return js_mkundef();
508 case TYPED_ARRAY_UINT32: ((uint32_t *)data)[index] = (uint32_t)js_to_number(js, value); return js_mkundef();
509 case TYPED_ARRAY_FLOAT16: ((uint16_t *)data)[index] = double_to_half(js_to_number(js, value)); return js_mkundef();
510 case TYPED_ARRAY_FLOAT32: ((float *)data)[index] = (float)js_to_number(js, value); return js_mkundef();
511 case TYPED_ARRAY_FLOAT64: ((double *)data)[index] = js_to_number(js, value); return js_mkundef();
512 case TYPED_ARRAY_BIGINT64: {
513 ant_value_t bigint = buffer_require_bigint_value(js, value);
514 int64_t wrapped = 0;
515 if (is_err(bigint)) return bigint;
516 if (!bigint_to_int64_wrapping(js, bigint, &wrapped)) {
517 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt");
518 }
519 ((int64_t *)data)[index] = wrapped;
520 return js_mkundef();
521 }
522 case TYPED_ARRAY_BIGUINT64: {
523 ant_value_t bigint = buffer_require_bigint_value(js, value);
524 uint64_t wrapped = 0;
525 if (is_err(bigint)) return bigint;
526 if (!bigint_to_uint64_wrapping(js, bigint, &wrapped)) {
527 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt");
528 }
529 ((uint64_t *)data)[index] = wrapped;
530 return js_mkundef();
531 }
532 default:
533 return js_mkundef();
534 }
535}
536
537static ant_value_t typedarray_index_getter(ant_t *js, ant_value_t obj, const char *key, size_t key_len) {
538 if (key_len == 0 || key_len > 10) return js_mkundef();
539
540 size_t index = 0;
541 for (size_t i = 0; i < key_len; i++) {
542 char c = key[i];
543 if (c < '0' || c > '9') return js_mkundef();
544 index = index * 10 + (c - '0');
545 }
546
547 TypedArrayData *ta_data = buffer_get_typedarray_data(obj);
548 if (!ta_data || index >= ta_data->length) return js_mkundef();
549 if (!ta_data->buffer || ta_data->buffer->is_detached) return js_mkundef();
550
551 ant_value_t value;
552 if (!typedarray_read_value(js, ta_data, index, &value)) return js_mkundef();
553 return value;
554}
555
556static bool typedarray_index_setter(ant_t *js, ant_value_t obj, const char *key, size_t key_len, ant_value_t value) {
557 if (key_len == 0 || key_len > 10) return false;
558
559 size_t index = 0;
560 for (size_t i = 0; i < key_len; i++) {
561 char c = key[i];
562 if (c < '0' || c > '9') return false;
563 index = index * 10 + (c - '0');
564 }
565
566 TypedArrayData *ta_data = buffer_get_typedarray_data(obj);
567 if (!ta_data || index >= ta_data->length) return true;
568 if (!ta_data->buffer || ta_data->buffer->is_detached) return true;
569
570 return !is_err(typedarray_write_value(js, ta_data, index, value));
571}
572
573static bool typedarray_read_number(const TypedArrayData *ta_data, size_t index, double *out) {
574 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) return false;
575 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
576
577 static const void *dispatch[] = {
578 &&R_INT8, &&R_UINT8, &&R_UINT8, &&R_INT16, &&R_UINT16,
579 &&R_INT32, &&R_UINT32, &&R_FLOAT16, &&R_FLOAT32, &&R_FLOAT64, &&R_FAIL, &&R_FAIL
580 };
581
582 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto R_FAIL;
583 goto *dispatch[ta_data->type];
584
585 R_INT8: *out = (double)((int8_t *)data)[index]; return true;
586 R_UINT8: *out = (double)data[index]; return true;
587 R_INT16: *out = (double)((int16_t *)data)[index]; return true;
588 R_UINT16: *out = (double)((uint16_t *)data)[index]; return true;
589 R_INT32: *out = (double)((int32_t *)data)[index]; return true;
590 R_UINT32: *out = (double)((uint32_t *)data)[index]; return true;
591 R_FLOAT16: *out = half_to_double(((uint16_t *)data)[index]); return true;
592 R_FLOAT32: *out = (double)((float *)data)[index]; return true;
593 R_FLOAT64: *out = ((double *)data)[index]; return true;
594 R_FAIL: return false;
595}
596
597static bool typedarray_write_number(TypedArrayData *ta_data, size_t index, double value) {
598 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached || index >= ta_data->length) return false;
599 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
600
601 static const void *dispatch[] = {
602 &&W_INT8, &&W_UINT8, &&W_UINT8, &&W_INT16, &&W_UINT16,
603 &&W_INT32, &&W_UINT32, &&W_FLOAT16, &&W_FLOAT32, &&W_FLOAT64, &&W_FAIL, &&W_FAIL
604 };
605
606 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto W_FAIL;
607 goto *dispatch[ta_data->type];
608
609 W_INT8: ((int8_t *)data)[index] = (int8_t)value; return true;
610 W_UINT8: data[index] = (uint8_t)value; return true;
611 W_INT16: ((int16_t *)data)[index] = (int16_t)value; return true;
612 W_UINT16: ((uint16_t *)data)[index] = (uint16_t)value; return true;
613 W_INT32: ((int32_t *)data)[index] = (int32_t)value; return true;
614 W_UINT32: ((uint32_t *)data)[index] = (uint32_t)value; return true;
615 W_FLOAT16: ((uint16_t *)data)[index] = double_to_half(value); return true;
616 W_FLOAT32: ((float *)data)[index] = (float)value; return true;
617 W_FLOAT64: ((double *)data)[index] = value; return true;
618 W_FAIL: return false;
619}
620
621static ant_value_t js_typedarray_every(ant_t *js, ant_value_t *args, int nargs) {
622 if (nargs < 1 || !is_callable(args[0]))
623 return js_mkerr_typed(js, JS_ERR_TYPE, "TypedArray.prototype.every requires a callable");
624
625 ant_value_t this_val = js_getthis(js);
626 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
627 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
628 if (!ta_data->buffer || ta_data->buffer->is_detached)
629 return js_mkerr(js, "Cannot operate on a detached TypedArray");
630
631 ant_value_t callback = args[0];
632 ant_value_t this_arg = nargs > 1 ? args[1] : js_mkundef();
633
634 for (size_t i = 0; i < ta_data->length; i++) {
635 ant_value_t value = js_mkundef();
636 if (!typedarray_read_value(js, ta_data, i, &value)) return js_false;
637
638 ant_value_t call_args[3] = { value, js_mknum((double)i), this_val };
639 ant_value_t result = sv_vm_call(js->vm, js, callback, this_arg, call_args, 3, NULL, false);
640 if (is_err(result)) return result;
641 if (!js_truthy(js, result)) return js_false;
642 }
643
644 return js_true;
645}
646
647ant_value_t create_arraybuffer_obj(ant_t *js, ArrayBufferData *buffer) {
648 ant_value_t ab_obj = js_mkobj(js);
649 ant_value_t ab_proto = js_get_ctor_proto(js, "ArrayBuffer", 11);
650 if (is_special_object(ab_proto)) js_set_proto_init(ab_obj, ab_proto);
651
652 js_set_native(ab_obj, buffer, BUFFER_ARRAYBUFFER_NATIVE_TAG);
653 js_set(js, ab_obj, "byteLength", js_mknum((double)buffer->length));
654 js_set_finalizer(ab_obj, arraybuffer_finalize);
655 buffer->ref_count++;
656
657 return ab_obj;
658}
659
660ant_value_t create_typed_array_with_buffer(
661 ant_t *js, TypedArrayType type, ArrayBufferData *buffer,
662 size_t byte_offset, size_t length, const char *type_name, ant_value_t arraybuffer_obj
663) {
664 TypedArrayData *ta_data = ta_meta_alloc(sizeof(TypedArrayData));
665 if (!ta_data) return js_mkerr(js, "Failed to allocate TypedArray");
666
667 size_t element_size = get_element_size(type);
668 ta_data->buffer = buffer;
669 ta_data->type = type;
670 ta_data->byte_offset = byte_offset;
671 ta_data->byte_length = length * element_size;
672 ta_data->length = length;
673 buffer->ref_count++;
674
675 ant_value_t obj = js_mkobj(js);
676 ant_value_t proto = js_get_ctor_proto(js, type_name, strlen(type_name));
677 if (is_special_object(proto)) js_set_proto_init(obj, proto);
678
679 js_set_native(obj, ta_data, BUFFER_TYPEDARRAY_NATIVE_TAG);
680 js_set(js, obj, "length", js_mknum((double)length));
681 js_set(js, obj, "byteLength", js_mknum((double)(length * element_size)));
682 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset));
683 js_set(js, obj, "BYTES_PER_ELEMENT", js_mknum((double)element_size));
684 js_set(js, obj, "buffer", arraybuffer_obj);
685
686 js_set_getter(obj, typedarray_index_getter);
687 js_set_setter(obj, typedarray_index_setter);
688 js_set_finalizer(obj, typedarray_finalize);
689
690 return obj;
691}
692
693ant_value_t create_typed_array(
694 ant_t *js, TypedArrayType type, ArrayBufferData *buffer,
695 size_t byte_offset, size_t length, const char *type_name
696) {
697 ant_value_t ab_obj = create_arraybuffer_obj(js, buffer);
698 ant_value_t result = create_typed_array_with_buffer(js, type, buffer, byte_offset, length, type_name, ab_obj);
699 free_array_buffer_data(buffer); return result;
700}
701
702ant_value_t create_dataview_with_buffer(
703 ant_t *js, ArrayBufferData *buffer,
704 size_t byte_offset, size_t byte_length,
705 ant_value_t arraybuffer_obj
706) {
707 DataViewData *dv_data = ta_meta_alloc(sizeof(DataViewData));
708 if (!dv_data) return js_mkerr(js, "Failed to allocate DataView");
709
710 dv_data->buffer = buffer;
711 dv_data->byte_offset = byte_offset;
712 dv_data->byte_length = byte_length;
713 buffer->ref_count++;
714
715 ant_value_t obj = js_mkobj(js);
716 ant_value_t proto = js_get_ctor_proto(js, "DataView", 8);
717 if (is_special_object(proto)) js_set_proto_init(obj, proto);
718
719 js_set_native(obj, dv_data, BUFFER_DATAVIEW_NATIVE_TAG);
720 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_DATAVIEW));
721 js_mkprop_fast(js, obj, "buffer", 6, arraybuffer_obj);
722 js_set_descriptor(js, obj, "buffer", 6, 0);
723 js_set(js, obj, "byteLength", js_mknum((double)byte_length));
724 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset));
725 js_set_finalizer(obj, dataview_finalize);
726
727 return obj;
728}
729
730typedef struct {
731 ant_value_t *values;
732 size_t length;
733 size_t capacity;
734} iter_collect_ctx_t;
735
736static bool iter_collect_callback(ant_t *js, ant_value_t value, void *udata) {
737 iter_collect_ctx_t *ctx = (iter_collect_ctx_t *)udata;
738 if (ctx->length >= ctx->capacity) {
739 ctx->capacity *= 2;
740 ant_value_t *new_values = realloc(ctx->values, ctx->capacity * sizeof(ant_value_t));
741 if (!new_values) return false;
742 ctx->values = new_values;
743 }
744 ctx->values[ctx->length++] = value;
745 return true;
746}
747
748static ant_value_t js_typedarray_constructor(ant_t *js, ant_value_t *args, int nargs, TypedArrayType type, const char *type_name) {
749 if (nargs == 0) {
750 ArrayBufferData *buffer = create_array_buffer_data(0);
751 return create_typed_array(js, type, buffer, 0, 0, type_name);
752 }
753
754 if (vtype(args[0]) == T_NUM) {
755 size_t length = (size_t)js_getnum(args[0]);
756 size_t element_size = get_element_size(type);
757 ArrayBufferData *buffer = create_array_buffer_data(length * element_size);
758 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
759 return create_typed_array(js, type, buffer, 0, length, type_name);
760 }
761
762 ArrayBufferData *arraybuffer = buffer_get_arraybuffer_data(args[0]);
763 if (arraybuffer) {
764 ArrayBufferData *buffer = arraybuffer;
765 size_t byte_offset = 0;
766 size_t length = buffer->length;
767
768 if (nargs > 1 && vtype(args[1]) == T_NUM) {
769 byte_offset = (size_t)js_getnum(args[1]);
770 }
771
772 size_t element_size = get_element_size(type);
773
774 if (byte_offset > buffer->length) {
775 return js_mkerr(js, "Start offset is outside the bounds of the buffer");
776 }
777
778 if (nargs > 2 && vtype(args[2]) == T_NUM) {
779 length = (size_t)js_getnum(args[2]);
780 size_t available = buffer->length - byte_offset;
781 if (length > available / element_size) {
782 return js_mkerr(js, "Invalid TypedArray length");
783 }
784 } else length = (buffer->length - byte_offset) / element_size;
785
786 return create_typed_array_with_buffer(js, type, buffer, byte_offset, length, type_name, args[0]);
787 }
788
789 if (is_special_object(args[0])) {
790 ant_value_t len_val = js_get(js, args[0], "length");
791 size_t length = 0; ant_value_t *values = NULL;
792 bool is_iterable = false;
793
794 if (vtype(len_val) == T_NUM) length = (size_t)js_getnum(len_val); else {
795 iter_collect_ctx_t ctx = { .values = NULL, .length = 0, .capacity = 16 };
796 ctx.values = malloc(ctx.capacity * sizeof(ant_value_t));
797 if (!ctx.values) return js_mkerr(js, "Failed to allocate memory");
798 is_iterable = js_iter(js, args[0], iter_collect_callback, &ctx);
799
800 if (is_iterable) {
801 values = ctx.values;
802 length = ctx.length;
803 } else free(ctx.values);
804 }
805
806 if (length > 0 || is_iterable || vtype(len_val) == T_NUM) {
807 size_t element_size = get_element_size(type);
808 ArrayBufferData *buffer = create_array_buffer_data(length * element_size);
809 if (!buffer) { if (values) free(values); return js_mkerr(js, "Failed to allocate buffer"); }
810
811 ant_value_t result = create_typed_array(js, type, buffer, 0, length, type_name);
812 if (is_err(result)) { if (values) free(values); return result; }
813 TypedArrayData *result_ta = buffer_get_typedarray_data(result);
814
815 for (size_t i = 0; i < length; i++) {
816 ant_value_t elem;
817 if (values) elem = values[i]; else {
818 char idx_str[16];
819 snprintf(idx_str, sizeof(idx_str), "%zu", i);
820 elem = js_get(js, args[0], idx_str);
821 }
822 ant_value_t write_result = typedarray_write_value(js, result_ta, i, elem);
823 if (is_err(write_result)) {
824 if (values) free(values);
825 return write_result;
826 }
827 }
828 if (values) free(values);
829 return result;
830 }
831 }
832
833 return js_mkerr(js, "Invalid TypedArray constructor arguments");
834}
835
836// TypedArray.prototype.slice(begin, end)
837// TypedArray.prototype.at(index)
838static ant_value_t js_typedarray_at(ant_t *js, ant_value_t *args, int nargs) {
839 ant_value_t this_val = js_getthis(js);
840 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
841 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
842
843 if (nargs == 0 || vtype(args[0]) != T_NUM) return js_mkundef();
844
845 ssize_t len = (ssize_t)ta_data->length;
846 ssize_t idx = (ssize_t)js_getnum(args[0]);
847 if (idx < 0) idx += len;
848 if (idx < 0 || idx >= len) return js_mkundef();
849 if (!ta_data->buffer || ta_data->buffer->is_detached) return js_mkundef();
850
851 ant_value_t value;
852 if (!typedarray_read_value(js, ta_data, (size_t)idx, &value)) return js_mkundef();
853 return value;
854}
855
856static ant_value_t js_typedarray_slice(ant_t *js, ant_value_t *args, int nargs) {
857 ant_value_t this_val = js_getthis(js);
858 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
859 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
860
861 ssize_t len = (ssize_t)ta_data->length;
862 ssize_t begin = 0, end = len;
863
864 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]);
865 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]);
866
867 begin = normalize_index(begin, len);
868 end = normalize_index(end, len);
869 if (end < begin) end = begin;
870
871 size_t new_length = (size_t)(end - begin);
872 size_t element_size = get_element_size(ta_data->type);
873 ArrayBufferData *new_buffer = create_array_buffer_data(new_length * element_size);
874 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer");
875
876 memcpy(
877 new_buffer->data,
878 ta_data->buffer->data + ta_data->byte_offset + (size_t)begin * element_size,
879 new_length * element_size
880 );
881
882 ant_value_t out = create_typed_array_like(
883 js, this_val, ta_data->type,
884 new_buffer, 0, new_length
885 ); free_array_buffer_data(new_buffer);
886
887 return out;
888}
889
890// TypedArray.prototype.subarray(begin, end)
891static ant_value_t js_typedarray_subarray(ant_t *js, ant_value_t *args, int nargs) {
892 ant_value_t this_val = js_getthis(js);
893 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
894 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
895
896 ssize_t len = (ssize_t)ta_data->length;
897 ssize_t begin = 0, end = len;
898
899 if (nargs > 0 && vtype(args[0]) == T_NUM) begin = (ssize_t)js_getnum(args[0]);
900 if (nargs > 1 && vtype(args[1]) == T_NUM) end = (ssize_t)js_getnum(args[1]);
901
902 begin = normalize_index(begin, len);
903 end = normalize_index(end, len);
904 if (end < begin) end = begin;
905
906 size_t new_length = (size_t)(end - begin);
907 size_t element_size = get_element_size(ta_data->type);
908 size_t new_offset = ta_data->byte_offset + (size_t)begin * element_size;
909
910 return create_typed_array_like(
911 js, this_val, ta_data->type,
912 ta_data->buffer, new_offset, new_length
913 );
914}
915
916// TypedArray.prototype.fill(value, start, end)
917static ant_value_t js_typedarray_fill(ant_t *js, ant_value_t *args, int nargs) {
918 ant_value_t this_val = js_getthis(js);
919 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
920 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
921
922 ant_value_t value = nargs > 0 ? args[0] : js_mknum(0);
923
924 ssize_t len = (ssize_t)ta_data->length;
925 ssize_t start = 0, end = len;
926
927 if (nargs > 1 && vtype(args[1]) == T_NUM) start = (ssize_t)js_getnum(args[1]);
928 if (nargs > 2 && vtype(args[2]) == T_NUM) end = (ssize_t)js_getnum(args[2]);
929
930 start = normalize_index(start, len);
931 end = normalize_index(end, len);
932 if (end < start) end = start;
933
934 if (ta_data->type == TYPED_ARRAY_BIGINT64 || ta_data->type == TYPED_ARRAY_BIGUINT64) {
935 for (ssize_t i = start; i < end; i++) {
936 ant_value_t write_result = typedarray_write_value(js, ta_data, (size_t)i, value);
937 if (is_err(write_result)) return write_result;
938 }
939 return this_val;
940 }
941
942 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
943
944 static const void *dispatch[] = {
945 &&L_INT8, &&L_UINT8, &&L_UINT8, &&L_INT16, &&L_UINT16,
946 &&L_INT32, &&L_UINT32, &&L_FLOAT16, &&L_FLOAT32, &&L_FLOAT64, &&L_DONE, &&L_DONE
947 };
948
949 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto L_DONE;
950 goto *dispatch[ta_data->type];
951
952 L_INT8:
953 for (ssize_t i = start; i < end; i++) ((int8_t*)data)[i] = (int8_t)js_to_number(js, value);
954 goto L_DONE;
955 L_UINT8:
956 for (ssize_t i = start; i < end; i++) data[i] = (uint8_t)js_to_number(js, value);
957 goto L_DONE;
958 L_INT16:
959 for (ssize_t i = start; i < end; i++) ((int16_t*)data)[i] = (int16_t)js_to_number(js, value);
960 goto L_DONE;
961 L_UINT16:
962 for (ssize_t i = start; i < end; i++) ((uint16_t*)data)[i] = (uint16_t)js_to_number(js, value);
963 goto L_DONE;
964 L_INT32:
965 for (ssize_t i = start; i < end; i++) ((int32_t*)data)[i] = (int32_t)js_to_number(js, value);
966 goto L_DONE;
967 L_UINT32:
968 for (ssize_t i = start; i < end; i++) ((uint32_t*)data)[i] = (uint32_t)js_to_number(js, value);
969 goto L_DONE;
970 L_FLOAT16:
971 for (ssize_t i = start; i < end; i++) ((uint16_t*)data)[i] = double_to_half(js_to_number(js, value));
972 goto L_DONE;
973 L_FLOAT32:
974 for (ssize_t i = start; i < end; i++) ((float*)data)[i] = (float)js_to_number(js, value);
975 goto L_DONE;
976 L_FLOAT64:
977 for (ssize_t i = start; i < end; i++) ((double*)data)[i] = js_to_number(js, value);
978 goto L_DONE;
979 L_DONE:
980 return this_val;
981}
982
983// TypedArray.prototype.set(source, offset = 0)
984static ant_value_t js_typedarray_set(ant_t *js, ant_value_t *args, int nargs) {
985 if (nargs < 1) return js_mkerr(js, "set requires source argument");
986
987 ant_value_t this_val = js_getthis(js);
988 TypedArrayData *dst = buffer_get_typedarray_data(this_val);
989 if (!dst) return js_mkerr(js, "Invalid TypedArray");
990 if (!dst->buffer || dst->buffer->is_detached) return js_mkerr(js, "Cannot operate on a detached TypedArray");
991
992 ssize_t offset_i = 0;
993 if (nargs > 1 && vtype(args[1]) == T_NUM) offset_i = (ssize_t)js_getnum(args[1]);
994 if (offset_i < 0) return js_mkerr(js, "Offset out of bounds");
995 size_t offset = (size_t)offset_i;
996 if (offset > dst->length) return js_mkerr(js, "Offset out of bounds");
997
998 ant_value_t src_val = args[0];
999 TypedArrayData *src_ta = buffer_get_typedarray_data(src_val);
1000
1001 if (src_ta && src_ta->buffer && !src_ta->buffer->is_detached) {
1002 size_t src_len = src_ta->length;
1003 if (offset + src_len > dst->length) return js_mkerr(js, "Source is too large");
1004
1005 if (src_ta->type == dst->type) {
1006 size_t el = get_element_size(dst->type);
1007 uint8_t *dst_data = dst->buffer->data + dst->byte_offset + offset * el;
1008 uint8_t *src_data = src_ta->buffer->data + src_ta->byte_offset;
1009 memmove(dst_data, src_data, src_len * el);
1010 return js_mkundef();
1011 }
1012
1013 for (size_t i = 0; i < src_len; i++) {
1014 ant_value_t value = js_mkundef();
1015 if (!typedarray_read_value(js, src_ta, i, &value)) value = js_mknum(0);
1016 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, value);
1017 if (is_err(write_result)) return write_result;
1018 }
1019 return js_mkundef();
1020 }
1021
1022 if (!is_special_object(src_val) && vtype(src_val) != T_STR) {
1023 return js_mkerr(js, "set source must be array-like or TypedArray");
1024 }
1025
1026 size_t src_len = 0;
1027 if (vtype(src_val) == T_STR) {
1028 src_len = (size_t)vstrlen(js, src_val);
1029 } else {
1030 ant_value_t len_val = js_get(js, src_val, "length");
1031 src_len = vtype(len_val) == T_NUM ? (size_t)js_getnum(len_val) : 0;
1032 }
1033
1034 if (offset + src_len > dst->length) return js_mkerr(js, "Source is too large");
1035
1036 for (size_t i = 0; i < src_len; i++) {
1037 if (vtype(src_val) == T_STR) {
1038 ant_offset_t slen = 0;
1039 ant_offset_t soff = vstr(js, src_val, &slen);
1040 const unsigned char *sptr = (const unsigned char *)(uintptr_t)soff;
1041 double value = 0;
1042 if (i < (size_t)slen) value = sptr[i];
1043 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, js_mknum(value));
1044 if (is_err(write_result)) return write_result;
1045 } else {
1046 char idx[24];
1047 size_t idx_len = uint_to_str(idx, sizeof(idx), (uint64_t)i);
1048 idx[idx_len] = '\0';
1049 ant_value_t elem = js_get(js, src_val, idx);
1050 ant_value_t write_result = typedarray_write_value(js, dst, offset + i, elem);
1051 if (is_err(write_result)) return write_result;
1052 }
1053 }
1054
1055 return js_mkundef();
1056}
1057
1058// TypedArray.prototype.copyWithin(target, start, end)
1059static ant_value_t js_typedarray_copyWithin(ant_t *js, ant_value_t *args, int nargs) {
1060 ant_value_t this_val = js_getthis(js);
1061 TypedArrayData *ta = buffer_get_typedarray_data(this_val);
1062 if (!ta) return js_mkerr(js, "Invalid TypedArray");
1063 if (!ta->buffer || ta->buffer->is_detached) return js_mkerr(js, "Cannot operate on a detached TypedArray");
1064
1065 ssize_t len = (ssize_t)ta->length;
1066 if (len <= 0) return this_val;
1067
1068 ssize_t target = 0, start = 0, end = len;
1069 if (nargs > 0 && vtype(args[0]) == T_NUM) target = (ssize_t)js_getnum(args[0]);
1070 if (nargs > 1 && vtype(args[1]) == T_NUM) start = (ssize_t)js_getnum(args[1]);
1071 if (nargs > 2 && vtype(args[2]) == T_NUM) end = (ssize_t)js_getnum(args[2]);
1072
1073 target = normalize_index(target, len);
1074 start = normalize_index(start, len);
1075 end = normalize_index(end, len);
1076 if (end < start) end = start;
1077 if (target >= len || start >= len || end <= start) return this_val;
1078
1079 size_t count = (size_t)(end - start);
1080 size_t max_to_end = (size_t)(len - target);
1081 if (count > max_to_end) count = max_to_end;
1082 if (count == 0) return this_val;
1083
1084 size_t el = get_element_size(ta->type);
1085 uint8_t *base = ta->buffer->data + ta->byte_offset;
1086 memmove(base + (size_t)target * el, base + (size_t)start * el, count * el);
1087 return this_val;
1088}
1089
1090// TypedArray.prototype.toReversed()
1091static ant_value_t js_typedarray_toReversed(ant_t *js, ant_value_t *args, int nargs) {
1092 (void)args; (void)nargs;
1093 ant_value_t this_val = js_getthis(js);
1094 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
1095 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
1096
1097 size_t length = ta_data->length;
1098 size_t element_size = get_element_size(ta_data->type);
1099 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size);
1100 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer");
1101
1102 uint8_t *src = ta_data->buffer->data + ta_data->byte_offset;
1103 uint8_t *dst = new_buffer->data;
1104
1105 for (size_t i = 0; i < length; i++) {
1106 memcpy(dst + i * element_size, src + (length - 1 - i) * element_size, element_size);
1107 }
1108
1109 ant_value_t out = create_typed_array_like(
1110 js, this_val, ta_data->type,
1111 new_buffer, 0, length
1112 ); free_array_buffer_data(new_buffer);
1113
1114 return out;
1115}
1116
1117// TypedArray.prototype.toSorted(comparefn)
1118static ant_value_t js_typedarray_toSorted(ant_t *js, ant_value_t *args, int nargs) {
1119 ant_value_t this_val = js_getthis(js);
1120 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
1121 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
1122
1123 size_t length = ta_data->length;
1124 size_t element_size = get_element_size(ta_data->type);
1125 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size);
1126 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer");
1127
1128 memcpy(new_buffer->data, ta_data->buffer->data + ta_data->byte_offset, length * element_size);
1129 ant_value_t result = create_typed_array_like(js, this_val, ta_data->type, new_buffer, 0, length);
1130
1131 free_array_buffer_data(new_buffer);
1132 if (is_err(result)) return result;
1133
1134 TypedArrayData *result_ta = buffer_get_typedarray_data(result);
1135 uint8_t *data = result_ta->buffer->data;
1136
1137 ant_value_t comparefn = (nargs > 0 && vtype(args[0]) == T_FUNC) ? args[0] : js_mkundef();
1138 bool has_comparefn = vtype(comparefn) == T_FUNC;
1139
1140 for (size_t i = 1; i < length; i++) {
1141 for (size_t j = i; j > 0; j--) {
1142 double a_val, b_val;
1143 int cmp;
1144
1145 static const void *read_dispatch[] = {
1146 &&R_INT8, &&R_UINT8, &&R_UINT8, &&R_INT16, &&R_UINT16,
1147 &&R_INT32, &&R_UINT32, &&R_FLOAT16, &&R_FLOAT32, &&R_FLOAT64, &&R_DONE, &&R_DONE
1148 };
1149
1150 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto R_DONE;
1151 goto *read_dispatch[ta_data->type];
1152
1153 R_INT8: a_val = (double)((int8_t*)data)[j-1]; b_val = (double)((int8_t*)data)[j]; goto R_COMPARE;
1154 R_UINT8: a_val = (double)data[j-1]; b_val = (double)data[j]; goto R_COMPARE;
1155 R_INT16: a_val = (double)((int16_t*)data)[j-1]; b_val = (double)((int16_t*)data)[j]; goto R_COMPARE;
1156 R_UINT16: a_val = (double)((uint16_t*)data)[j-1]; b_val = (double)((uint16_t*)data)[j]; goto R_COMPARE;
1157 R_INT32: a_val = (double)((int32_t*)data)[j-1]; b_val = (double)((int32_t*)data)[j]; goto R_COMPARE;
1158 R_UINT32: a_val = (double)((uint32_t*)data)[j-1]; b_val = (double)((uint32_t*)data)[j]; goto R_COMPARE;
1159 R_FLOAT16: a_val = half_to_double(((uint16_t*)data)[j-1]); b_val = half_to_double(((uint16_t*)data)[j]); goto R_COMPARE;
1160 R_FLOAT32: a_val = (double)((float*)data)[j-1]; b_val = (double)((float*)data)[j]; goto R_COMPARE;
1161 R_FLOAT64: a_val = ((double*)data)[j-1]; b_val = ((double*)data)[j]; goto R_COMPARE;
1162 R_DONE: goto SORT_DONE;
1163
1164 R_COMPARE:
1165 if (has_comparefn) {
1166 ant_value_t cmp_args[2] = { js_mknum(a_val), js_mknum(b_val) };
1167 ant_value_t cmp_result = sv_vm_call(js->vm, js, comparefn, js_mkundef(), cmp_args, 2, NULL, false);
1168 cmp = (int)js_getnum(cmp_result);
1169 } else {
1170 cmp = (a_val > b_val) ? 1 : ((a_val < b_val) ? -1 : 0);
1171 }
1172
1173 if (cmp <= 0) break;
1174
1175 static const void *swap_dispatch[] = {
1176 &&S_INT8, &&S_UINT8, &&S_UINT8, &&S_INT16, &&S_UINT16,
1177 &&S_INT32, &&S_UINT32, &&S_FLOAT16, &&S_FLOAT32, &&S_FLOAT64, &&S_DONE, &&S_DONE
1178 };
1179
1180 if (ta_data->type > TYPED_ARRAY_BIGUINT64) goto S_DONE;
1181 goto *swap_dispatch[ta_data->type];
1182
1183 S_INT8: { int8_t tmp = ((int8_t*)data)[j-1]; ((int8_t*)data)[j-1] = ((int8_t*)data)[j]; ((int8_t*)data)[j] = tmp; goto S_DONE; }
1184 S_UINT8: { uint8_t tmp = data[j-1]; data[j-1] = data[j]; data[j] = tmp; goto S_DONE; }
1185 S_INT16: { int16_t tmp = ((int16_t*)data)[j-1]; ((int16_t*)data)[j-1] = ((int16_t*)data)[j]; ((int16_t*)data)[j] = tmp; goto S_DONE; }
1186 S_UINT16: { uint16_t tmp = ((uint16_t*)data)[j-1]; ((uint16_t*)data)[j-1] = ((uint16_t*)data)[j]; ((uint16_t*)data)[j] = tmp; goto S_DONE; }
1187 S_INT32: { int32_t tmp = ((int32_t*)data)[j-1]; ((int32_t*)data)[j-1] = ((int32_t*)data)[j]; ((int32_t*)data)[j] = tmp; goto S_DONE; }
1188 S_UINT32: { uint32_t tmp = ((uint32_t*)data)[j-1]; ((uint32_t*)data)[j-1] = ((uint32_t*)data)[j]; ((uint32_t*)data)[j] = tmp; goto S_DONE; }
1189 S_FLOAT16: { uint16_t tmp = ((uint16_t*)data)[j-1]; ((uint16_t*)data)[j-1] = ((uint16_t*)data)[j]; ((uint16_t*)data)[j] = tmp; goto S_DONE; }
1190 S_FLOAT32: { float tmp = ((float*)data)[j-1]; ((float*)data)[j-1] = ((float*)data)[j]; ((float*)data)[j] = tmp; goto S_DONE; }
1191 S_FLOAT64: { double tmp = ((double*)data)[j-1]; ((double*)data)[j-1] = ((double*)data)[j]; ((double*)data)[j] = tmp; goto S_DONE; }
1192 S_DONE:;
1193 }
1194 }
1195
1196 SORT_DONE:
1197 return result;
1198}
1199
1200// TypedArray.prototype.with(index, value)
1201static ant_value_t js_typedarray_with(ant_t *js, ant_value_t *args, int nargs) {
1202 if (nargs < 2) return js_mkerr(js, "with requires index and value");
1203
1204 ant_value_t this_val = js_getthis(js);
1205 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
1206 if (!ta_data) return js_mkerr(js, "Invalid TypedArray");
1207
1208 ssize_t index = (ssize_t)js_getnum(args[0]);
1209 size_t length = ta_data->length;
1210
1211 if (index < 0) index = (ssize_t)length + index;
1212 if (index < 0 || (size_t)index >= length) {
1213 return js_mkerr(js, "Index out of bounds");
1214 }
1215
1216 size_t element_size = get_element_size(ta_data->type);
1217 ArrayBufferData *new_buffer = create_array_buffer_data(length * element_size);
1218 if (!new_buffer) return js_mkerr(js, "Failed to allocate new buffer");
1219
1220 memcpy(new_buffer->data, ta_data->buffer->data + ta_data->byte_offset, length * element_size);
1221
1222 ant_value_t out = create_typed_array_like(
1223 js, this_val, ta_data->type,
1224 new_buffer, 0, length
1225 ); free_array_buffer_data(new_buffer);
1226 if (is_err(out)) return out;
1227
1228 TypedArrayData *out_ta = buffer_get_typedarray_data(out);
1229 ant_value_t write_result = typedarray_write_value(js, out_ta, (size_t)index, args[1]);
1230 if (is_err(write_result)) return write_result;
1231
1232 return out;
1233}
1234
1235#define DEFINE_TYPEDARRAY_CONSTRUCTOR(name, type) \
1236 static ant_value_t js_##name##_constructor(ant_t *js, ant_value_t *args, int nargs) { \
1237 if (vtype(js->new_target) == T_UNDEF) return js_mkerr_typed(js, JS_ERR_TYPE, #name " constructor requires 'new'"); \
1238 return js_typedarray_constructor(js, args, nargs, type, #name); \
1239 }
1240
1241DEFINE_TYPEDARRAY_CONSTRUCTOR(Int8Array, TYPED_ARRAY_INT8)
1242DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint8Array, TYPED_ARRAY_UINT8)
1243DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint8ClampedArray, TYPED_ARRAY_UINT8_CLAMPED)
1244DEFINE_TYPEDARRAY_CONSTRUCTOR(Int16Array, TYPED_ARRAY_INT16)
1245DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint16Array, TYPED_ARRAY_UINT16)
1246DEFINE_TYPEDARRAY_CONSTRUCTOR(Int32Array, TYPED_ARRAY_INT32)
1247DEFINE_TYPEDARRAY_CONSTRUCTOR(Uint32Array, TYPED_ARRAY_UINT32)
1248DEFINE_TYPEDARRAY_CONSTRUCTOR(Float16Array, TYPED_ARRAY_FLOAT16)
1249DEFINE_TYPEDARRAY_CONSTRUCTOR(Float32Array, TYPED_ARRAY_FLOAT32)
1250DEFINE_TYPEDARRAY_CONSTRUCTOR(Float64Array, TYPED_ARRAY_FLOAT64)
1251DEFINE_TYPEDARRAY_CONSTRUCTOR(BigInt64Array, TYPED_ARRAY_BIGINT64)
1252DEFINE_TYPEDARRAY_CONSTRUCTOR(BigUint64Array, TYPED_ARRAY_BIGUINT64)
1253
1254static ant_value_t js_typedarray_from(ant_t *js, ant_value_t *args, int nargs, TypedArrayType type, const char *type_name) {
1255 if (nargs < 1) return js_mkerr_typed(js, JS_ERR_TYPE, "%s.from requires at least 1 argument", type_name);
1256
1257 ant_value_t source = args[0];
1258 bool has_map = nargs >= 2 && vtype(args[1]) != T_UNDEF;
1259
1260 ant_value_t map_fn = js_mkundef();
1261 ant_value_t this_arg = nargs >= 3 ? args[2] : js_mkundef();
1262 ant_value_t result = js_mkundef();
1263 ant_value_t *collected = NULL;
1264
1265 gc_temp_root_scope_t temp_roots = {0};
1266 bool temp_roots_active = false;
1267
1268 if (has_map) {
1269 if (!is_callable(args[1])) return js_mkerr_typed(
1270 js, JS_ERR_TYPE, "%s.from: mapFn is not a function", type_name
1271 );
1272 map_fn = args[1];
1273 }
1274
1275 gc_temp_root_scope_begin(js, &temp_roots);
1276 temp_roots_active = true;
1277
1278 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, source))) goto oom;
1279 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, map_fn))) goto oom;
1280 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, this_arg))) goto oom;
1281
1282 size_t count = 0, cap = 16;
1283 collected = malloc(cap * sizeof(ant_value_t));
1284 if (!collected) goto oom;
1285
1286 js_iter_t it;
1287 if (js_iter_open(js, source, &it)) {
1288 ant_value_t item;
1289 while (js_iter_next(js, &it, &item)) {
1290 if (count >= cap) {
1291 cap *= 2;
1292 ant_value_t *tmp = realloc(collected, cap * sizeof(ant_value_t));
1293 if (!tmp) goto oom;
1294 collected = tmp;
1295 }
1296 if (has_map) {
1297 ant_value_t map_args[2] = { item, js_mknum((double)count) };
1298 item = sv_vm_call(js->vm, js, map_fn, this_arg, map_args, 2, NULL, false);
1299 if (is_err(item)) {
1300 result = item;
1301 goto done;
1302 }
1303 }
1304 collected[count++] = item;
1305 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, item))) goto oom;
1306 }
1307 js_iter_close(js, &it);
1308 } else {
1309 ant_value_t len_val = js_get(js, source, "length");
1310 size_t len = vtype(len_val) == T_NUM ? (size_t)js_getnum(len_val) : 0;
1311 for (size_t i = 0; i < len; i++) {
1312 char idx[16];
1313 snprintf(idx, sizeof(idx), "%zu", i);
1314 ant_value_t item = js_get(js, source, idx);
1315 if (count >= cap) {
1316 cap *= 2;
1317 ant_value_t *tmp = realloc(collected, cap * sizeof(ant_value_t));
1318 if (!tmp) goto oom;
1319 collected = tmp;
1320 }
1321 if (has_map) {
1322 ant_value_t map_args[2] = { item, js_mknum((double)i) };
1323 item = sv_vm_call(js->vm, js, map_fn, this_arg, map_args, 2, NULL, false);
1324 if (is_err(item)) {
1325 result = item;
1326 goto done;
1327 }
1328 }
1329 collected[count++] = item;
1330 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, item))) goto oom;
1331 }
1332 }
1333
1334 size_t elem_size = get_element_size(type);
1335 ArrayBufferData *buffer = create_array_buffer_data(count * elem_size);
1336 if (!buffer) goto oom;
1337
1338 result = create_typed_array(js, type, buffer, 0, count, type_name);
1339 if (is_err(result)) goto done;
1340 if (!gc_temp_root_handle_valid(gc_temp_root_add(&temp_roots, result))) goto oom;
1341 TypedArrayData *result_ta = buffer_get_typedarray_data(result);
1342
1343 for (size_t i = 0; i < count; i++) {
1344 ant_value_t write_result = typedarray_write_value(js, result_ta, i, collected[i]);
1345 if (is_err(write_result)) {
1346 result = write_result;
1347 goto done;
1348 }
1349 }
1350
1351done:
1352 if (temp_roots_active) gc_temp_root_scope_end(&temp_roots);
1353 free(collected);
1354 return result;
1355
1356oom:
1357 result = js_mkerr(js, "oom");
1358 goto done;
1359}
1360
1361#define DEFINE_TYPEDARRAY_FROM(name, type) \
1362 static ant_value_t js_##name##_from(ant_t *js, ant_value_t *args, int nargs) { \
1363 return js_typedarray_from(js, args, nargs, type, #name); \
1364 }
1365
1366DEFINE_TYPEDARRAY_FROM(Int8Array, TYPED_ARRAY_INT8)
1367DEFINE_TYPEDARRAY_FROM(Uint8Array, TYPED_ARRAY_UINT8)
1368DEFINE_TYPEDARRAY_FROM(Uint8ClampedArray, TYPED_ARRAY_UINT8_CLAMPED)
1369DEFINE_TYPEDARRAY_FROM(Int16Array, TYPED_ARRAY_INT16)
1370DEFINE_TYPEDARRAY_FROM(Uint16Array, TYPED_ARRAY_UINT16)
1371DEFINE_TYPEDARRAY_FROM(Int32Array, TYPED_ARRAY_INT32)
1372DEFINE_TYPEDARRAY_FROM(Uint32Array, TYPED_ARRAY_UINT32)
1373DEFINE_TYPEDARRAY_FROM(Float16Array, TYPED_ARRAY_FLOAT16)
1374DEFINE_TYPEDARRAY_FROM(Float32Array, TYPED_ARRAY_FLOAT32)
1375DEFINE_TYPEDARRAY_FROM(Float64Array, TYPED_ARRAY_FLOAT64)
1376DEFINE_TYPEDARRAY_FROM(BigInt64Array, TYPED_ARRAY_BIGINT64)
1377DEFINE_TYPEDARRAY_FROM(BigUint64Array, TYPED_ARRAY_BIGUINT64)
1378
1379static ant_value_t js_dataview_constructor(ant_t *js, ant_value_t *args, int nargs) {
1380 if (vtype(js->new_target) == T_UNDEF) {
1381 return js_mkerr_typed(js, JS_ERR_TYPE, "DataView constructor requires 'new'");
1382 }
1383 if (nargs < 1) {
1384 return js_mkerr(js, "DataView requires an ArrayBuffer");
1385 }
1386
1387 ArrayBufferData *buffer = buffer_get_arraybuffer_data(args[0]);
1388 if (!buffer) {
1389 return js_mkerr(js, "First argument must be an ArrayBuffer");
1390 }
1391 size_t byte_offset = 0;
1392 size_t byte_length = buffer->length;
1393
1394 if (nargs > 1 && vtype(args[1]) == T_NUM) {
1395 byte_offset = (size_t)js_getnum(args[1]);
1396 }
1397
1398 if (byte_offset > buffer->length) {
1399 return js_mkerr(js, "Start offset is outside the bounds of the buffer");
1400 }
1401
1402 if (nargs > 2 && vtype(args[2]) == T_NUM) {
1403 byte_length = (size_t)js_getnum(args[2]);
1404 if (byte_length > buffer->length - byte_offset) {
1405 return js_mkerr(js, "Invalid DataView length");
1406 }
1407 } else byte_length = buffer->length - byte_offset;
1408
1409 DataViewData *dv_data = ta_meta_alloc(sizeof(DataViewData));
1410 if (!dv_data) return js_mkerr(js, "Failed to allocate DataView");
1411
1412 dv_data->buffer = buffer;
1413 dv_data->byte_offset = byte_offset;
1414 dv_data->byte_length = byte_length;
1415 buffer->ref_count++;
1416
1417 ant_value_t obj = js_mkobj(js);
1418 ant_value_t proto = js_get_ctor_proto(js, "DataView", 8);
1419 if (is_special_object(proto)) js_set_proto_init(obj, proto);
1420
1421 js_set_native(obj, dv_data, BUFFER_DATAVIEW_NATIVE_TAG);
1422 js_set_slot(obj, SLOT_BRAND, js_mknum(BRAND_DATAVIEW));
1423 js_mkprop_fast(js, obj, "buffer", 6, args[0]);
1424 js_set_descriptor(js, obj, "buffer", 6, 0);
1425
1426 js_set(js, obj, "byteLength", js_mknum((double)byte_length));
1427 js_set(js, obj, "byteOffset", js_mknum((double)byte_offset));
1428 js_set_finalizer(obj, dataview_finalize);
1429
1430 return obj;
1431}
1432
1433// DataView.prototype.getUint8(byteOffset)
1434static ant_value_t js_dataview_getInt8(ant_t *js, ant_value_t *args, int nargs) {
1435 if (nargs < 1) return js_mkerr(js, "getInt8 requires byteOffset");
1436
1437 ant_value_t this_val = js_getthis(js);
1438 DataViewData *dv = buffer_get_dataview_data(this_val);
1439 if (!dv) return js_mkerr(js, "Not a DataView");
1440 size_t offset = (size_t)js_getnum(args[0]);
1441
1442 if (offset >= dv->byte_length) {
1443 return js_mkerr(js, "Offset out of bounds");
1444 }
1445
1446 int8_t value = (int8_t)dv->buffer->data[dv->byte_offset + offset];
1447 return js_mknum((double)value);
1448}
1449
1450// DataView.prototype.setInt8(byteOffset, value)
1451static ant_value_t js_dataview_setInt8(ant_t *js, ant_value_t *args, int nargs) {
1452 if (nargs < 2) return js_mkerr(js, "setInt8 requires byteOffset and value");
1453
1454 ant_value_t this_val = js_getthis(js);
1455 DataViewData *dv = buffer_get_dataview_data(this_val);
1456 if (!dv) return js_mkerr(js, "Not a DataView");
1457 size_t offset = (size_t)js_getnum(args[0]);
1458 int8_t value = (int8_t)js_to_int32(js_getnum(args[1]));
1459
1460 if (offset >= dv->byte_length) {
1461 return js_mkerr(js, "Offset out of bounds");
1462 }
1463
1464 dv->buffer->data[dv->byte_offset + offset] = (uint8_t)value;
1465 return js_mkundef();
1466}
1467
1468// DataView.prototype.getUint8(byteOffset)
1469static ant_value_t js_dataview_getUint8(ant_t *js, ant_value_t *args, int nargs) {
1470 if (nargs < 1) return js_mkerr(js, "getUint8 requires byteOffset");
1471
1472 ant_value_t this_val = js_getthis(js);
1473 DataViewData *dv = buffer_get_dataview_data(this_val);
1474 if (!dv) return js_mkerr(js, "Not a DataView");
1475 size_t offset = (size_t)js_getnum(args[0]);
1476
1477 if (offset >= dv->byte_length) {
1478 return js_mkerr(js, "Offset out of bounds");
1479 }
1480
1481 uint8_t value = dv->buffer->data[dv->byte_offset + offset];
1482 return js_mknum((double)value);
1483}
1484
1485// DataView.prototype.setUint8(byteOffset, value)
1486static ant_value_t js_dataview_setUint8(ant_t *js, ant_value_t *args, int nargs) {
1487 if (nargs < 2) return js_mkerr(js, "setUint8 requires byteOffset and value");
1488
1489 ant_value_t this_val = js_getthis(js);
1490 DataViewData *dv = buffer_get_dataview_data(this_val);
1491 if (!dv) return js_mkerr(js, "Not a DataView");
1492 size_t offset = (size_t)js_getnum(args[0]);
1493 uint8_t value = (uint8_t)js_to_uint32(js_getnum(args[1]));
1494
1495 if (offset >= dv->byte_length) {
1496 return js_mkerr(js, "Offset out of bounds");
1497 }
1498
1499 dv->buffer->data[dv->byte_offset + offset] = value;
1500 return js_mkundef();
1501}
1502
1503// DataView.prototype.getInt16(byteOffset, littleEndian)
1504static ant_value_t js_dataview_getInt16(ant_t *js, ant_value_t *args, int nargs) {
1505 if (nargs < 1) return js_mkerr(js, "getInt16 requires byteOffset");
1506
1507 ant_value_t this_val = js_getthis(js);
1508 DataViewData *dv = buffer_get_dataview_data(this_val);
1509 if (!dv) return js_mkerr(js, "Not a DataView");
1510 size_t offset = (size_t)js_getnum(args[0]);
1511 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1512
1513 if (offset + 2 > dv->byte_length) {
1514 return js_mkerr(js, "Offset out of bounds");
1515 }
1516
1517 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1518 int16_t value;
1519
1520 if (little_endian) {
1521 value = (int16_t)(ptr[0] | (ptr[1] << 8));
1522 } else {
1523 value = (int16_t)((ptr[0] << 8) | ptr[1]);
1524 }
1525
1526 return js_mknum((double)value);
1527}
1528
1529// DataView.prototype.getUint16(byteOffset, littleEndian)
1530static ant_value_t js_dataview_getUint16(ant_t *js, ant_value_t *args, int nargs) {
1531 if (nargs < 1) return js_mkerr(js, "getUint16 requires byteOffset");
1532
1533 ant_value_t this_val = js_getthis(js);
1534 DataViewData *dv = buffer_get_dataview_data(this_val);
1535 if (!dv) return js_mkerr(js, "Not a DataView");
1536 size_t offset = (size_t)js_getnum(args[0]);
1537 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1538
1539 if (offset + 2 > dv->byte_length) {
1540 return js_mkerr(js, "Offset out of bounds");
1541 }
1542
1543 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1544 uint16_t value;
1545
1546 if (little_endian) value = (uint16_t)(ptr[0] | (ptr[1] << 8));
1547 else value = (uint16_t)((ptr[0] << 8) | ptr[1]);
1548
1549 return js_mknum((double)value);
1550}
1551
1552// DataView.prototype.setUint16(byteOffset, value, littleEndian)
1553static ant_value_t js_dataview_setUint16(ant_t *js, ant_value_t *args, int nargs) {
1554 if (nargs < 2) return js_mkerr(js, "setUint16 requires byteOffset and value");
1555
1556 ant_value_t this_val = js_getthis(js);
1557 DataViewData *dv = buffer_get_dataview_data(this_val);
1558 if (!dv) return js_mkerr(js, "Not a DataView");
1559 size_t offset = (size_t)js_getnum(args[0]);
1560 uint16_t value = (uint16_t)js_to_uint32(js_getnum(args[1]));
1561 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1562
1563 if (offset + 2 > dv->byte_length) {
1564 return js_mkerr(js, "Offset out of bounds");
1565 }
1566
1567 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1568
1569 if (little_endian) {
1570 ptr[0] = (uint8_t)(value & 0xFF);
1571 ptr[1] = (uint8_t)((value >> 8) & 0xFF);
1572 } else {
1573 ptr[0] = (uint8_t)((value >> 8) & 0xFF);
1574 ptr[1] = (uint8_t)(value & 0xFF);
1575 }
1576
1577 return js_mkundef();
1578}
1579
1580// DataView.prototype.getInt32(byteOffset, littleEndian)
1581static ant_value_t js_dataview_getInt32(ant_t *js, ant_value_t *args, int nargs) {
1582 if (nargs < 1) return js_mkerr(js, "getInt32 requires byteOffset");
1583
1584 ant_value_t this_val = js_getthis(js);
1585 DataViewData *dv = buffer_get_dataview_data(this_val);
1586 if (!dv) return js_mkerr(js, "Not a DataView");
1587 size_t offset = (size_t)js_getnum(args[0]);
1588 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1589
1590 if (offset + 4 > dv->byte_length) {
1591 return js_mkerr(js, "Offset out of bounds");
1592 }
1593
1594 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1595 int32_t value;
1596
1597 if (little_endian) {
1598 value = (int32_t)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24));
1599 } else {
1600 value = (int32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]);
1601 }
1602
1603 return js_mknum((double)value);
1604}
1605
1606// DataView.prototype.getFloat32(byteOffset, littleEndian)
1607static ant_value_t js_dataview_getFloat32(ant_t *js, ant_value_t *args, int nargs) {
1608 if (nargs < 1) return js_mkerr(js, "getFloat32 requires byteOffset");
1609
1610 ant_value_t this_val = js_getthis(js);
1611 DataViewData *dv = buffer_get_dataview_data(this_val);
1612 if (!dv) return js_mkerr(js, "Not a DataView");
1613 size_t offset = (size_t)js_getnum(args[0]);
1614 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1615
1616 if (offset + 4 > dv->byte_length) {
1617 return js_mkerr(js, "Offset out of bounds");
1618 }
1619
1620 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1621 uint32_t bits;
1622
1623 if (little_endian) {
1624 bits = ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
1625 } else {
1626 bits = (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
1627 }
1628
1629 float value;
1630 memcpy(&value, &bits, 4);
1631 return js_mknum((double)value);
1632}
1633
1634// DataView.prototype.setInt16(byteOffset, value, littleEndian)
1635static ant_value_t js_dataview_setInt16(ant_t *js, ant_value_t *args, int nargs) {
1636 if (nargs < 2) return js_mkerr(js, "setInt16 requires byteOffset and value");
1637
1638 ant_value_t this_val = js_getthis(js);
1639 DataViewData *dv = buffer_get_dataview_data(this_val);
1640 if (!dv) return js_mkerr(js, "Not a DataView");
1641 size_t offset = (size_t)js_getnum(args[0]);
1642 int16_t value = (int16_t)js_to_int32(js_getnum(args[1]));
1643 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1644
1645 if (offset + 2 > dv->byte_length) {
1646 return js_mkerr(js, "Offset out of bounds");
1647 }
1648
1649 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1650
1651 if (little_endian) {
1652 ptr[0] = (uint8_t)(value & 0xFF);
1653 ptr[1] = (uint8_t)((value >> 8) & 0xFF);
1654 } else {
1655 ptr[0] = (uint8_t)((value >> 8) & 0xFF);
1656 ptr[1] = (uint8_t)(value & 0xFF);
1657 }
1658
1659 return js_mkundef();
1660}
1661
1662// DataView.prototype.setInt32(byteOffset, value, littleEndian)
1663static ant_value_t js_dataview_setInt32(ant_t *js, ant_value_t *args, int nargs) {
1664 if (nargs < 2) return js_mkerr(js, "setInt32 requires byteOffset and value");
1665
1666 ant_value_t this_val = js_getthis(js);
1667 DataViewData *dv = buffer_get_dataview_data(this_val);
1668 if (!dv) return js_mkerr(js, "Not a DataView");
1669 size_t offset = (size_t)js_getnum(args[0]);
1670 int32_t value = js_to_int32(js_getnum(args[1]));
1671 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1672
1673 if (offset + 4 > dv->byte_length) {
1674 return js_mkerr(js, "Offset out of bounds");
1675 }
1676
1677 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1678
1679 if (little_endian) {
1680 ptr[0] = (uint8_t)(value & 0xFF);
1681 ptr[1] = (uint8_t)((value >> 8) & 0xFF);
1682 ptr[2] = (uint8_t)((value >> 16) & 0xFF);
1683 ptr[3] = (uint8_t)((value >> 24) & 0xFF);
1684 } else {
1685 ptr[0] = (uint8_t)((value >> 24) & 0xFF);
1686 ptr[1] = (uint8_t)((value >> 16) & 0xFF);
1687 ptr[2] = (uint8_t)((value >> 8) & 0xFF);
1688 ptr[3] = (uint8_t)(value & 0xFF);
1689 }
1690
1691 return js_mkundef();
1692}
1693
1694// DataView.prototype.getUint32(byteOffset, littleEndian)
1695static ant_value_t js_dataview_getUint32(ant_t *js, ant_value_t *args, int nargs) {
1696 if (nargs < 1) return js_mkerr(js, "getUint32 requires byteOffset");
1697
1698 ant_value_t this_val = js_getthis(js);
1699 DataViewData *dv = buffer_get_dataview_data(this_val);
1700 if (!dv) return js_mkerr(js, "Not a DataView");
1701 size_t offset = (size_t)js_getnum(args[0]);
1702 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1703
1704 if (offset + 4 > dv->byte_length) {
1705 return js_mkerr(js, "Offset out of bounds");
1706 }
1707
1708 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1709 uint32_t value;
1710
1711 if (little_endian) value = (uint32_t)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24));
1712 else value = (uint32_t)((ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3]);
1713
1714 return js_mknum((double)value);
1715}
1716
1717// DataView.prototype.setUint32(byteOffset, value, littleEndian)
1718static ant_value_t js_dataview_setUint32(ant_t *js, ant_value_t *args, int nargs) {
1719 if (nargs < 2) return js_mkerr(js, "setUint32 requires byteOffset and value");
1720
1721 ant_value_t this_val = js_getthis(js);
1722 DataViewData *dv = buffer_get_dataview_data(this_val);
1723 if (!dv) return js_mkerr(js, "Not a DataView");
1724 size_t offset = (size_t)js_getnum(args[0]);
1725
1726 uint32_t value = js_to_uint32(js_getnum(args[1]));
1727 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1728
1729 if (offset + 4 > dv->byte_length) return js_mkerr(js, "Offset out of bounds");
1730 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1731
1732 if (little_endian) {
1733 ptr[0] = (uint8_t)(value & 0xFF);
1734 ptr[1] = (uint8_t)((value >> 8) & 0xFF);
1735 ptr[2] = (uint8_t)((value >> 16) & 0xFF);
1736 ptr[3] = (uint8_t)((value >> 24) & 0xFF);
1737 } else {
1738 ptr[0] = (uint8_t)((value >> 24) & 0xFF);
1739 ptr[1] = (uint8_t)((value >> 16) & 0xFF);
1740 ptr[2] = (uint8_t)((value >> 8) & 0xFF);
1741 ptr[3] = (uint8_t)(value & 0xFF);
1742 }
1743
1744 return js_mkundef();
1745}
1746
1747// DataView.prototype.setFloat32(byteOffset, value, littleEndian)
1748static ant_value_t js_dataview_setFloat32(ant_t *js, ant_value_t *args, int nargs) {
1749 if (nargs < 2) return js_mkerr(js, "setFloat32 requires byteOffset and value");
1750
1751 ant_value_t this_val = js_getthis(js);
1752 DataViewData *dv = buffer_get_dataview_data(this_val);
1753 if (!dv) return js_mkerr(js, "Not a DataView");
1754 size_t offset = (size_t)js_getnum(args[0]);
1755 float value = (float)js_getnum(args[1]);
1756 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1757
1758 if (offset + 4 > dv->byte_length) {
1759 return js_mkerr(js, "Offset out of bounds");
1760 }
1761
1762 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1763 uint32_t bits;
1764 memcpy(&bits, &value, 4);
1765
1766 if (little_endian) {
1767 ptr[0] = (uint8_t)(bits & 0xFF);
1768 ptr[1] = (uint8_t)((bits >> 8) & 0xFF);
1769 ptr[2] = (uint8_t)((bits >> 16) & 0xFF);
1770 ptr[3] = (uint8_t)((bits >> 24) & 0xFF);
1771 } else {
1772 ptr[0] = (uint8_t)((bits >> 24) & 0xFF);
1773 ptr[1] = (uint8_t)((bits >> 16) & 0xFF);
1774 ptr[2] = (uint8_t)((bits >> 8) & 0xFF);
1775 ptr[3] = (uint8_t)(bits & 0xFF);
1776 }
1777
1778 return js_mkundef();
1779}
1780
1781// DataView.prototype.getFloat64(byteOffset, littleEndian)
1782static ant_value_t js_dataview_getFloat64(ant_t *js, ant_value_t *args, int nargs) {
1783 if (nargs < 1) return js_mkerr(js, "getFloat64 requires byteOffset");
1784
1785 ant_value_t this_val = js_getthis(js);
1786 DataViewData *dv = buffer_get_dataview_data(this_val);
1787 if (!dv) return js_mkerr(js, "Not a DataView");
1788 size_t offset = (size_t)js_getnum(args[0]);
1789 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1790
1791 if (offset + 8 > dv->byte_length) {
1792 return js_mkerr(js, "Offset out of bounds");
1793 }
1794
1795 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1796 uint64_t bits;
1797
1798 if (little_endian) {
1799 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) |
1800 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56);
1801 } else {
1802 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) |
1803 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7];
1804 }
1805
1806 double value;
1807 memcpy(&value, &bits, 8);
1808 return js_mknum(value);
1809}
1810
1811// DataView.prototype.setFloat64(byteOffset, value, littleEndian)
1812static ant_value_t js_dataview_setFloat64(ant_t *js, ant_value_t *args, int nargs) {
1813 if (nargs < 2) return js_mkerr(js, "setFloat64 requires byteOffset and value");
1814
1815 ant_value_t this_val = js_getthis(js);
1816 DataViewData *dv = buffer_get_dataview_data(this_val);
1817 if (!dv) return js_mkerr(js, "Not a DataView");
1818 size_t offset = (size_t)js_getnum(args[0]);
1819 double value = js_getnum(args[1]);
1820 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1821
1822 if (offset + 8 > dv->byte_length) {
1823 return js_mkerr(js, "Offset out of bounds");
1824 }
1825
1826 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1827 uint64_t bits;
1828 memcpy(&bits, &value, 8);
1829
1830 if (little_endian) {
1831 ptr[0] = (uint8_t)(bits & 0xFF);
1832 ptr[1] = (uint8_t)((bits >> 8) & 0xFF);
1833 ptr[2] = (uint8_t)((bits >> 16) & 0xFF);
1834 ptr[3] = (uint8_t)((bits >> 24) & 0xFF);
1835 ptr[4] = (uint8_t)((bits >> 32) & 0xFF);
1836 ptr[5] = (uint8_t)((bits >> 40) & 0xFF);
1837 ptr[6] = (uint8_t)((bits >> 48) & 0xFF);
1838 ptr[7] = (uint8_t)((bits >> 56) & 0xFF);
1839 } else {
1840 ptr[0] = (uint8_t)((bits >> 56) & 0xFF);
1841 ptr[1] = (uint8_t)((bits >> 48) & 0xFF);
1842 ptr[2] = (uint8_t)((bits >> 40) & 0xFF);
1843 ptr[3] = (uint8_t)((bits >> 32) & 0xFF);
1844 ptr[4] = (uint8_t)((bits >> 24) & 0xFF);
1845 ptr[5] = (uint8_t)((bits >> 16) & 0xFF);
1846 ptr[6] = (uint8_t)((bits >> 8) & 0xFF);
1847 ptr[7] = (uint8_t)(bits & 0xFF);
1848 }
1849
1850 return js_mkundef();
1851}
1852
1853static ant_value_t js_dataview_getBigInt64(ant_t *js, ant_value_t *args, int nargs) {
1854 if (nargs < 1) return js_mkerr(js, "getBigInt64 requires byteOffset");
1855
1856 ant_value_t this_val = js_getthis(js);
1857 DataViewData *dv = buffer_get_dataview_data(this_val);
1858 if (!dv) return js_mkerr(js, "Not a DataView");
1859 size_t offset = (size_t)js_getnum(args[0]);
1860 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1861
1862 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds");
1863
1864 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1865 uint64_t bits;
1866 if (little_endian) {
1867 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) |
1868 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56);
1869 } else {
1870 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) |
1871 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7];
1872 }
1873
1874 return bigint_from_int64(js, (int64_t)bits);
1875}
1876
1877static ant_value_t js_dataview_setBigInt64(ant_t *js, ant_value_t *args, int nargs) {
1878 if (nargs < 2) return js_mkerr(js, "setBigInt64 requires byteOffset and value");
1879
1880 ant_value_t this_val = js_getthis(js);
1881 DataViewData *dv = buffer_get_dataview_data(this_val);
1882 if (!dv) return js_mkerr(js, "Not a DataView");
1883 size_t offset = (size_t)js_getnum(args[0]);
1884 ant_value_t bigint = buffer_require_bigint_value(js, args[1]);
1885 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1886 int64_t wrapped = 0;
1887
1888 if (is_err(bigint)) return bigint;
1889 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds");
1890 if (!bigint_to_int64_wrapping(js, bigint, &wrapped)) {
1891 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt");
1892 }
1893
1894 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1895 uint64_t bits = (uint64_t)wrapped;
1896 if (little_endian) {
1897 ptr[0] = (uint8_t)(bits & 0xFF);
1898 ptr[1] = (uint8_t)((bits >> 8) & 0xFF);
1899 ptr[2] = (uint8_t)((bits >> 16) & 0xFF);
1900 ptr[3] = (uint8_t)((bits >> 24) & 0xFF);
1901 ptr[4] = (uint8_t)((bits >> 32) & 0xFF);
1902 ptr[5] = (uint8_t)((bits >> 40) & 0xFF);
1903 ptr[6] = (uint8_t)((bits >> 48) & 0xFF);
1904 ptr[7] = (uint8_t)((bits >> 56) & 0xFF);
1905 } else {
1906 ptr[0] = (uint8_t)((bits >> 56) & 0xFF);
1907 ptr[1] = (uint8_t)((bits >> 48) & 0xFF);
1908 ptr[2] = (uint8_t)((bits >> 40) & 0xFF);
1909 ptr[3] = (uint8_t)((bits >> 32) & 0xFF);
1910 ptr[4] = (uint8_t)((bits >> 24) & 0xFF);
1911 ptr[5] = (uint8_t)((bits >> 16) & 0xFF);
1912 ptr[6] = (uint8_t)((bits >> 8) & 0xFF);
1913 ptr[7] = (uint8_t)(bits & 0xFF);
1914 }
1915
1916 return js_mkundef();
1917}
1918
1919static ant_value_t js_dataview_getBigUint64(ant_t *js, ant_value_t *args, int nargs) {
1920 if (nargs < 1) return js_mkerr(js, "getBigUint64 requires byteOffset");
1921
1922 ant_value_t this_val = js_getthis(js);
1923 DataViewData *dv = buffer_get_dataview_data(this_val);
1924 if (!dv) return js_mkerr(js, "Not a DataView");
1925 size_t offset = (size_t)js_getnum(args[0]);
1926 bool little_endian = (nargs > 1 && js_truthy(js, args[1]));
1927
1928 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds");
1929
1930 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1931 uint64_t bits;
1932 if (little_endian) {
1933 bits = (uint64_t)ptr[0] | ((uint64_t)ptr[1] << 8) | ((uint64_t)ptr[2] << 16) | ((uint64_t)ptr[3] << 24) |
1934 ((uint64_t)ptr[4] << 32) | ((uint64_t)ptr[5] << 40) | ((uint64_t)ptr[6] << 48) | ((uint64_t)ptr[7] << 56);
1935 } else {
1936 bits = ((uint64_t)ptr[0] << 56) | ((uint64_t)ptr[1] << 48) | ((uint64_t)ptr[2] << 40) | ((uint64_t)ptr[3] << 32) |
1937 ((uint64_t)ptr[4] << 24) | ((uint64_t)ptr[5] << 16) | ((uint64_t)ptr[6] << 8) | (uint64_t)ptr[7];
1938 }
1939
1940 return bigint_from_uint64(js, bits);
1941}
1942
1943static ant_value_t js_dataview_setBigUint64(ant_t *js, ant_value_t *args, int nargs) {
1944 if (nargs < 2) return js_mkerr(js, "setBigUint64 requires byteOffset and value");
1945
1946 ant_value_t this_val = js_getthis(js);
1947 DataViewData *dv = buffer_get_dataview_data(this_val);
1948 if (!dv) return js_mkerr(js, "Not a DataView");
1949 size_t offset = (size_t)js_getnum(args[0]);
1950 ant_value_t bigint = buffer_require_bigint_value(js, args[1]);
1951 bool little_endian = (nargs > 2 && js_truthy(js, args[2]));
1952 uint64_t wrapped = 0;
1953
1954 if (is_err(bigint)) return bigint;
1955 if (offset + 8 > dv->byte_length) return js_mkerr(js, "Offset out of bounds");
1956 if (!bigint_to_uint64_wrapping(js, bigint, &wrapped)) {
1957 return js_mkerr_typed(js, JS_ERR_TYPE, "Cannot convert to BigInt");
1958 }
1959
1960 uint8_t *ptr = dv->buffer->data + dv->byte_offset + offset;
1961 if (little_endian) {
1962 ptr[0] = (uint8_t)(wrapped & 0xFF);
1963 ptr[1] = (uint8_t)((wrapped >> 8) & 0xFF);
1964 ptr[2] = (uint8_t)((wrapped >> 16) & 0xFF);
1965 ptr[3] = (uint8_t)((wrapped >> 24) & 0xFF);
1966 ptr[4] = (uint8_t)((wrapped >> 32) & 0xFF);
1967 ptr[5] = (uint8_t)((wrapped >> 40) & 0xFF);
1968 ptr[6] = (uint8_t)((wrapped >> 48) & 0xFF);
1969 ptr[7] = (uint8_t)((wrapped >> 56) & 0xFF);
1970 } else {
1971 ptr[0] = (uint8_t)((wrapped >> 56) & 0xFF);
1972 ptr[1] = (uint8_t)((wrapped >> 48) & 0xFF);
1973 ptr[2] = (uint8_t)((wrapped >> 40) & 0xFF);
1974 ptr[3] = (uint8_t)((wrapped >> 32) & 0xFF);
1975 ptr[4] = (uint8_t)((wrapped >> 24) & 0xFF);
1976 ptr[5] = (uint8_t)((wrapped >> 16) & 0xFF);
1977 ptr[6] = (uint8_t)((wrapped >> 8) & 0xFF);
1978 ptr[7] = (uint8_t)(wrapped & 0xFF);
1979 }
1980
1981 return js_mkundef();
1982}
1983
1984static uint8_t *hex_decode(const char *data, size_t len, size_t *out_len) {
1985 if (len % 2 != 0) return NULL;
1986
1987 size_t decoded_len = len / 2;
1988 size_t alloc_len = decoded_len;
1989
1990 if (alloc_len == 0) alloc_len = 1;
1991 uint8_t *decoded = malloc(alloc_len);
1992 if (!decoded) return NULL;
1993
1994 for (size_t i = 0; i < decoded_len; i++) {
1995 unsigned char hi_ch = (unsigned char)data[i * 2];
1996 unsigned char lo_ch = (unsigned char)data[i * 2 + 1];
1997 int hi; int lo;
1998
1999 if (hi_ch >= '0' && hi_ch <= '9') { hi = hi_ch - '0'; goto have_hi; }
2000 if (hi_ch >= 'a' && hi_ch <= 'f') { hi = hi_ch - 'a' + 10; goto have_hi; }
2001 if (hi_ch >= 'A' && hi_ch <= 'F') { hi = hi_ch - 'A' + 10; goto have_hi; }
2002 goto fail;
2003
2004 have_hi:
2005 if (lo_ch >= '0' && lo_ch <= '9') { lo = lo_ch - '0'; goto have_lo; }
2006 if (lo_ch >= 'a' && lo_ch <= 'f') { lo = lo_ch - 'a' + 10; goto have_lo; }
2007 if (lo_ch >= 'A' && lo_ch <= 'F') { lo = lo_ch - 'A' + 10; goto have_lo; }
2008 goto fail;
2009
2010 have_lo:
2011 decoded[i] = (uint8_t)((hi << 4) | lo);
2012 }
2013
2014 *out_len = decoded_len;
2015 return decoded;
2016
2017fail:
2018 free(decoded);
2019 return NULL;
2020}
2021
2022static ant_value_t uint8array_from_bytes(ant_t *js, const uint8_t *bytes, size_t len) {
2023 ArrayBufferData *buffer = create_array_buffer_data(len);
2024 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2025 if (len > 0) memcpy(buffer->data, bytes, len);
2026 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Uint8Array");
2027}
2028
2029static ant_value_t js_uint8array_fromHex(ant_t *js, ant_value_t *args, int nargs) {
2030 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0);
2031 if (is_err(source)) return source;
2032
2033 size_t len = 0;
2034 char *str = js_getstr(js, source, &len);
2035
2036 size_t decoded_len = 0;
2037 uint8_t *decoded = hex_decode(str, len, &decoded_len);
2038 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string");
2039
2040 ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len);
2041 free(decoded);
2042
2043 return result;
2044}
2045
2046static ant_value_t js_uint8array_fromBase64(ant_t *js, ant_value_t *args, int nargs) {
2047 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0);
2048 if (is_err(source)) return source;
2049
2050 size_t len = 0;
2051 char *str = js_getstr(js, source, &len);
2052
2053 size_t decoded_len = 0;
2054 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len);
2055 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string");
2056
2057 ant_value_t result = uint8array_from_bytes(js, decoded, decoded_len);
2058 free(decoded);
2059
2060 return result;
2061}
2062
2063static ant_value_t js_uint8array_toHex(ant_t *js, ant_value_t *args, int nargs) {
2064 ant_value_t this_val = js_getthis(js);
2065 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2066
2067 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8)
2068 return js_mkerr(js, "Uint8Array.prototype.toHex called on incompatible receiver");
2069 if (!ta_data->buffer || ta_data->buffer->is_detached)
2070 return js_mkerr(js, "Cannot read from detached Uint8Array");
2071
2072 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
2073 size_t len = ta_data->byte_length;
2074 char *hex = malloc(len * 2 + 1);
2075
2076 if (!hex) return js_mkerr(js, "Failed to allocate hex string");
2077 for (size_t i = 0; i < len; i++) snprintf(hex + i * 2, 3, "%02x", data[i]);
2078
2079 ant_value_t result = js_mkstr(js, hex, len * 2);
2080 free(hex);
2081
2082 return result;
2083}
2084
2085static ant_value_t js_uint8array_toBase64(ant_t *js, ant_value_t *args, int nargs) {
2086 ant_value_t this_val = js_getthis(js);
2087 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2088
2089 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8)
2090 return js_mkerr(js, "Uint8Array.prototype.toBase64 called on incompatible receiver");
2091 if (!ta_data->buffer || ta_data->buffer->is_detached)
2092 return js_mkerr(js, "Cannot read from detached Uint8Array");
2093
2094 size_t out_len = 0;
2095 char *encoded = ant_base64_encode(
2096 ta_data->buffer->data + ta_data->byte_offset,
2097 ta_data->byte_length, &out_len
2098 );
2099
2100 if (!encoded) return js_mkerr(js, "Failed to encode base64");
2101 ant_value_t result = js_mkstr(js, encoded, out_len);
2102 free(encoded);
2103
2104 return result;
2105}
2106
2107static ant_value_t uint8array_set_result(ant_t *js, size_t read, size_t written) {
2108 ant_value_t result = js_mkobj(js);
2109 js_set(js, result, "read", js_mknum((double)read));
2110 js_set(js, result, "written", js_mknum((double)written));
2111 return result;
2112}
2113
2114static ant_value_t uint8array_set_bytes(ant_t *js, const uint8_t *bytes, size_t byte_len, size_t read) {
2115 ant_value_t this_val = js_getthis(js);
2116 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2117
2118 if (!ta_data || ta_data->type != TYPED_ARRAY_UINT8)
2119 return js_mkerr(js, "Uint8Array setFrom called on incompatible receiver");
2120 if (!ta_data->buffer || ta_data->buffer->is_detached)
2121 return js_mkerr(js, "Cannot write to detached Uint8Array");
2122 if (byte_len > ta_data->byte_length)
2123 return js_mkerr_typed(js, JS_ERR_RANGE, "Decoded data does not fit in Uint8Array");
2124
2125 if (byte_len > 0) memcpy(ta_data->buffer->data + ta_data->byte_offset, bytes, byte_len);
2126 return uint8array_set_result(js, read, byte_len);
2127}
2128
2129static ant_value_t js_uint8array_setFromHex(ant_t *js, ant_value_t *args, int nargs) {
2130 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0);
2131 if (is_err(source)) return source;
2132
2133 size_t len = 0;
2134 char *str = js_getstr(js, source, &len);
2135 size_t decoded_len = 0;
2136
2137 uint8_t *decoded = hex_decode(str, len, &decoded_len);
2138 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid hex string");
2139
2140 ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len);
2141 free(decoded);
2142
2143 return result;
2144}
2145
2146static ant_value_t js_uint8array_setFromBase64(ant_t *js, ant_value_t *args, int nargs) {
2147 ant_value_t source = nargs > 0 ? js_tostring_val(js, args[0]) : js_mkstr(js, "", 0);
2148 if (is_err(source)) return source;
2149
2150 size_t len = 0;
2151 char *str = js_getstr(js, source, &len);
2152 size_t decoded_len = 0;
2153
2154 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len);
2155 if (!decoded) return js_mkerr_typed(js, JS_ERR_SYNTAX, "Invalid base64 string");
2156
2157 ant_value_t result = uint8array_set_bytes(js, decoded, decoded_len, len);
2158 free(decoded);
2159
2160 return result;
2161}
2162
2163typedef enum {
2164 ENC_UTF8,
2165 ENC_HEX,
2166 ENC_BASE64,
2167 ENC_ASCII,
2168 ENC_LATIN1,
2169 ENC_UCS2,
2170 ENC_UNKNOWN
2171} BufferEncoding;
2172
2173static BufferEncoding parse_encoding(const char *enc, size_t len) {
2174 if (len == 3 && strncasecmp(enc, "hex", 3) == 0) return ENC_HEX;
2175 if (len == 5 && strncasecmp(enc, "ascii", 5) == 0) return ENC_ASCII;
2176 if (len == 6 && strncasecmp(enc, "base64", 6) == 0) return ENC_BASE64;
2177 if ((len == 4 && strncasecmp(enc, "utf8", 4) == 0) || (len == 5 && strncasecmp(enc, "utf-8", 5) == 0)) return ENC_UTF8;
2178 if ((len == 6 && strncasecmp(enc, "latin1", 6) == 0) || (len == 6 && strncasecmp(enc, "binary", 6) == 0)) return ENC_LATIN1;
2179
2180 if (
2181 (len == 4 && strncasecmp(enc, "ucs2", 4) == 0) ||
2182 (len == 5 && strncasecmp(enc, "ucs-2", 5) == 0) ||
2183 (len == 7 && strncasecmp(enc, "utf16le", 7) == 0) ||
2184 (len == 8 && strncasecmp(enc, "utf-16le", 8) == 0)
2185 ) return ENC_UCS2;
2186
2187 return ENC_UNKNOWN;
2188}
2189
2190// Buffer.from(array/string/buffer, encoding)
2191static ant_value_t js_buffer_from(ant_t *js, ant_value_t *args, int nargs) {
2192 if (nargs < 1) return js_mkerr(js, "Buffer.from requires at least one argument");
2193
2194 if (vtype(args[0]) == T_STR) {
2195 size_t len;
2196 char *str = js_getstr(js, args[0], &len);
2197
2198 BufferEncoding encoding = ENC_UTF8;
2199 if (nargs >= 2 && vtype(args[1]) == T_STR) {
2200 size_t enc_len;
2201 char *enc_str = js_getstr(js, args[1], &enc_len);
2202 encoding = parse_encoding(enc_str, enc_len);
2203 if (encoding == ENC_UNKNOWN) encoding = ENC_UTF8;
2204 }
2205
2206 if (encoding == ENC_BASE64) {
2207 size_t decoded_len;
2208 uint8_t *decoded = ant_base64_decode(str, len, &decoded_len);
2209 if (!decoded) return js_mkerr(js, "Failed to decode base64");
2210
2211 ArrayBufferData *buffer = create_array_buffer_data(decoded_len);
2212 if (!buffer) { free(decoded); return js_mkerr(js, "Failed to allocate buffer"); }
2213
2214 memcpy(buffer->data, decoded, decoded_len);
2215 free(decoded);
2216 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer");
2217 } else if (encoding == ENC_HEX) {
2218 size_t decoded_len;
2219 uint8_t *decoded = hex_decode(str, len, &decoded_len);
2220 if (!decoded) return js_mkerr(js, "Failed to decode hex");
2221
2222 ArrayBufferData *buffer = create_array_buffer_data(decoded_len);
2223 if (!buffer) { free(decoded); return js_mkerr(js, "Failed to allocate buffer"); }
2224
2225 memcpy(buffer->data, decoded, decoded_len);
2226 free(decoded);
2227 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer");
2228 } else if (encoding == ENC_UCS2) {
2229 size_t decoded_len = len * 2;
2230 ArrayBufferData *buffer = create_array_buffer_data(decoded_len);
2231 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2232
2233 for (size_t i = 0; i < len; i++) {
2234 buffer->data[i * 2] = (uint8_t)str[i];
2235 buffer->data[i * 2 + 1] = 0;
2236 }
2237 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, decoded_len, "Buffer");
2238 } else {
2239 ArrayBufferData *buffer = create_array_buffer_data(len);
2240 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2241
2242 memcpy(buffer->data, str, len);
2243 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Buffer");
2244 }
2245 }
2246
2247 ant_value_t length_val = js_get(js, args[0], "length");
2248 if (vtype(length_val) == T_NUM) {
2249 size_t len = (size_t)js_getnum(length_val);
2250 ArrayBufferData *buffer = create_array_buffer_data(len);
2251 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2252
2253 for (size_t i = 0; i < len; i++) {
2254 char idx_str[32];
2255 snprintf(idx_str, sizeof(idx_str), "%zu", i);
2256 ant_value_t elem = js_get(js, args[0], idx_str);
2257 if (vtype(elem) == T_NUM) {
2258 buffer->data[i] = (uint8_t)js_getnum(elem);
2259 }
2260 }
2261
2262 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, len, "Buffer");
2263 }
2264
2265 return js_mkerr(js, "Invalid argument to Buffer.from");
2266}
2267
2268// Buffer.alloc(size)
2269static ant_value_t js_buffer_alloc(ant_t *js, ant_value_t *args, int nargs) {
2270 if (nargs < 1) {
2271 return js_mkerr(js, "Buffer.alloc requires a size argument");
2272 }
2273
2274 size_t size = (size_t)js_getnum(args[0]);
2275 ArrayBufferData *buffer = create_array_buffer_data(size);
2276 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2277
2278 memset(buffer->data, 0, size);
2279 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, size, "Buffer");
2280}
2281
2282// Buffer.allocUnsafe(size)
2283static ant_value_t js_buffer_allocUnsafe(ant_t *js, ant_value_t *args, int nargs) {
2284 if (nargs < 1) {
2285 return js_mkerr(js, "Buffer.allocUnsafe requires a size argument");
2286 }
2287
2288 size_t size = (size_t)js_getnum(args[0]);
2289 ArrayBufferData *buffer = create_array_buffer_data(size);
2290 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2291 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, size, "Buffer");
2292}
2293
2294static ant_value_t typedarray_join_with(ant_t *js, ant_value_t this_val, const char *sep, size_t sep_len) {
2295 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2296 if (!ta_data) return js_mkstr(js, "", 0);
2297 if (!ta_data->buffer || ta_data->buffer->is_detached || ta_data->length == 0)
2298 return js_mkstr(js, "", 0);
2299
2300 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
2301 size_t len = ta_data->length;
2302
2303 size_t cap = len * 12;
2304 char *buf = malloc(cap);
2305 if (!buf) return js_mkerr(js, "Out of memory");
2306 size_t pos = 0;
2307
2308 for (size_t i = 0; i < len; i++) {
2309 if (i > 0) {
2310 if (pos + sep_len + 32 > cap) {
2311 cap *= 2;
2312 char *tmp = realloc(buf, cap);
2313 if (!tmp) { free(buf); return js_mkerr(js, "Out of memory"); }
2314 buf = tmp;
2315 }
2316 memcpy(buf + pos, sep, sep_len);
2317 pos += sep_len;
2318 }
2319
2320 if (pos + 32 > cap) {
2321 cap *= 2;
2322 char *tmp = realloc(buf, cap);
2323 if (!tmp) { free(buf); return js_mkerr(js, "Out of memory"); }
2324 buf = tmp;
2325 }
2326
2327 int written = 0;
2328 switch (ta_data->type) {
2329 case TYPED_ARRAY_INT8: written = snprintf(buf + pos, cap - pos, "%d", ((int8_t*)data)[i]); break;
2330 case TYPED_ARRAY_UINT8:
2331 case TYPED_ARRAY_UINT8_CLAMPED: written = snprintf(buf + pos, cap - pos, "%u", data[i]); break;
2332 case TYPED_ARRAY_INT16: written = snprintf(buf + pos, cap - pos, "%d", ((int16_t*)data)[i]); break;
2333 case TYPED_ARRAY_UINT16: written = snprintf(buf + pos, cap - pos, "%u", ((uint16_t*)data)[i]); break;
2334 case TYPED_ARRAY_INT32: written = snprintf(buf + pos, cap - pos, "%d", ((int32_t*)data)[i]); break;
2335 case TYPED_ARRAY_UINT32: written = snprintf(buf + pos, cap - pos, "%u", ((uint32_t*)data)[i]); break;
2336 case TYPED_ARRAY_FLOAT16: written = snprintf(buf + pos, cap - pos, "%g", half_to_double(((uint16_t*)data)[i])); break;
2337 case TYPED_ARRAY_FLOAT32: written = snprintf(buf + pos, cap - pos, "%g", (double)((float*)data)[i]); break;
2338 case TYPED_ARRAY_FLOAT64: written = snprintf(buf + pos, cap - pos, "%g", ((double*)data)[i]); break;
2339 case TYPED_ARRAY_BIGINT64: written = snprintf(buf + pos, cap - pos, "%lld", ((long long*)data)[i]); break;
2340 case TYPED_ARRAY_BIGUINT64: written = snprintf(buf + pos, cap - pos, "%llu", ((unsigned long long*)data)[i]); break;
2341 default: break;
2342 }
2343 if (written > 0) pos += (size_t)written;
2344 }
2345
2346 ant_value_t ret = js_mkstr(js, buf, pos);
2347 free(buf);
2348 return ret;
2349}
2350
2351// TypedArray.prototype.toString()
2352static ant_value_t js_typedarray_toString(ant_t *js, ant_value_t *args, int nargs) {
2353 return typedarray_join_with(js, js_getthis(js), ",", 1);
2354}
2355
2356// TypedArray.prototype.join(separator)
2357static ant_value_t js_typedarray_join(ant_t *js, ant_value_t *args, int nargs) {
2358 const char *sep = ",";
2359 size_t sep_len = 1;
2360 if (nargs > 0 && vtype(args[0]) == T_STR)
2361 sep = js_getstr(js, args[0], &sep_len);
2362 return typedarray_join_with(js, js_getthis(js), sep, sep_len);
2363}
2364
2365static ant_value_t js_typedarray_indexOf(ant_t *js, ant_value_t *args, int nargs) {
2366 ant_value_t this_val = js_getthis(js);
2367 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2368 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached) return js_mknum(-1);
2369
2370 size_t len = ta_data->length;
2371 if (len == 0 || nargs < 1) return js_mknum(-1);
2372
2373 int64_t from_index = 0;
2374 if (nargs > 1 && vtype(args[1]) != T_UNDEF) {
2375 from_index = (int64_t)js_to_number(js, args[1]);
2376 if (from_index < 0) {
2377 from_index += (int64_t)len;
2378 if (from_index < 0) from_index = 0;
2379 }}
2380
2381 if ((size_t)from_index >= len) return js_mknum(-1);
2382 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
2383 double needle_num = js_to_number(js, args[0]);
2384
2385 for (size_t i = (size_t)from_index; i < len; i++) {
2386 bool match = false;
2387 switch (ta_data->type) {
2388 case TYPED_ARRAY_INT8: match = ((int8_t *)data)[i] == (int8_t)needle_num; break;
2389 case TYPED_ARRAY_UINT8:
2390 case TYPED_ARRAY_UINT8_CLAMPED: match = data[i] == (uint8_t)needle_num; break;
2391 case TYPED_ARRAY_INT16: match = ((int16_t *)data)[i] == (int16_t)needle_num; break;
2392 case TYPED_ARRAY_UINT16: match = ((uint16_t *)data)[i] == (uint16_t)needle_num; break;
2393 case TYPED_ARRAY_INT32: match = ((int32_t *)data)[i] == (int32_t)needle_num; break;
2394 case TYPED_ARRAY_UINT32: match = ((uint32_t *)data)[i] == (uint32_t)needle_num; break;
2395 case TYPED_ARRAY_FLOAT16: match = half_to_double(((uint16_t *)data)[i]) == needle_num; break;
2396 case TYPED_ARRAY_FLOAT32: match = ((float *)data)[i] == (float)needle_num; break;
2397 case TYPED_ARRAY_FLOAT64: match = ((double *)data)[i] == needle_num; break;
2398 case TYPED_ARRAY_BIGINT64: match = ((int64_t *)data)[i] == (int64_t)needle_num; break;
2399 case TYPED_ARRAY_BIGUINT64: match = ((uint64_t *)data)[i] == (uint64_t)needle_num; break;
2400 default: break;
2401 }
2402 if (match) return js_mknum((double)i);
2403 }
2404
2405 return js_mknum(-1);
2406}
2407
2408static ant_value_t js_typedarray_includes(ant_t *js, ant_value_t *args, int nargs) {
2409 ant_value_t this_val = js_getthis(js);
2410 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2411
2412 if (!ta_data || !ta_data->buffer || ta_data->buffer->is_detached) {
2413 return js_mkerr(js, "Invalid TypedArray");
2414 }
2415
2416 size_t len = ta_data->length;
2417 ant_value_t search = (nargs > 0) ? args[0] : js_mkundef();
2418
2419 if (len == 0) return js_false;
2420 int64_t from_index = 0;
2421
2422 if (nargs > 1 && vtype(args[1]) != T_UNDEF) {
2423 double from_index_num = js_to_number(js, args[1]);
2424 if (!isnan(from_index_num)) from_index = (int64_t)from_index_num;
2425 if (from_index < 0) {
2426 from_index += (int64_t)len;
2427 if (from_index < 0) from_index = 0;
2428 }}
2429
2430 if ((size_t)from_index >= len) return js_false;
2431
2432 if (ta_data->type == TYPED_ARRAY_BIGINT64) {
2433 int64_t needle = 0;
2434 if (vtype(search) == T_BIGINT) {
2435 if (!bigint_to_int64_wrapping(js, search, &needle)) return js_false;
2436 } else needle = (int64_t)js_to_number(js, search);
2437
2438 int64_t *data = (int64_t *)(ta_data->buffer->data + ta_data->byte_offset);
2439 for (size_t i = (size_t)from_index; i < len; i++) {
2440 if (data[i] == needle) return js_true;
2441 }
2442
2443 return js_false;
2444 }
2445
2446 if (ta_data->type == TYPED_ARRAY_BIGUINT64) {
2447 uint64_t needle = 0;
2448 if (vtype(search) == T_BIGINT) {
2449 if (!bigint_to_uint64_wrapping(js, search, &needle)) return js_false;
2450 } else needle = (uint64_t)js_to_number(js, search);
2451
2452 uint64_t *data = (uint64_t *)(ta_data->buffer->data + ta_data->byte_offset);
2453 for (size_t i = (size_t)from_index; i < len; i++) {
2454 if (data[i] == needle) return js_true;
2455 }
2456
2457 return js_false;
2458 }
2459
2460 double needle = js_to_number(js, search);
2461 for (size_t i = (size_t)from_index; i < len; i++) {
2462 double value = 0;
2463 if (!typedarray_read_number(ta_data, i, &value)) return js_false;
2464 if (isnan(value) && isnan(needle)) return js_true;
2465 if (value == needle) return js_true;
2466 }
2467
2468 return js_false;
2469}
2470
2471// Buffer.prototype.toString(encoding)
2472static ant_value_t js_buffer_slice(ant_t *js, ant_value_t *args, int nargs) {
2473 return js_typedarray_subarray(js, args, nargs);
2474}
2475
2476// Buffer.prototype.toString(encoding)
2477static ant_value_t js_buffer_toString(ant_t *js, ant_value_t *args, int nargs) {
2478 ant_value_t this_val = js_getthis(js);
2479 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2480 if (!ta_data) return js_mkerr(js, "Invalid Buffer");
2481
2482 BufferEncoding encoding = ENC_UTF8;
2483 if (nargs > 0 && vtype(args[0]) == T_STR) {
2484 size_t enc_len;
2485 char *enc_str = js_getstr(js, args[0], &enc_len);
2486 encoding = parse_encoding(enc_str, enc_len);
2487 if (encoding == ENC_UNKNOWN) encoding = ENC_UTF8;
2488 }
2489
2490 if (!ta_data->buffer || ta_data->buffer->is_detached) {
2491 return js_mkerr(js, "Cannot read from detached buffer");
2492 }
2493
2494 uint8_t *data = ta_data->buffer->data + ta_data->byte_offset;
2495 size_t len = ta_data->byte_length;
2496
2497 if (encoding == ENC_BASE64) {
2498 size_t out_len;
2499 char *encoded = ant_base64_encode(data, len, &out_len);
2500 if (!encoded) return js_mkerr(js, "Failed to encode base64");
2501
2502 ant_value_t result = js_mkstr(js, encoded, out_len);
2503 free(encoded);
2504 return result;
2505 } else if (encoding == ENC_HEX) {
2506 char *hex = malloc(len * 2 + 1);
2507 if (!hex) return js_mkerr(js, "Failed to allocate hex string");
2508
2509 for (size_t i = 0; i < len; i++) {
2510 snprintf(hex + i * 2, 3, "%02x", data[i]);
2511 }
2512
2513 ant_value_t result = js_mkstr(js, hex, len * 2);
2514 free(hex);
2515 return result;
2516 } else if (encoding == ENC_UCS2) {
2517 size_t char_count = len / 2;
2518 char *str = malloc(char_count + 1);
2519 if (!str) return js_mkerr(js, "Failed to allocate string");
2520
2521 for (size_t i = 0; i < char_count; i++) str[i] = (char)data[i * 2];
2522 str[char_count] = '\0';
2523
2524 ant_value_t result = js_mkstr(js, str, char_count);
2525 free(str);
2526 return result;
2527 } else {
2528 size_t out_cap = len * 3 + 1;
2529 char *out = malloc(out_cap);
2530 if (!out) return js_mkerr(js, "Failed to allocate string");
2531
2532 utf8_dec_t dec = { .bom_seen = true, .ignore_bom = true };
2533 utf8proc_ssize_t out_len = utf8_whatwg_decode(&dec, data, len, out, false, false);
2534
2535 if (out_len < 0) {
2536 free(out);
2537 return js_mkerr(js, "Failed to decode buffer as UTF-8");
2538 }
2539
2540 ant_value_t result = js_mkstr(js, out, (size_t)out_len);
2541 free(out);
2542
2543 return result;
2544 }
2545}
2546
2547// Buffer.prototype.toBase64()
2548static ant_value_t js_buffer_toBase64(ant_t *js, ant_value_t *args, int nargs) {
2549 (void)args; (void)nargs;
2550 ant_value_t encoding_arg = js_mkstr(js, "base64", 6);
2551 ant_value_t new_args[1] = {encoding_arg};
2552 return js_buffer_toString(js, new_args, 1);
2553}
2554
2555// Buffer.prototype.write(string, offset, length, encoding)
2556static ant_value_t js_buffer_write(ant_t *js, ant_value_t *args, int nargs) {
2557 if (nargs < 1) return js_mkerr(js, "write requires a string");
2558
2559 ant_value_t this_val = js_getthis(js);
2560 TypedArrayData *ta_data = buffer_get_typedarray_data(this_val);
2561 if (!ta_data) return js_mkerr(js, "Invalid Buffer");
2562
2563 size_t str_len;
2564 char *str = js_getstr(js, args[0], &str_len);
2565 size_t offset = 0;
2566 size_t length = ta_data->byte_length;
2567
2568 if (nargs > 1 && vtype(args[1]) == T_NUM) {
2569 offset = (size_t)js_getnum(args[1]);
2570 }
2571
2572 if (nargs > 2 && vtype(args[2]) == T_NUM) {
2573 length = (size_t)js_getnum(args[2]);
2574 }
2575
2576 if (offset >= ta_data->byte_length) {
2577 return js_mknum(0);
2578 }
2579
2580 size_t available = ta_data->byte_length - offset;
2581 size_t to_write = (str_len < length) ? str_len : length;
2582 to_write = (to_write < available) ? to_write : available;
2583
2584 memcpy(ta_data->buffer->data + ta_data->byte_offset + offset, str, to_write);
2585 return js_mknum((double)to_write);
2586}
2587
2588static ant_value_t js_buffer_copy(ant_t *js, ant_value_t *args, int nargs) {
2589 if (nargs < 1) return js_mkerr(js, "copy requires a target buffer");
2590
2591 TypedArrayData *src = buffer_get_typedarray_data(js_getthis(js));
2592 TypedArrayData *dst = buffer_get_typedarray_data(args[0]);
2593 if (!src || !dst) return js_mkerr(js, "copy requires Buffer arguments");
2594
2595 size_t target_start = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0;
2596 size_t source_start = (nargs > 2 && vtype(args[2]) == T_NUM) ? (size_t)js_getnum(args[2]) : 0;
2597 size_t source_end = (nargs > 3 && vtype(args[3]) == T_NUM) ? (size_t)js_getnum(args[3]) : src->byte_length;
2598
2599 if (target_start > dst->byte_length) target_start = dst->byte_length;
2600 if (source_start > src->byte_length) source_start = src->byte_length;
2601 if (source_end > src->byte_length) source_end = src->byte_length;
2602 if (source_end < source_start) source_end = source_start;
2603
2604 size_t src_len = source_end - source_start;
2605 size_t dst_len = dst->byte_length - target_start;
2606 size_t copy_len = src_len < dst_len ? src_len : dst_len;
2607 if (copy_len == 0) return js_mknum(0);
2608
2609 uint8_t *src_ptr = src->buffer->data + src->byte_offset + source_start;
2610 uint8_t *dst_ptr = dst->buffer->data + dst->byte_offset + target_start;
2611 memmove(dst_ptr, src_ptr, copy_len);
2612
2613 return js_mknum((double)copy_len);
2614}
2615
2616static ant_value_t js_buffer_writeInt16BE(ant_t *js, ant_value_t *args, int nargs) {
2617 if (nargs < 1) return js_mkerr(js, "writeInt16BE requires a value");
2618
2619 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2620 if (!ta) return js_mkerr(js, "Invalid Buffer");
2621
2622 int16_t value = (int16_t)js_to_int32(js_getnum(args[0]));
2623 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0;
2624 if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2625
2626 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2627 ptr[0] = (uint8_t)((value >> 8) & 0xff);
2628 ptr[1] = (uint8_t)(value & 0xff);
2629
2630 return js_mknum((double)(offset + 2));
2631}
2632
2633static ant_value_t js_buffer_writeInt32BE(ant_t *js, ant_value_t *args, int nargs) {
2634 if (nargs < 1) return js_mkerr(js, "writeInt32BE requires a value");
2635
2636 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2637 if (!ta) return js_mkerr(js, "Invalid Buffer");
2638
2639 int32_t value = js_to_int32(js_getnum(args[0]));
2640 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0;
2641 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2642
2643 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2644 ptr[0] = (uint8_t)((value >> 24) & 0xff);
2645 ptr[1] = (uint8_t)((value >> 16) & 0xff);
2646 ptr[2] = (uint8_t)((value >> 8) & 0xff);
2647 ptr[3] = (uint8_t)(value & 0xff);
2648
2649 return js_mknum((double)(offset + 4));
2650}
2651
2652static ant_value_t js_buffer_writeUInt32BE(ant_t *js, ant_value_t *args, int nargs) {
2653 if (nargs < 1) return js_mkerr(js, "writeUInt32BE requires a value");
2654
2655 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2656 if (!ta) return js_mkerr(js, "Invalid Buffer");
2657
2658 uint32_t value = js_to_uint32(js_getnum(args[0]));
2659 size_t offset = (nargs > 1 && vtype(args[1]) == T_NUM) ? (size_t)js_getnum(args[1]) : 0;
2660 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2661
2662 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2663 ptr[0] = (uint8_t)((value >> 24) & 0xff);
2664 ptr[1] = (uint8_t)((value >> 16) & 0xff);
2665 ptr[2] = (uint8_t)((value >> 8) & 0xff);
2666 ptr[3] = (uint8_t)(value & 0xff);
2667
2668 return js_mknum((double)(offset + 4));
2669}
2670
2671static ant_value_t js_buffer_readInt16BE(ant_t *js, ant_value_t *args, int nargs) {
2672 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2673 if (!ta) return js_mkerr(js, "Invalid Buffer");
2674
2675 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0;
2676 if (offset + 2 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2677
2678 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2679 int16_t value = (int16_t)((ptr[0] << 8) | ptr[1]);
2680
2681 return js_mknum((double)value);
2682}
2683
2684static ant_value_t js_buffer_readInt32BE(ant_t *js, ant_value_t *args, int nargs) {
2685 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2686 if (!ta) return js_mkerr(js, "Invalid Buffer");
2687
2688 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0;
2689 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2690
2691 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2692 int32_t value = (int32_t)(((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) |
2693 ((uint32_t)ptr[2] << 8) | (uint32_t)ptr[3]);
2694
2695 return js_mknum((double)value);
2696}
2697
2698static ant_value_t js_buffer_readUInt32BE(ant_t *js, ant_value_t *args, int nargs) {
2699 TypedArrayData *ta = buffer_get_typedarray_data(js_getthis(js));
2700 if (!ta) return js_mkerr(js, "Invalid Buffer");
2701
2702 size_t offset = (nargs > 0 && vtype(args[0]) == T_NUM) ? (size_t)js_getnum(args[0]) : 0;
2703 if (offset + 4 > ta->byte_length) return js_mkerr(js, "Offset out of bounds");
2704
2705 uint8_t *ptr = ta->buffer->data + ta->byte_offset + offset;
2706 uint32_t value = ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) |
2707 ((uint32_t)ptr[2] << 8) | (uint32_t)ptr[3];
2708
2709 return js_mknum((double)value);
2710}
2711
2712// Buffer.isBuffer(obj)
2713static ant_value_t js_buffer_isBuffer(ant_t *js, ant_value_t *args, int nargs) {
2714 if (nargs < 1) return js_false;
2715 if (!is_special_object(args[0])) return js_false;
2716
2717 ant_value_t proto = js_get_proto(js, args[0]);
2718 ant_value_t buffer_proto = js_get_ctor_proto(js, "Buffer", 6);
2719
2720 return js_bool(proto == buffer_proto);
2721}
2722
2723// Buffer.isEncoding(encoding)
2724static ant_value_t js_buffer_isEncoding(ant_t *js, ant_value_t *args, int nargs) {
2725 if (nargs < 1 || vtype(args[0]) != T_STR) return js_false;
2726
2727 size_t len;
2728 char *enc = js_getstr(js, args[0], &len);
2729
2730 if ((len == 4 && strncasecmp(enc, "utf8", 4) == 0) ||
2731 (len == 5 && strncasecmp(enc, "utf-8", 5) == 0) ||
2732 (len == 3 && strncasecmp(enc, "hex", 3) == 0) ||
2733 (len == 6 && strncasecmp(enc, "base64", 6) == 0) ||
2734 (len == 5 && strncasecmp(enc, "ascii", 5) == 0) ||
2735 (len == 6 && strncasecmp(enc, "latin1", 6) == 0) ||
2736 (len == 6 && strncasecmp(enc, "binary", 6) == 0) ||
2737 (len == 4 && strncasecmp(enc, "ucs2", 4) == 0) ||
2738 (len == 5 && strncasecmp(enc, "ucs-2", 5) == 0) ||
2739 (len == 7 && strncasecmp(enc, "utf16le", 7) == 0) ||
2740 (len == 8 && strncasecmp(enc, "utf-16le", 8) == 0)) {
2741 return js_true;
2742 }
2743
2744 return js_false;
2745}
2746
2747// Buffer.byteLength(string, encoding)
2748static ant_value_t js_buffer_byteLength(ant_t *js, ant_value_t *args, int nargs) {
2749 if (nargs < 1) return js_mknum(0);
2750
2751 ant_value_t arg = args[0];
2752
2753 if (is_special_object(arg)) {
2754 ant_value_t bytelen = js_get(js, arg, "byteLength");
2755 if (vtype(bytelen) == T_NUM) return bytelen;
2756
2757 ant_value_t len = js_get(js, arg, "length");
2758 if (vtype(len) == T_NUM) return len;
2759 }
2760
2761 if (vtype(arg) == T_STR) {
2762 size_t len;
2763 js_getstr(js, arg, &len);
2764 return js_mknum((double)len);
2765 }
2766
2767 return js_mknum(0);
2768}
2769
2770// Buffer.concat(list, totalLength)
2771static ant_value_t js_buffer_concat(ant_t *js, ant_value_t *args, int nargs) {
2772 if (nargs < 1 || !is_special_object(args[0])) {
2773 return js_mkerr(js, "First argument must be an array");
2774 }
2775
2776 ant_value_t list = args[0];
2777 ant_value_t len_val = js_get(js, list, "length");
2778 if (vtype(len_val) != T_NUM) {
2779 return js_mkerr(js, "First argument must be an array");
2780 }
2781
2782 size_t list_len = (size_t)js_getnum(len_val);
2783 size_t total_length = 0;
2784
2785 if (nargs > 1 && vtype(args[1]) == T_NUM) {
2786 total_length = (size_t)js_getnum(args[1]);
2787 } else {
2788 for (size_t i = 0; i < list_len; i++) {
2789 char idx[16];
2790 snprintf(idx, sizeof(idx), "%zu", i);
2791 ant_value_t buf = js_get(js, list, idx);
2792 ant_value_t buf_len = js_get(js, buf, "length");
2793 if (vtype(buf_len) == T_NUM) total_length += (size_t)js_getnum(buf_len);
2794 }
2795 }
2796
2797 ArrayBufferData *buffer = create_array_buffer_data(total_length);
2798 if (!buffer) return js_mkerr(js, "Failed to allocate buffer");
2799
2800 size_t offset = 0;
2801 for (size_t i = 0; i < list_len && offset < total_length; i++) {
2802 char idx[16];
2803 snprintf(idx, sizeof(idx), "%zu", i);
2804 ant_value_t buf = js_get(js, list, idx);
2805
2806 TypedArrayData *ta = buffer_get_typedarray_data(buf);
2807 if (!ta || !ta->buffer) continue;
2808
2809 size_t copy_len = ta->byte_length;
2810 if (offset + copy_len > total_length) {
2811 copy_len = total_length - offset;
2812 }
2813
2814 memcpy(buffer->data + offset, ta->buffer->data + ta->byte_offset, copy_len);
2815 offset += copy_len;
2816 }
2817
2818 return create_typed_array(js, TYPED_ARRAY_UINT8, buffer, 0, total_length, "Buffer");
2819}
2820
2821// Buffer.compare(buf1, buf2)
2822static ant_value_t js_buffer_compare(ant_t *js, ant_value_t *args, int nargs) {
2823 if (nargs < 2) return js_mkerr(js, "Buffer.compare requires two arguments");
2824
2825 TypedArrayData *ta1 = buffer_get_typedarray_data(args[0]);
2826 TypedArrayData *ta2 = buffer_get_typedarray_data(args[1]);
2827
2828 if (!ta1 || !ta2) {
2829 return js_mkerr(js, "Arguments must be Buffers");
2830 }
2831
2832 if (!ta1 || !ta1->buffer || !ta2 || !ta2->buffer) {
2833 return js_mkerr(js, "Invalid buffer");
2834 }
2835
2836 size_t len = ta1->byte_length < ta2->byte_length ? ta1->byte_length : ta2->byte_length;
2837 int cmp = memcmp(ta1->buffer->data + ta1->byte_offset, ta2->buffer->data + ta2->byte_offset, len);
2838
2839 if (cmp == 0) {
2840 if (ta1->byte_length < ta2->byte_length) cmp = -1;
2841 else if (ta1->byte_length > ta2->byte_length) cmp = 1;
2842 } else cmp = cmp < 0 ? -1 : 1;
2843
2844 return js_mknum((double)cmp);
2845}
2846
2847static ant_value_t js_sharedarraybuffer_constructor(ant_t *js, ant_value_t *args, int nargs) {
2848 if (vtype(js->new_target) == T_UNDEF) {
2849 return js_mkerr_typed(js, JS_ERR_TYPE, "SharedArrayBuffer constructor requires 'new'");
2850 }
2851 size_t length = 0;
2852 if (nargs > 0 && vtype(args[0]) == T_NUM) {
2853 length = (size_t)js_getnum(args[0]);
2854 }
2855
2856 ArrayBufferData *data = create_shared_array_buffer_data(length);
2857 if (!data) {
2858 return js_mkerr(js, "Failed to allocate SharedArrayBuffer");
2859 }
2860
2861 ant_value_t obj = js_mkobj(js);
2862 ant_value_t proto = js_get_ctor_proto(js, "SharedArrayBuffer", 17);
2863
2864 if (is_special_object(proto)) js_set_proto_init(obj, proto);
2865 js_set_native(obj, data, BUFFER_ARRAYBUFFER_NATIVE_TAG);
2866 js_set(js, obj, "byteLength", js_mknum((double)length));
2867 js_set_finalizer(obj, arraybuffer_finalize);
2868
2869 return obj;
2870}
2871
2872static ant_value_t buffer_make_constants(ant_t *js) {
2873 ant_value_t constants = js_newobj(js);
2874 js_set(js, constants, "MAX_LENGTH", js_mknum(BUFFER_COMPAT_MAX_LENGTH));
2875 js_set(js, constants, "MAX_STRING_LENGTH", js_mknum(BUFFER_COMPAT_MAX_STRING_LENGTH));
2876 return constants;
2877}
2878
2879ant_value_t buffer_library(ant_t *js) {
2880 ant_value_t glob = js_glob(js);
2881 ant_value_t lib = js_newobj(js);
2882
2883 js_set(js, lib, "Buffer", js_get(js, glob, "Buffer"));
2884 js_set(js, lib, "Blob", js_get(js, glob, "Blob"));
2885 js_set(js, lib, "File", js_get(js, glob, "File"));
2886 js_set(js, lib, "atob", js_get(js, glob, "atob"));
2887 js_set(js, lib, "btoa", js_get(js, glob, "btoa"));
2888 js_set(js, lib, "constants", buffer_make_constants(js));
2889 js_set(js, lib, "kMaxLength", js_mknum(BUFFER_COMPAT_MAX_LENGTH));
2890 js_set(js, lib, "kStringMaxLength", js_mknum(BUFFER_COMPAT_MAX_STRING_LENGTH));
2891 js_set(js, lib, "INSPECT_MAX_BYTES", js_mknum(BUFFER_COMPAT_INSPECT_MAX_BYTES));
2892
2893 return lib;
2894}
2895
2896void init_buffer_module() {
2897 ant_t *js = rt->js;
2898
2899 ant_value_t glob = js->global;
2900 ant_value_t object_proto = js->sym.object_proto;
2901
2902 ant_value_t arraybuffer_ctor_obj = js_mkobj(js);
2903 ant_value_t arraybuffer_proto = js_mkobj(js);
2904 js_set_proto_init(arraybuffer_proto, object_proto);
2905
2906 js_set(js, arraybuffer_proto, "slice", js_mkfun(js_arraybuffer_slice));
2907 js_set(js, arraybuffer_proto, "transfer", js_mkfun(js_arraybuffer_transfer));
2908 js_set(js, arraybuffer_proto, "transferToFixedLength", js_mkfun(js_arraybuffer_transferToFixedLength));
2909 js_set_getter_desc(js, arraybuffer_proto, "detached", 8, js_mkfun(js_arraybuffer_detached_getter), JS_DESC_E);
2910 js_set_getter_desc(js, arraybuffer_proto, "byteLength", 10, js_mkfun(js_arraybuffer_byteLength_getter), JS_DESC_C);
2911 js_set_sym(js, arraybuffer_proto, get_toStringTag_sym(), js_mkstr(js, "ArrayBuffer", 11));
2912
2913 js_set_slot(arraybuffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_arraybuffer_constructor));
2914 js_mkprop_fast(js, arraybuffer_ctor_obj, "prototype", 9, arraybuffer_proto);
2915 js_mkprop_fast(js, arraybuffer_ctor_obj, "name", 4, ANT_STRING("ArrayBuffer"));
2916 js_set_descriptor(js, arraybuffer_ctor_obj, "name", 4, 0);
2917 js_set(js, arraybuffer_ctor_obj, "isView", js_mkfun(js_arraybuffer_isView));
2918 js_define_species_getter(js, arraybuffer_ctor_obj);
2919 ant_value_t arraybuffer_ctor = js_obj_to_func(arraybuffer_ctor_obj);
2920 js_set(js, arraybuffer_proto, "constructor", arraybuffer_ctor);
2921 js_set_descriptor(js, arraybuffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
2922 js_set(js, glob, "ArrayBuffer", arraybuffer_ctor);
2923
2924 ant_value_t typedarray_proto = js_mkobj(js);
2925 js_set_proto_init(typedarray_proto, object_proto);
2926
2927 js_set(js, typedarray_proto, "at", js_mkfun(js_typedarray_at));
2928 js_set(js, typedarray_proto, "set", js_mkfun(js_typedarray_set));
2929 js_set(js, typedarray_proto, "copyWithin", js_mkfun(js_typedarray_copyWithin));
2930 js_set(js, typedarray_proto, "slice", js_mkfun(js_typedarray_slice));
2931 js_set(js, typedarray_proto, "subarray", js_mkfun(js_typedarray_subarray));
2932 js_set(js, typedarray_proto, "fill", js_mkfun(js_typedarray_fill));
2933 js_set(js, typedarray_proto, "toReversed", js_mkfun(js_typedarray_toReversed));
2934 js_set(js, typedarray_proto, "toSorted", js_mkfun(js_typedarray_toSorted));
2935 js_set(js, typedarray_proto, "with", js_mkfun(js_typedarray_with));
2936 js_set(js, typedarray_proto, "toString", js_mkfun(js_typedarray_toString));
2937 js_set(js, typedarray_proto, "join", js_mkfun(js_typedarray_join));
2938 js_set(js, typedarray_proto, "indexOf", js_mkfun(js_typedarray_indexOf));
2939 js_set(js, typedarray_proto, "includes", js_mkfun(js_typedarray_includes));
2940 js_set(js, typedarray_proto, "every", js_mkfun(js_typedarray_every));
2941 js_set_sym(js, typedarray_proto, get_toStringTag_sym(), js_mkstr(js, "TypedArray", 10));
2942
2943 g_typedarray_iter_proto = js_mkobj(js);
2944 js_set_proto_init(g_typedarray_iter_proto, js->sym.iterator_proto);
2945 js_set(js, g_typedarray_iter_proto, "next", js_mkfun(ta_iter_next));
2946 js_iter_register_advance(g_typedarray_iter_proto, advance_typedarray);
2947
2948 js_set(js, typedarray_proto, "values", js_mkfun(ta_values));
2949 js_set(js, typedarray_proto, "keys", js_mkfun(ta_keys));
2950 js_set(js, typedarray_proto, "entries", js_mkfun(ta_entries));
2951 js_set_sym(js, typedarray_proto, get_iterator_sym(), js_get(js, typedarray_proto, "values"));
2952
2953 // TODO: find a better way of doing this, macro is code smell
2954 #define SETUP_TYPEDARRAY(name) \
2955 do { \
2956 ant_value_t name##_ctor_obj = js_mkobj(js); \
2957 ant_value_t name##_proto = js_mkobj(js); \
2958 js_set_proto_init(name##_proto, typedarray_proto); \
2959 js_set_sym(js, name##_proto, get_toStringTag_sym(), js_mkstr(js, #name, sizeof(#name) - 1)); \
2960 js_set_slot(name##_ctor_obj, SLOT_CFUNC, js_mkfun(js_##name##_constructor)); \
2961 js_setprop(js, name##_ctor_obj, js_mkstr(js, "prototype", 9), name##_proto); \
2962 js_mkprop_fast(js, name##_ctor_obj, "name", 4, ANT_STRING(#name)); \
2963 js_set_descriptor(js, name##_ctor_obj, "name", 4, 0); \
2964 js_define_species_getter(js, name##_ctor_obj); \
2965 js_set(js, name##_ctor_obj, "from", js_mkfun(js_##name##_from)); \
2966 ant_value_t name##_ctor = js_obj_to_func(name##_ctor_obj); \
2967 js_setprop(js, name##_proto, ANT_STRING("constructor"), name##_ctor); \
2968 js_set_descriptor(js, name##_proto, "constructor", 11, JS_DESC_W | JS_DESC_C); \
2969 js_set(js, glob, #name, name##_ctor); \
2970 } while(0)
2971
2972 SETUP_TYPEDARRAY(Int8Array);
2973 SETUP_TYPEDARRAY(Uint8Array);
2974 SETUP_TYPEDARRAY(Uint8ClampedArray);
2975 SETUP_TYPEDARRAY(Int16Array);
2976 SETUP_TYPEDARRAY(Uint16Array);
2977 SETUP_TYPEDARRAY(Int32Array);
2978 SETUP_TYPEDARRAY(Uint32Array);
2979 SETUP_TYPEDARRAY(Float16Array);
2980 SETUP_TYPEDARRAY(Float32Array);
2981 SETUP_TYPEDARRAY(Float64Array);
2982 SETUP_TYPEDARRAY(BigInt64Array);
2983 SETUP_TYPEDARRAY(BigUint64Array);
2984
2985 ant_value_t uint8array_codec_ctor = js_get(js, glob, "Uint8Array");
2986 ant_value_t uint8array_codec_proto = js_get(js, uint8array_codec_ctor, "prototype");
2987 js_set(js, uint8array_codec_ctor, "fromHex", js_mkfun(js_uint8array_fromHex));
2988 js_set(js, uint8array_codec_ctor, "fromBase64", js_mkfun(js_uint8array_fromBase64));
2989 js_set(js, uint8array_codec_proto, "toHex", js_mkfun(js_uint8array_toHex));
2990 js_set(js, uint8array_codec_proto, "toBase64", js_mkfun(js_uint8array_toBase64));
2991 js_set(js, uint8array_codec_proto, "setFromHex", js_mkfun(js_uint8array_setFromHex));
2992 js_set(js, uint8array_codec_proto, "setFromBase64", js_mkfun(js_uint8array_setFromBase64));
2993
2994 ant_value_t dataview_ctor_obj = js_mkobj(js);
2995 ant_value_t dataview_proto = js_mkobj(js);
2996 js_set_proto_init(dataview_proto, object_proto);
2997
2998 js_set(js, dataview_proto, "getInt8", js_mkfun(js_dataview_getInt8));
2999 js_set(js, dataview_proto, "setInt8", js_mkfun(js_dataview_setInt8));
3000 js_set(js, dataview_proto, "getUint8", js_mkfun(js_dataview_getUint8));
3001 js_set(js, dataview_proto, "setUint8", js_mkfun(js_dataview_setUint8));
3002 js_set(js, dataview_proto, "getInt16", js_mkfun(js_dataview_getInt16));
3003 js_set(js, dataview_proto, "setInt16", js_mkfun(js_dataview_setInt16));
3004 js_set(js, dataview_proto, "getUint16", js_mkfun(js_dataview_getUint16));
3005 js_set(js, dataview_proto, "setUint16", js_mkfun(js_dataview_setUint16));
3006 js_set(js, dataview_proto, "getInt32", js_mkfun(js_dataview_getInt32));
3007 js_set(js, dataview_proto, "setInt32", js_mkfun(js_dataview_setInt32));
3008 js_set(js, dataview_proto, "getUint32", js_mkfun(js_dataview_getUint32));
3009 js_set(js, dataview_proto, "setUint32", js_mkfun(js_dataview_setUint32));
3010 js_set(js, dataview_proto, "getFloat32", js_mkfun(js_dataview_getFloat32));
3011 js_set(js, dataview_proto, "setFloat32", js_mkfun(js_dataview_setFloat32));
3012 js_set(js, dataview_proto, "getFloat64", js_mkfun(js_dataview_getFloat64));
3013 js_set(js, dataview_proto, "setFloat64", js_mkfun(js_dataview_setFloat64));
3014 js_set(js, dataview_proto, "getBigInt64", js_mkfun(js_dataview_getBigInt64));
3015 js_set(js, dataview_proto, "setBigInt64", js_mkfun(js_dataview_setBigInt64));
3016 js_set(js, dataview_proto, "getBigUint64", js_mkfun(js_dataview_getBigUint64));
3017 js_set(js, dataview_proto, "setBigUint64", js_mkfun(js_dataview_setBigUint64));
3018 js_set_sym(js, dataview_proto, get_toStringTag_sym(), js_mkstr(js, "DataView", 8));
3019
3020 js_set_slot(dataview_ctor_obj, SLOT_CFUNC, js_mkfun(js_dataview_constructor));
3021 js_mkprop_fast(js, dataview_ctor_obj, "prototype", 9, dataview_proto);
3022 js_mkprop_fast(js, dataview_ctor_obj, "name", 4, ANT_STRING("DataView"));
3023 js_set_descriptor(js, dataview_ctor_obj, "name", 4, 0);
3024
3025 ant_value_t dataview_ctor = js_obj_to_func(dataview_ctor_obj);
3026 js_set(js, dataview_proto, "constructor", dataview_ctor);
3027 js_set_descriptor(js, dataview_proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
3028 js_set(js, glob, "DataView", dataview_ctor);
3029
3030 ant_value_t sharedarraybuffer_ctor_obj = js_mkobj(js);
3031 ant_value_t sharedarraybuffer_proto = js_mkobj(js);
3032 js_set_proto_init(sharedarraybuffer_proto, object_proto);
3033
3034 js_set(js, sharedarraybuffer_proto, "slice", js_mkfun(js_arraybuffer_slice));
3035 js_set_getter_desc(js, sharedarraybuffer_proto, "byteLength", 10, js_mkfun(js_arraybuffer_byteLength_getter), JS_DESC_C);
3036 js_set_sym(js, sharedarraybuffer_proto, get_toStringTag_sym(), js_mkstr(js, "SharedArrayBuffer", 17));
3037
3038 js_set_slot(sharedarraybuffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_sharedarraybuffer_constructor));
3039 js_mkprop_fast(js, sharedarraybuffer_ctor_obj, "prototype", 9, sharedarraybuffer_proto);
3040 js_mkprop_fast(js, sharedarraybuffer_ctor_obj, "name", 4, ANT_STRING("SharedArrayBuffer"));
3041 js_set_descriptor(js, sharedarraybuffer_ctor_obj, "name", 4, 0);
3042 js_define_species_getter(js, sharedarraybuffer_ctor_obj);
3043
3044 ant_value_t sharedarraybuffer_ctor = js_obj_to_func(sharedarraybuffer_ctor_obj);
3045 js_set(js, sharedarraybuffer_proto, "constructor", sharedarraybuffer_ctor);
3046 js_set_descriptor(js, sharedarraybuffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
3047 js_set(js, glob, "SharedArrayBuffer", sharedarraybuffer_ctor);
3048
3049 ant_value_t buffer_ctor_obj = js_mkobj(js);
3050 ant_value_t buffer_proto = js_mkobj(js);
3051
3052 ant_value_t uint8array_ctor = js_get(js, glob, "Uint8Array");
3053 ant_value_t uint8array_proto = js_get(js, uint8array_ctor, "prototype");
3054
3055 if (is_special_object(uint8array_proto)) js_set_proto_init(buffer_proto, uint8array_proto);
3056 else js_set_proto_init(buffer_proto, typedarray_proto);
3057
3058 js_set(js, buffer_proto, "slice", js_mkfun(js_buffer_slice));
3059 js_set(js, buffer_proto, "toString", js_mkfun(js_buffer_toString));
3060 js_set(js, buffer_proto, "toBase64", js_mkfun(js_buffer_toBase64));
3061 js_set(js, buffer_proto, "write", js_mkfun(js_buffer_write));
3062 js_set(js, buffer_proto, "copy", js_mkfun(js_buffer_copy));
3063 js_set(js, buffer_proto, "writeInt16BE", js_mkfun(js_buffer_writeInt16BE));
3064 js_set(js, buffer_proto, "writeInt32BE", js_mkfun(js_buffer_writeInt32BE));
3065 js_set(js, buffer_proto, "writeUInt32BE", js_mkfun(js_buffer_writeUInt32BE));
3066 js_set(js, buffer_proto, "readInt16BE", js_mkfun(js_buffer_readInt16BE));
3067 js_set(js, buffer_proto, "readInt32BE", js_mkfun(js_buffer_readInt32BE));
3068 js_set(js, buffer_proto, "readUInt32BE", js_mkfun(js_buffer_readUInt32BE));
3069
3070 js_set_sym(js, buffer_proto, get_toStringTag_sym(), js_mkstr(js, "Buffer", 6));
3071 js_set(js, buffer_proto, "values", js_get(js, typedarray_proto, "values"));
3072 js_set_sym(js, buffer_proto, get_iterator_sym(), js_get(js, buffer_proto, "values"));
3073
3074 js_set(js, buffer_ctor_obj, "from", js_mkfun(js_buffer_from));
3075 js_set(js, buffer_ctor_obj, "alloc", js_mkfun(js_buffer_alloc));
3076 js_set(js, buffer_ctor_obj, "allocUnsafe", js_mkfun(js_buffer_allocUnsafe));
3077 js_set(js, buffer_ctor_obj, "isBuffer", js_mkfun(js_buffer_isBuffer));
3078 js_set(js, buffer_ctor_obj, "isEncoding", js_mkfun(js_buffer_isEncoding));
3079 js_set(js, buffer_ctor_obj, "byteLength", js_mkfun(js_buffer_byteLength));
3080 js_set(js, buffer_ctor_obj, "concat", js_mkfun(js_buffer_concat));
3081 js_set(js, buffer_ctor_obj, "compare", js_mkfun(js_buffer_compare));
3082
3083 js_set_slot(buffer_ctor_obj, SLOT_CFUNC, js_mkfun(js_buffer_from));
3084 js_mkprop_fast(js, buffer_ctor_obj, "prototype", 9, buffer_proto);
3085 js_mkprop_fast(js, buffer_ctor_obj, "name", 4, ANT_STRING("Buffer"));
3086 js_set_descriptor(js, buffer_ctor_obj, "name", 4, 0);
3087
3088 ant_value_t buffer_ctor = js_obj_to_func(buffer_ctor_obj);
3089 js_set(js, buffer_proto, "constructor", buffer_ctor);
3090 js_set_descriptor(js, buffer_proto, "constructor", 11, JS_DESC_W | JS_DESC_C);
3091 js_set(js, glob, "Buffer", buffer_ctor);
3092}
3093
3094void cleanup_buffer_module(void) {
3095 if (buffer_registry) {
3096 for (size_t i = 0; i < buffer_registry_count; i++) {
3097 if (buffer_registry[i]) free(buffer_registry[i]);
3098 }
3099 free(buffer_registry);
3100 buffer_registry = NULL;
3101 buffer_registry_count = 0;
3102 buffer_registry_cap = 0;
3103 }
3104
3105 ta_metadata_bytes = 0;
3106}
3107
3108size_t buffer_get_external_memory(void) {
3109 size_t total = ta_metadata_bytes;
3110
3111 for (size_t i = 0; i < buffer_registry_count; i++) {
3112 if (buffer_registry[i])
3113 total += sizeof(ArrayBufferData) + buffer_registry[i]->capacity;
3114 }
3115 total += buffer_registry_cap * sizeof(ArrayBufferData *);
3116
3117 return total;
3118}