1use crate::host::HostFunction;
2use crate::object::object::{JSObject, ObjectType, TypedArrayKind};
3use crate::runtime::context::JSContext;
4use crate::value::JSValue;
5
6#[derive(Debug)]
7pub struct ArrayBufferData {
8 pub data: Vec<u8>,
9}
10
11fn create_array_buffer(ctx: &mut JSContext, length: usize) -> JSValue {
12 let mut obj = JSObject::new_typed(ObjectType::ArrayBuffer);
13 let data = ArrayBufferData {
14 data: vec![0; length],
15 };
16
17 obj.set(ctx.intern("byteLength"), JSValue::new_int(length as i64));
18
19 let data_ptr = Box::into_raw(Box::new(data));
20 obj.set_array_buffer_data(data_ptr as usize);
21 let ptr = Box::into_raw(Box::new(obj)) as usize;
22 JSValue::new_object(ptr)
23}
24
25fn get_array_buffer_data(obj: &JSObject) -> Option<&mut ArrayBufferData> {
26 obj.get_array_buffer_data()
27 .map(|ptr| unsafe { &mut *(ptr as *mut ArrayBufferData) })
28}
29
30fn create_typed_array(
31 ctx: &mut JSContext,
32 kind: TypedArrayKind,
33 buffer: JSValue,
34 byte_offset: usize,
35 length: Option<usize>,
36) -> Result<JSValue, String> {
37 if !buffer.is_object() {
38 return Err("TypedArray constructor requires ArrayBuffer".to_string());
39 }
40
41 let buffer_obj = buffer.as_object();
42 let buffer_data = get_array_buffer_data(&buffer_obj).ok_or("Invalid ArrayBuffer")?;
43
44 let bytes_per_element = kind.bytes_per_element();
45
46 if byte_offset % bytes_per_element != 0 {
47 return Err(format!(
48 "byteOffset must be a multiple of {}",
49 bytes_per_element
50 ));
51 }
52
53 let byte_length = buffer_data.data.len();
54 let remaining_bytes = byte_length.saturating_sub(byte_offset);
55
56 let element_length = match length {
57 Some(len) => len,
58 None => remaining_bytes / bytes_per_element,
59 };
60
61 let required_bytes = byte_offset + element_length * bytes_per_element;
62 if required_bytes > byte_length {
63 return Err("TypedArray extends beyond ArrayBuffer bounds".to_string());
64 }
65
66 let mut obj = JSObject::new_typed(ObjectType::TypedArray);
67 obj.set_typed_array_kind(kind);
68 if let Some(ta_proto_ptr) = ctx.get_typed_array_prototype() {
69 obj.prototype = Some(ta_proto_ptr);
70 }
71
72 obj.set(ctx.intern("buffer"), buffer);
73 obj.set(
74 ctx.intern("byteOffset"),
75 JSValue::new_int(byte_offset as i64),
76 );
77 obj.set(
78 ctx.intern("byteLength"),
79 JSValue::new_int((element_length * bytes_per_element) as i64),
80 );
81 obj.set(
82 ctx.intern("length"),
83 JSValue::new_int(element_length as i64),
84 );
85
86 let ptr = Box::into_raw(Box::new(obj)) as usize;
87 Ok(JSValue::new_object(ptr))
88}
89
90fn typed_array_from_args(
91 ctx: &mut JSContext,
92 kind: TypedArrayKind,
93 args: &[JSValue],
94) -> Result<JSValue, String> {
95 if args.is_empty() {
96 let buffer = create_array_buffer(ctx, 0);
97 return create_typed_array(ctx, kind, buffer, 0, Some(0));
98 }
99
100 let first_arg = &args[0];
101
102 if first_arg.is_object() {
103 let obj = first_arg.as_object();
104
105 if obj.obj_type() == ObjectType::ArrayBuffer {
106 let byte_offset = if args.len() > 1 {
107 args[1].get_int() as usize
108 } else {
109 0
110 };
111 let length = if args.len() > 2 {
112 Some(args[2].get_int() as usize)
113 } else {
114 None
115 };
116 return create_typed_array(ctx, kind, *first_arg, byte_offset, length);
117 }
118
119 if obj.obj_type() == ObjectType::TypedArray {
120 let src_len = obj
121 .get(ctx.intern("length"))
122 .map(|v| v.get_int() as usize)
123 .unwrap_or(0);
124
125 let bytes_per_element = kind.bytes_per_element();
126 let buffer = create_array_buffer(ctx, src_len * bytes_per_element);
127 let result = create_typed_array(ctx, kind, buffer, 0, Some(src_len))?;
128
129 return Ok(result);
130 }
131
132 let len = obj.get(ctx.common_atoms.length)
133 .map(|v| v.get_int() as usize)
134 .unwrap_or(0);
135
136 let bytes_per_element = kind.bytes_per_element();
137 let buffer = create_array_buffer(ctx, len * bytes_per_element);
138 let result = create_typed_array(ctx, kind, buffer, 0, Some(len))?;
139
140 if result.is_object() {
141 let mut result_obj = result.as_object_mut();
142 for i in 0..len {
143 let val = if obj.is_array() && obj.is_dense_array() {
144 let ptr = obj as *const JSObject as usize;
145 let arr = unsafe { &*(ptr as *const crate::object::array_obj::JSArrayObject) };
146 arr.get(i)
147 } else {
148 obj.get_indexed(i).or_else(|| {
149 let key = ctx.int_atom_mut(i);
150 obj.get(key)
151 })
152 };
153 if let Some(v) = val {
154 ta_set_element(ctx, &mut result_obj, i, v);
155 }
156 }
157 }
158
159 return Ok(result);
160 }
161
162 if first_arg.is_int() || first_arg.is_float() {
163 let length = first_arg.get_int() as usize;
164 let bytes_per_element = kind.bytes_per_element();
165 let buffer = create_array_buffer(ctx, length * bytes_per_element);
166 return create_typed_array(ctx, kind, buffer, 0, Some(length));
167 }
168
169 Err("Invalid TypedArray constructor argument".to_string())
170}
171
172fn array_buffer_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
173 let length = if args.is_empty() {
174 0
175 } else {
176 args[0].get_int() as usize
177 };
178 create_array_buffer(ctx, length)
179}
180
181fn data_view_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
182 if args.is_empty() || !args[0].is_object() {
183 return JSValue::undefined();
184 }
185
186 let buffer = &args[0];
187 let byte_offset = if args.len() > 1 {
188 args[1].get_int() as usize
189 } else {
190 0
191 };
192
193 let mut obj = JSObject::new_typed(ObjectType::DataView);
194 if let Some(dv_proto_ptr) = ctx.get_dataview_prototype() {
195 obj.prototype = Some(dv_proto_ptr);
196 }
197 obj.set(ctx.intern("buffer"), *buffer);
198 obj.set(
199 ctx.intern("byteOffset"),
200 JSValue::new_int(byte_offset as i64),
201 );
202
203 if let Some(buffer_obj) = if buffer.is_object() {
204 Some(buffer.as_object())
205 } else {
206 None
207 } {
208 if let Some(data) = get_array_buffer_data(&buffer_obj) {
209 let byte_length = if args.len() > 2 {
210 args[2].get_int() as usize
211 } else {
212 data.data.len().saturating_sub(byte_offset)
213 };
214 obj.set(
215 ctx.intern("byteLength"),
216 JSValue::new_int(byte_length as i64),
217 );
218 }
219 }
220
221 let ptr = Box::into_raw(Box::new(obj)) as usize;
222 JSValue::new_object(ptr)
223}
224
225fn typedarray_from(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
226 let source = args.get(1).copied().unwrap_or(JSValue::undefined());
227 let map_fn = args.get(2).copied().filter(|v| v.is_function());
228
229 if source.is_null_or_undefined() {
230 throw_type_error(ctx, "TypedArray.from requires an array-like object or iterable");
231 return JSValue::undefined();
232 }
233
234 let mut items: Vec<JSValue> = Vec::new();
235
236 if source.is_string() {
237 let chars: Vec<char> = {
238 let s = ctx.get_atom_str(source.get_atom());
239 s.chars().collect()
240 };
241 for ch in chars {
242 items.push(JSValue::new_string(ctx.intern(&ch.to_string())));
243 }
244 } else if source.is_object() {
245 let obj = source.as_object();
246
247 let sym_iter_atom = crate::builtins::symbol::get_symbol_iterator_atom(ctx);
248 if let Some(iter_val) = obj.get(sym_iter_atom) {
249 if iter_val.is_function() {
250 match crate::builtins::array::call_callback_with_this(ctx, iter_val, source, &[]) {
251 Ok(iterator) => {
252 if iterator.is_object() {
253 let iter_obj = iterator.as_object();
254 let next_fn = iter_obj.get(ctx.intern("next"));
255 if let Some(next_val) = next_fn {
256 if next_val.is_function() {
257 loop {
258 match crate::builtins::array::call_callback_with_this(ctx, next_val, iterator, &[]) {
259 Ok(result) => {
260 if result.is_object() {
261 let robj = result.as_object();
262 let done = robj
263 .get(ctx.intern("done"))
264 .map(|v| v.is_truthy())
265 .unwrap_or(false);
266 if done {
267 break;
268 }
269 let value = robj
270 .get(ctx.intern("value"))
271 .unwrap_or(JSValue::undefined());
272 if let Some(mf) = map_fn {
273 match crate::builtins::array::call_callback(ctx, mf, &[value, JSValue::new_int(items.len() as i64), source]) {
274 Ok(v) => items.push(v),
275 Err(_) => return JSValue::undefined(),
276 }
277 } else {
278 items.push(value);
279 }
280 } else {
281 break;
282 }
283 }
284 Err(_) => return JSValue::undefined(),
285 }
286 }
287 }
288 }
289 }
290 }
291 Err(_) => return JSValue::undefined(),
292 }
293 }
294 } else {
295 let len = obj.get(ctx.common_atoms.length)
296 .map(|v| {
297 if v.is_string() {
298 let s = ctx.get_atom_str(v.get_atom());
299 let n: f64 = s.parse().unwrap_or(f64::NAN);
300 if n.is_nan() || n <= 0.0 { 0usize }
301 else if n.is_infinite() { usize::MAX }
302 else { n as usize }
303 } else {
304 crate::builtins::string::js_to_length(&v) as usize
305 }
306 })
307 .unwrap_or(0);
308
309 for i in 0..len {
310 let val = crate::builtins::array::array_get(obj, i, ctx)
311 .unwrap_or(JSValue::undefined());
312 if let Some(mf) = map_fn {
313 match crate::builtins::array::call_callback(ctx, mf, &[val, JSValue::new_int(i as i64), source]) {
314 Ok(v) => items.push(v),
315 Err(_) => return JSValue::undefined(),
316 }
317 } else {
318 items.push(val);
319 }
320 }
321 }
322 }
323
324 let len = items.len();
325 let buffer = create_array_buffer(ctx, len * 8);
326 match create_typed_array(ctx, TypedArrayKind::Float64, buffer, 0, Some(len)) {
327 Ok(result) => {
328 if result.is_object() {
329 let mut result_obj = result.as_object_mut();
330 for (i, &val) in items.iter().enumerate() {
331 ta_set_element(ctx, &mut result_obj, i, val);
332 }
333 }
334 result
335 }
336 Err(e) => {
337 throw_type_error(ctx, &e);
338 JSValue::undefined()
339 }
340 }
341}
342
343fn typedarray_of(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
344 let items: Vec<JSValue> = args[1..].to_vec();
345 let len = items.len();
346 let buffer = create_array_buffer(ctx, len * 8);
347 match create_typed_array(ctx, TypedArrayKind::Float64, buffer, 0, Some(len)) {
348 Ok(result) => {
349 if result.is_object() {
350 let mut result_obj = result.as_object_mut();
351 for (i, &val) in items.iter().enumerate() {
352 ta_set_element(ctx, &mut result_obj, i, val);
353 }
354 }
355 result
356 }
357 Err(e) => {
358 throw_type_error(ctx, &e);
359 JSValue::undefined()
360 }
361 }
362}
363
364fn typedarray_species_get(_ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
365 if let Some(this_val) = args.first() {
366 *this_val
367 } else {
368 JSValue::undefined()
369 }
370}
371
372fn int8_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
373 typed_array_from_args(ctx, TypedArrayKind::Int8, args).unwrap_or(JSValue::undefined())
374}
375
376fn uint8_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
377 typed_array_from_args(ctx, TypedArrayKind::Uint8, args).unwrap_or(JSValue::undefined())
378}
379
380fn uint8_clamped_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
381 typed_array_from_args(ctx, TypedArrayKind::Uint8Clamped, args).unwrap_or(JSValue::undefined())
382}
383
384fn int16_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
385 typed_array_from_args(ctx, TypedArrayKind::Int16, args).unwrap_or(JSValue::undefined())
386}
387
388fn uint16_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
389 typed_array_from_args(ctx, TypedArrayKind::Uint16, args).unwrap_or(JSValue::undefined())
390}
391
392fn int32_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
393 typed_array_from_args(ctx, TypedArrayKind::Int32, args).unwrap_or(JSValue::undefined())
394}
395
396fn uint32_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
397 typed_array_from_args(ctx, TypedArrayKind::Uint32, args).unwrap_or(JSValue::undefined())
398}
399
400fn float32_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
401 typed_array_from_args(ctx, TypedArrayKind::Float32, args).unwrap_or(JSValue::undefined())
402}
403
404fn float64_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
405 typed_array_from_args(ctx, TypedArrayKind::Float64, args).unwrap_or(JSValue::undefined())
406}
407
408fn bigint64_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
409 typed_array_from_args(ctx, TypedArrayKind::BigInt64, args).unwrap_or(JSValue::undefined())
410}
411
412fn biguint64_array_constructor(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
413 typed_array_from_args(ctx, TypedArrayKind::BigUint64, args).unwrap_or(JSValue::undefined())
414}
415
416fn typed_array_get_buffer(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
417 if args.is_empty() || !args[0].is_object() {
418 return JSValue::undefined();
419 }
420 let obj = args[0].as_object();
421 obj.get(ctx.intern("buffer"))
422 .unwrap_or(JSValue::undefined())
423}
424
425fn typed_array_get_byte_length(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
426 if args.is_empty() || !args[0].is_object() {
427 return JSValue::undefined();
428 }
429 let obj = args[0].as_object();
430 obj.get(ctx.intern("byteLength"))
431 .unwrap_or(JSValue::undefined())
432}
433
434fn typed_array_get_byte_offset(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
435 if args.is_empty() || !args[0].is_object() {
436 return JSValue::undefined();
437 }
438 let obj = args[0].as_object();
439 obj.get(ctx.intern("byteOffset"))
440 .unwrap_or(JSValue::undefined())
441}
442
443fn typed_array_get_length(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
444 if args.is_empty() || !args[0].is_object() {
445 return JSValue::undefined();
446 }
447 let obj = args[0].as_object();
448 obj.get(ctx.intern("length"))
449 .unwrap_or(JSValue::undefined())
450}
451
452fn array_buffer_get_byte_length(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
453 if args.is_empty() || !args[0].is_object() {
454 return JSValue::undefined();
455 }
456 let obj = args[0].as_object();
457 obj.get(ctx.intern("byteLength"))
458 .unwrap_or(JSValue::undefined())
459}
460
461fn data_view_get_buffer(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
462 if !dv_check_this(args, ctx) {
463 return JSValue::undefined();
464 }
465 let obj = args[0].as_object();
466 obj.get(ctx.intern("buffer"))
467 .unwrap_or(JSValue::undefined())
468}
469
470fn data_view_get_byte_length(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
471 if !dv_check_this(args, ctx) {
472 return JSValue::undefined();
473 }
474 let obj = args[0].as_object();
475 obj.get(ctx.intern("byteLength"))
476 .unwrap_or(JSValue::undefined())
477}
478
479fn data_view_get_byte_offset(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
480 if !dv_check_this(args, ctx) {
481 return JSValue::undefined();
482 }
483 let obj = args[0].as_object();
484 obj.get(ctx.intern("byteOffset"))
485 .unwrap_or(JSValue::undefined())
486}
487
488fn data_view_get_int8(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
489 match dv_read_bytes_checked(args, ctx, 1) {
490 Some(b) => JSValue::new_int(b[0] as i8 as i64),
491 None => JSValue::undefined(),
492 }
493}
494
495fn data_view_get_uint8(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
496 match dv_read_bytes_checked(args, ctx, 1) {
497 Some(b) => JSValue::new_int(b[0] as i64),
498 None => JSValue::undefined(),
499 }
500}
501
502fn f16_to_f32(val: u16) -> f32 {
503 let sign = (val >> 15) as u32;
504 let exp = (val >> 10) & 0x1F;
505 let mantissa = val & 0x3FF;
506
507 if exp == 0 {
508 if mantissa == 0 {
509 f32::from_bits(sign << 31)
510 } else {
511 let mut m = mantissa as u32;
512 let mut e = 1;
513 while (m & 0x400) == 0 {
514 m <<= 1;
515 e -= 1;
516 }
517 m &= 0x3FF;
518 f32::from_bits((sign << 31) | (((112 + e) as u32) << 23) | (m << 13))
519 }
520 } else if exp == 31 {
521 f32::from_bits((sign << 31) | 0x7F800000 | ((mantissa as u32) << 13))
522 } else {
523 f32::from_bits((sign << 31) | (((exp as u32) + 112) << 23) | ((mantissa as u32) << 13))
524 }
525}
526
527fn f32_to_f16(val: f32) -> u16 {
528 let bits = val.to_bits();
529 let sign = (bits >> 16) as u16;
530 let exp = ((bits >> 23) & 0xFF) as i32;
531 let mantissa = bits & 0x7FFFFF;
532
533 if exp == 0xFF {
534 return sign | 0x7C00 | if mantissa != 0 { 0x200 } else { 0 };
535 }
536 if exp == 0 {
537 return sign | (mantissa >> 13) as u16;
538 }
539 let new_exp = exp - 127 + 15;
540 if new_exp >= 31 {
541 return sign | 0x7C00;
542 }
543 if new_exp <= 0 {
544 return sign | (mantissa >> (14 - new_exp)) as u16;
545 }
546 sign | ((new_exp as u16) << 10) | ((mantissa >> 13) as u16)
547}
548
549fn dv_extract_buffer_info(args: &[JSValue], ctx: &mut JSContext) -> Option<(Vec<u8>, usize)> {
550 if args.is_empty() || !args[0].is_object() {
551 return None;
552 }
553 let view_obj = args[0].as_object();
554 let byte_offset = view_obj
555 .get(ctx.intern("byteOffset"))
556 .map(|v| v.to_number() as usize)
557 .unwrap_or(0);
558 let buffer = view_obj.get(ctx.intern("buffer"))?;
559 if !buffer.is_object() { return None; }
560 let buf_obj = buffer.as_object();
561 let data = get_array_buffer_data(&buf_obj)?;
562 Some((data.data.clone(), byte_offset))
563}
564
565fn throw_type_error(ctx: &mut JSContext, msg: &str) {
566 let mut err = JSObject::new();
567 if let Some(proto_ptr) = ctx.get_type_error_prototype() {
568 err.prototype = Some(proto_ptr);
569 }
570 err.set(ctx.common_atoms.name, JSValue::new_string(ctx.intern("TypeError")));
571 err.set(ctx.common_atoms.message, JSValue::new_string(ctx.intern(msg)));
572 let ptr = Box::into_raw(Box::new(err)) as usize;
573 ctx.runtime_mut().gc_heap_mut().track(ptr);
574 ctx.pending_exception = Some(JSValue::new_object(ptr));
575}
576
577fn throw_range_error(ctx: &mut JSContext, msg: &str) {
578 let mut err = JSObject::new();
579 if let Some(proto_ptr) = ctx.get_range_error_prototype() {
580 err.prototype = Some(proto_ptr);
581 }
582 err.set(ctx.common_atoms.name, JSValue::new_string(ctx.intern("RangeError")));
583 err.set(ctx.common_atoms.message, JSValue::new_string(ctx.intern(msg)));
584 let ptr = Box::into_raw(Box::new(err)) as usize;
585 ctx.runtime_mut().gc_heap_mut().track(ptr);
586 ctx.pending_exception = Some(JSValue::new_object(ptr));
587}
588
589fn dv_check_this(args: &[JSValue], ctx: &mut JSContext) -> bool {
590 if args.is_empty() || !args[0].is_object() {
591 throw_type_error(ctx, "Method called on incompatible receiver");
592 return false;
593 }
594 let view_obj = args[0].as_object();
595 if view_obj.obj_type() != crate::object::object::ObjectType::DataView {
596 throw_type_error(ctx, "Method called on incompatible receiver");
597 return false;
598 }
599 true
600}
601
602fn dv_to_index(val: f64) -> Option<usize> {
603 if val.is_nan() || val < 0.0 || !val.is_finite() {
604 return None;
605 }
606 Some(val as usize)
607}
608
609fn dv_read_bytes_checked(args: &[JSValue], ctx: &mut JSContext, n: usize) -> Option<[u8; 8]> {
610 if !dv_check_this(args, ctx) { return None; }
611 if args.len() < 2 { return None; }
612 let raw_offset = args[1].to_number();
613 let offset = match dv_to_index(raw_offset) {
614 Some(o) => o,
615 None => {
616 throw_range_error(ctx, &format!("Offset is out of range: {}", raw_offset));
617 return None;
618 }
619 };
620 let little_endian = args.get(2).map_or(false, |v| v.is_truthy());
621 let (data, byte_offset) = dv_extract_buffer_info(args, ctx)?;
622 let idx = match byte_offset.checked_add(offset) {
623 Some(i) => i,
624 None => {
625 throw_range_error(ctx, "Offset is out of range");
626 return None;
627 }
628 };
629 if idx + n > data.len() {
630 throw_range_error(ctx, "Offset is out of range for DataView");
631 return None;
632 }
633 let mut buf = [0u8; 8];
634 buf[..n].copy_from_slice(&data[idx..idx+n]);
635 if little_endian {
636 buf[..n].reverse();
637 }
638 Some(buf)
639}
640
641fn dv_write_bytes_checked(args: &[JSValue], ctx: &mut JSContext, bytes: &[u8]) -> bool {
642 if !dv_check_this(args, ctx) { return false; }
643 if args.len() < 3 {
644 throw_type_error(ctx, "Not enough arguments");
645 return false;
646 }
647 let raw_offset = args[1].to_number();
648 let offset = match dv_to_index(raw_offset) {
649 Some(o) => o,
650 None => {
651 throw_range_error(ctx, &format!("Offset is out of range: {}", raw_offset));
652 return false;
653 }
654 };
655 let little_endian = args.get(3).map_or(false, |v| v.is_truthy());
656 let view_obj = args[0].as_object();
657 let byte_offset = view_obj
658 .get(ctx.intern("byteOffset"))
659 .map(|v| v.to_number() as usize)
660 .unwrap_or(0);
661 let buffer = match view_obj.get(ctx.intern("buffer")) {
662 Some(b) => b,
663 None => {
664 throw_type_error(ctx, "Detached buffer");
665 return false;
666 }
667 };
668 if !buffer.is_object() {
669 throw_type_error(ctx, "Detached buffer");
670 return false;
671 }
672 let buf_obj = buffer.as_object();
673 let data = match get_array_buffer_data(&buf_obj) {
674 Some(d) => d,
675 None => {
676 throw_type_error(ctx, "Detached buffer");
677 return false;
678 }
679 };
680 let idx = match byte_offset.checked_add(offset) {
681 Some(i) => i,
682 None => {
683 throw_range_error(ctx, "Offset is out of range");
684 return false;
685 }
686 };
687 if idx + bytes.len() > data.data.len() {
688 throw_range_error(ctx, "Offset is out of range for DataView");
689 return false;
690 }
691 if little_endian {
692 let mut rev = bytes.to_vec();
693 rev.reverse();
694 data.data[idx..idx+bytes.len()].copy_from_slice(&rev);
695 } else {
696 data.data[idx..idx+bytes.len()].copy_from_slice(bytes);
697 }
698 true
699}
700
701fn data_view_set_int8(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
702 if args.len() < 3 { return JSValue::undefined(); }
703 let val = args[2].get_int() as i8 as u8;
704 let bytes = [val];
705 dv_write_bytes_checked(args, ctx, &bytes);
706 JSValue::undefined()
707}
708
709fn data_view_set_uint8(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
710 if args.len() < 3 { return JSValue::undefined(); }
711 let val = args[2].get_int() as u8;
712 let bytes = [val];
713 dv_write_bytes_checked(args, ctx, &bytes);
714 JSValue::undefined()
715}
716
717fn data_view_set_int16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
718 if args.len() < 3 { return JSValue::undefined(); }
719 let val = args[2].to_number() as i16;
720 let bytes = val.to_be_bytes();
721 dv_write_bytes_checked(args, ctx, &bytes);
722 JSValue::undefined()
723}
724
725fn data_view_set_uint16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
726 if args.len() < 3 { return JSValue::undefined(); }
727 let val = args[2].to_number() as u16;
728 let bytes = val.to_be_bytes();
729 dv_write_bytes_checked(args, ctx, &bytes);
730 JSValue::undefined()
731}
732
733fn data_view_set_int32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
734 if args.len() < 3 { return JSValue::undefined(); }
735 let val = args[2].to_number() as i32;
736 let bytes = val.to_be_bytes();
737 dv_write_bytes_checked(args, ctx, &bytes);
738 JSValue::undefined()
739}
740
741fn data_view_set_uint32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
742 if args.len() < 3 { return JSValue::undefined(); }
743 let val = args[2].to_number() as u32;
744 let bytes = val.to_be_bytes();
745 dv_write_bytes_checked(args, ctx, &bytes);
746 JSValue::undefined()
747}
748
749fn data_view_set_float32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
750 if args.len() < 3 { return JSValue::undefined(); }
751 let val = args[2].to_number() as f32;
752 let bytes = val.to_be_bytes();
753 dv_write_bytes_checked(args, ctx, &bytes);
754 JSValue::undefined()
755}
756
757fn data_view_set_float64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
758 if args.len() < 3 { return JSValue::undefined(); }
759 let val = args[2].to_number();
760 let bytes = val.to_be_bytes();
761 dv_write_bytes_checked(args, ctx, &bytes);
762 JSValue::undefined()
763}
764
765fn data_view_set_float16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
766 if args.len() < 3 { return JSValue::undefined(); }
767 let val = args[2].to_number() as f32;
768 let h = f32_to_f16(val);
769 let bytes = h.to_be_bytes();
770 dv_write_bytes_checked(args, ctx, &bytes);
771 JSValue::undefined()
772}
773
774fn data_view_get_int16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
775 match dv_read_bytes_checked(args, ctx, 2) {
776 Some(b) => JSValue::new_int(i16::from_be_bytes([b[0], b[1]]) as i64),
777 None => JSValue::undefined(),
778 }
779}
780
781fn data_view_get_uint16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
782 match dv_read_bytes_checked(args, ctx, 2) {
783 Some(b) => JSValue::new_int(u16::from_be_bytes([b[0], b[1]]) as i64),
784 None => JSValue::undefined(),
785 }
786}
787
788fn data_view_get_int32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
789 match dv_read_bytes_checked(args, ctx, 4) {
790 Some(b) => JSValue::new_int(i32::from_be_bytes([b[0], b[1], b[2], b[3]]) as i64),
791 None => JSValue::undefined(),
792 }
793}
794
795fn data_view_get_uint32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
796 match dv_read_bytes_checked(args, ctx, 4) {
797 Some(b) => {
798 let val = u32::from_be_bytes([b[0], b[1], b[2], b[3]]);
799 JSValue::new_int(val as i64)
800 }
801 None => JSValue::undefined(),
802 }
803}
804
805fn data_view_get_float32(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
806 match dv_read_bytes_checked(args, ctx, 4) {
807 Some(b) => JSValue::new_float(f32::from_be_bytes([b[0], b[1], b[2], b[3]]) as f64),
808 None => JSValue::undefined(),
809 }
810}
811
812fn data_view_get_float64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
813 match dv_read_bytes_checked(args, ctx, 8) {
814 Some(b) => JSValue::new_float(f64::from_be_bytes([
815 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
816 ])),
817 None => JSValue::undefined(),
818 }
819}
820
821fn data_view_get_float16(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
822 match dv_read_bytes_checked(args, ctx, 2) {
823 Some(b) => {
824 let val = u16::from_be_bytes([b[0], b[1]]);
825 JSValue::new_float(f16_to_f32(val) as f64)
826 }
827 None => JSValue::undefined(),
828 }
829}
830
831fn data_view_get_bigint64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
832 match dv_read_bytes_checked(args, ctx, 8) {
833 Some(b) => {
834 let val = i64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
835 let mut obj = crate::object::object::JSObject::new_bigint();
836 obj.set_bigint_value(val as i128);
837 JSValue::new_bigint(Box::into_raw(Box::new(obj)) as usize)
838 }
839 None => JSValue::undefined(),
840 }
841}
842
843fn data_view_get_biguint64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
844 match dv_read_bytes_checked(args, ctx, 8) {
845 Some(b) => {
846 let val = u64::from_be_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
847 let mut obj = crate::object::object::JSObject::new_bigint();
848 obj.set_bigint_value(val as i128);
849 JSValue::new_bigint(Box::into_raw(Box::new(obj)) as usize)
850 }
851 None => JSValue::undefined(),
852 }
853}
854
855fn data_view_set_bigint64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
856 if args.len() < 3 { return JSValue::undefined(); }
857 let val = if args[2].is_bigint() {
858 let obj = args[2].as_object();
859 obj.get_bigint_value() as i64
860 } else {
861 args[2].to_number() as i64
862 };
863 let bytes = val.to_be_bytes();
864 dv_write_bytes_checked(args, ctx, &bytes);
865 JSValue::undefined()
866}
867
868fn data_view_set_biguint64(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
869 if args.len() < 3 { return JSValue::undefined(); }
870 let val = if args[2].is_bigint() {
871 let obj = args[2].as_object();
872 obj.get_bigint_value() as u64
873 } else {
874 args[2].to_number() as u64
875 };
876 let bytes = val.to_be_bytes();
877 dv_write_bytes_checked(args, ctx, &bytes);
878 JSValue::undefined()
879}
880
881fn create_builtin_function(ctx: &mut JSContext, name: &str) -> JSValue {
882 let arity = ctx.get_builtin_arity(name).unwrap_or(1);
883 let mut func = crate::object::function::JSFunction::new_builtin(ctx.intern(name), arity);
884 func.set_builtin_marker(ctx, name);
885 let ptr = Box::into_raw(Box::new(func)) as usize;
886 ctx.runtime_mut().gc_heap_mut().track_function(ptr);
887 JSValue::new_function(ptr)
888}
889
890fn ta_check_this(args: &[JSValue], ctx: &mut JSContext) -> bool {
891 if args.is_empty() || !args[0].is_object() {
892 throw_type_error(ctx, "Method called on incompatible receiver");
893 return false;
894 }
895 let obj = args[0].as_object();
896 if obj.obj_type() != ObjectType::TypedArray {
897 throw_type_error(ctx, "Method called on incompatible receiver");
898 return false;
899 }
900 true
901}
902
903fn ta_get_length(ctx: &mut JSContext, obj: &JSObject) -> usize {
904 obj.get(ctx.common_atoms.length)
905 .map(|v| v.get_int() as usize)
906 .unwrap_or(0)
907}
908
909pub fn ta_get_element(ctx: &mut JSContext, obj: &JSObject, index: usize) -> Option<JSValue> {
910 let kind = obj.get_typed_array_kind()?;
911 let bpe = kind.bytes_per_element();
912 let byte_offset = obj.get(ctx.intern("byteOffset"))
913 .map(|v| v.get_int() as usize)
914 .unwrap_or(0);
915 let buffer = obj.get(ctx.intern("buffer"))?;
916 if !buffer.is_object() { return None; }
917 let buf_obj = buffer.as_object();
918 let data = get_array_buffer_data(&buf_obj)?;
919 let byte_index = byte_offset + index * bpe;
920 if byte_index + bpe > data.data.len() { return None; }
921 let bytes = &data.data[byte_index..byte_index + bpe];
922 Some(match kind {
923 TypedArrayKind::Int8 => JSValue::new_int(bytes[0] as i8 as i64),
924 TypedArrayKind::Uint8 | TypedArrayKind::Uint8Clamped => JSValue::new_int(bytes[0] as i64),
925 TypedArrayKind::Int16 => JSValue::new_int(i16::from_le_bytes([bytes[0], bytes[1]]) as i64),
926 TypedArrayKind::Uint16 => JSValue::new_int(u16::from_le_bytes([bytes[0], bytes[1]]) as i64),
927 TypedArrayKind::Int32 => JSValue::new_int(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as i64),
928 TypedArrayKind::Uint32 => JSValue::new_int(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as i64),
929 TypedArrayKind::Float32 => JSValue::new_float(f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as f64),
930 TypedArrayKind::Float64 => JSValue::new_float(f64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]])),
931 TypedArrayKind::BigInt64 => {
932 let val = i64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]);
933 let mut bi_obj = crate::object::object::JSObject::new_bigint();
934 bi_obj.set_bigint_value(val as i128);
935 JSValue::new_bigint(Box::into_raw(Box::new(bi_obj)) as usize)
936 }
937 TypedArrayKind::BigUint64 => {
938 let val = u64::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7]]);
939 let mut bi_obj = crate::object::object::JSObject::new_bigint();
940 bi_obj.set_bigint_value(val as i128);
941 JSValue::new_bigint(Box::into_raw(Box::new(bi_obj)) as usize)
942 }
943 })
944}
945
946pub fn ta_set_element(ctx: &mut JSContext, obj: &mut JSObject, index: usize, value: JSValue) -> bool {
947 let kind = match obj.get_typed_array_kind() {
948 Some(k) => k,
949 None => return false,
950 };
951 let bpe = kind.bytes_per_element();
952 let byte_offset = obj.get(ctx.intern("byteOffset"))
953 .map(|v| v.get_int() as usize)
954 .unwrap_or(0);
955 let buffer = match obj.get(ctx.intern("buffer")) {
956 Some(b) => b,
957 None => return false,
958 };
959 if !buffer.is_object() { return false; }
960 let buf_obj = buffer.as_object();
961 let data = match get_array_buffer_data(&buf_obj) {
962 Some(d) => d,
963 None => return false,
964 };
965 let byte_index = byte_offset + index * bpe;
966 if byte_index + bpe > data.data.len() { return false; }
967 let num = value.to_number();
968 match kind {
969 TypedArrayKind::Int8 => {
970 let v = num as i8;
971 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
972 }
973 TypedArrayKind::Uint8 | TypedArrayKind::Uint8Clamped => {
974 let v = num as u8;
975 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
976 }
977 TypedArrayKind::Int16 => {
978 let v = num as i16;
979 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
980 }
981 TypedArrayKind::Uint16 => {
982 let v = num as u16;
983 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
984 }
985 TypedArrayKind::Int32 => {
986 let v = num as i32;
987 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
988 }
989 TypedArrayKind::Uint32 => {
990 let v = num as u32;
991 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
992 }
993 TypedArrayKind::Float32 => {
994 let v = num as f32;
995 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
996 }
997 TypedArrayKind::Float64 => {
998 let v = num;
999 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
1000 }
1001 TypedArrayKind::BigInt64 | TypedArrayKind::BigUint64 => {
1002 let v = num as i64;
1003 data.data[byte_index..byte_index + bpe].copy_from_slice(&v.to_le_bytes());
1004 }
1005 }
1006 true
1007}
1008
1009fn ta_call_callback(
1010 ctx: &mut JSContext,
1011 callback: JSValue,
1012 this_value: JSValue,
1013 args: &[JSValue],
1014) -> Result<JSValue, String> {
1015 if let Some(ptr) = ctx.get_register_vm_ptr() {
1016 let vm = unsafe { &mut *(ptr as *mut crate::runtime::vm::VM) };
1017 vm.call_function_with_this(ctx, callback, this_value, args)
1018 } else {
1019 Err("call_callback: VM not available".to_string())
1020 }
1021}
1022
1023fn typed_array_for_each(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1024 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1025 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1026 if !callback.is_function() {
1027 throw_type_error(ctx, "Callback is not a function");
1028 return JSValue::undefined();
1029 }
1030 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1031 let obj = args[0].as_object();
1032 let len = ta_get_length(ctx, obj);
1033 for i in 0..len {
1034 if let Some(val) = ta_get_element(ctx, obj, i) {
1035 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1036 let _ = ta_call_callback(ctx, callback, this_arg, &cb_args);
1037 }
1038 }
1039 JSValue::undefined()
1040}
1041
1042fn typed_array_every(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1043 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1044 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1045 if !callback.is_function() {
1046 throw_type_error(ctx, "Callback is not a function");
1047 return JSValue::undefined();
1048 }
1049 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1050 let obj = args[0].as_object();
1051 let len = ta_get_length(ctx, obj);
1052 for i in 0..len {
1053 if let Some(val) = ta_get_element(ctx, obj, i) {
1054 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1055 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1056 Ok(result) => {
1057 if !result.is_truthy() {
1058 return JSValue::new_int(0);
1059 }
1060 }
1061 Err(_) => return JSValue::undefined(),
1062 }
1063 }
1064 }
1065 JSValue::new_int(1)
1066}
1067
1068fn typed_array_some(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1069 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1070 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1071 if !callback.is_function() {
1072 throw_type_error(ctx, "Callback is not a function");
1073 return JSValue::undefined();
1074 }
1075 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1076 let obj = args[0].as_object();
1077 let len = ta_get_length(ctx, obj);
1078 for i in 0..len {
1079 if let Some(val) = ta_get_element(ctx, obj, i) {
1080 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1081 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1082 Ok(result) => {
1083 if result.is_truthy() {
1084 return JSValue::bool(true);
1085 }
1086 }
1087 Err(_) => return JSValue::undefined(),
1088 }
1089 }
1090 }
1091 JSValue::new_int(0)
1092}
1093
1094fn typed_array_find(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1095 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1096 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1097 if !callback.is_function() {
1098 throw_type_error(ctx, "Callback is not a function");
1099 return JSValue::undefined();
1100 }
1101 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1102 let obj = args[0].as_object();
1103 let len = ta_get_length(ctx, obj);
1104 for i in 0..len {
1105 if let Some(val) = ta_get_element(ctx, obj, i) {
1106 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1107 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1108 Ok(result) => {
1109 if result.is_truthy() {
1110 return val;
1111 }
1112 }
1113 Err(_) => return JSValue::undefined(),
1114 }
1115 }
1116 }
1117 JSValue::undefined()
1118}
1119
1120fn typed_array_find_index(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1121 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1122 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1123 if !callback.is_function() {
1124 throw_type_error(ctx, "Callback is not a function");
1125 return JSValue::undefined();
1126 }
1127 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1128 let obj = args[0].as_object();
1129 let len = ta_get_length(ctx, obj);
1130 for i in 0..len {
1131 if let Some(val) = ta_get_element(ctx, obj, i) {
1132 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1133 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1134 Ok(result) => {
1135 if result.is_truthy() {
1136 return JSValue::new_int(i as i64);
1137 }
1138 }
1139 Err(_) => return JSValue::new_int(-1),
1140 }
1141 }
1142 }
1143 JSValue::new_int(-1)
1144}
1145
1146fn typed_array_find_last(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1147 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1148 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1149 if !callback.is_function() {
1150 throw_type_error(ctx, "Callback is not a function");
1151 return JSValue::undefined();
1152 }
1153 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1154 let obj = args[0].as_object();
1155 let len = ta_get_length(ctx, obj);
1156 let mut result = JSValue::undefined();
1157 for i in 0..len {
1158 if let Some(val) = ta_get_element(ctx, obj, i) {
1159 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1160 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1161 Ok(res) => {
1162 if res.is_truthy() {
1163 result = val;
1164 }
1165 }
1166 Err(_) => return JSValue::undefined(),
1167 }
1168 }
1169 }
1170 result
1171}
1172
1173fn typed_array_find_last_index(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1174 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1175 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1176 if !callback.is_function() {
1177 throw_type_error(ctx, "Callback is not a function");
1178 return JSValue::undefined();
1179 }
1180 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1181 let obj = args[0].as_object();
1182 let len = ta_get_length(ctx, obj);
1183 let mut result = JSValue::new_int(-1);
1184 for i in 0..len {
1185 if let Some(val) = ta_get_element(ctx, obj, i) {
1186 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1187 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1188 Ok(res) => {
1189 if res.is_truthy() {
1190 result = JSValue::new_int(i as i64);
1191 }
1192 }
1193 Err(_) => return JSValue::new_int(-1),
1194 }
1195 }
1196 }
1197 result
1198}
1199
1200fn typed_array_reduce(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1201 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1202 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1203 if !callback.is_function() {
1204 throw_type_error(ctx, "Callback is not a function");
1205 return JSValue::undefined();
1206 }
1207 let obj = args[0].as_object();
1208 let len = ta_get_length(ctx, obj);
1209 let mut acc = JSValue::undefined();
1210 let mut start = 0;
1211 if len == 0 {
1212 if args.len() < 3 {
1213 throw_type_error(ctx, "Reduce of empty array with no initial value");
1214 return JSValue::undefined();
1215 }
1216 acc = args[2];
1217 } else if args.len() >= 3 {
1218 acc = args[2];
1219 } else {
1220 start = 1;
1221 acc = ta_get_element(ctx, obj, 0).unwrap_or(JSValue::undefined());
1222 }
1223 for i in start..len {
1224 if let Some(val) = ta_get_element(ctx, obj, i) {
1225 let cb_args = vec![acc, val, JSValue::new_int(i as i64), args[0]];
1226 match ta_call_callback(ctx, callback, JSValue::undefined(), &cb_args) {
1227 Ok(res) => { acc = res; }
1228 Err(_) => return JSValue::undefined(),
1229 }
1230 }
1231 }
1232 acc
1233}
1234
1235fn typed_array_reduce_right(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1236 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1237 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1238 if !callback.is_function() {
1239 throw_type_error(ctx, "Callback is not a function");
1240 return JSValue::undefined();
1241 }
1242 let obj = args[0].as_object();
1243 let len = ta_get_length(ctx, obj);
1244 let mut acc = JSValue::undefined();
1245 let mut end = len;
1246 if len == 0 {
1247 if args.len() < 3 {
1248 throw_type_error(ctx, "Reduce of empty array with no initial value");
1249 return JSValue::undefined();
1250 }
1251 acc = args[2];
1252 } else if args.len() >= 3 {
1253 acc = args[2];
1254 } else {
1255 end -= 1;
1256 acc = ta_get_element(ctx, obj, end).unwrap_or(JSValue::undefined());
1257 }
1258 for i in (0..end).rev() {
1259 if let Some(val) = ta_get_element(ctx, obj, i) {
1260 let cb_args = vec![acc, val, JSValue::new_int(i as i64), args[0]];
1261 match ta_call_callback(ctx, callback, JSValue::undefined(), &cb_args) {
1262 Ok(res) => { acc = res; }
1263 Err(_) => return JSValue::undefined(),
1264 }
1265 }
1266 }
1267 acc
1268}
1269
1270fn typed_array_map(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1271 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1272 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1273 if !callback.is_function() {
1274 throw_type_error(ctx, "Callback is not a function");
1275 return JSValue::undefined();
1276 }
1277 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1278 let obj = args[0].as_object();
1279 let len = ta_get_length(ctx, obj);
1280 let kind = obj.get_typed_array_kind().unwrap_or(TypedArrayKind::Int32);
1281 let result = typed_array_from_args(ctx, kind, &[
1282 JSValue::new_int(len as i64),
1283 ]);
1284 match result {
1285 Ok(r) => {
1286 let result_obj = r.as_object_mut();
1287 for i in 0..len {
1288 if let Some(val) = ta_get_element(ctx, obj, i) {
1289 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1290 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1291 Ok(mapped) => { ta_set_element(ctx, result_obj, i, mapped); }
1292 Err(_) => return JSValue::undefined(),
1293 }
1294 }
1295 }
1296 r
1297 }
1298 Err(_) => JSValue::undefined(),
1299 }
1300}
1301
1302fn typed_array_filter(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1303 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1304 let callback = args.get(1).copied().unwrap_or(JSValue::undefined());
1305 if !callback.is_function() {
1306 throw_type_error(ctx, "Callback is not a function");
1307 return JSValue::undefined();
1308 }
1309 let this_arg = args.get(2).copied().unwrap_or(JSValue::undefined());
1310 let obj = args[0].as_object();
1311 let len = ta_get_length(ctx, obj);
1312 let kind = obj.get_typed_array_kind().unwrap_or(TypedArrayKind::Int32);
1313 let mut result: Vec<JSValue> = Vec::new();
1314 for i in 0..len {
1315 if let Some(val) = ta_get_element(ctx, obj, i) {
1316 let cb_args = vec![val, JSValue::new_int(i as i64), args[0]];
1317 match ta_call_callback(ctx, callback, this_arg, &cb_args) {
1318 Ok(res) => {
1319 if res.is_truthy() {
1320 result.push(val);
1321 }
1322 }
1323 Err(_) => return JSValue::undefined(),
1324 }
1325 }
1326 }
1327 let result_val = typed_array_from_args(ctx, kind, &[
1328 JSValue::new_int(result.len() as i64),
1329 ]);
1330 match result_val {
1331 Ok(r) => {
1332 let result_obj = r.as_object_mut();
1333 for (i, val) in result.iter().enumerate() {
1334 ta_set_element(ctx, result_obj, i, *val);
1335 }
1336 r
1337 }
1338 Err(_) => JSValue::undefined(),
1339 }
1340}
1341
1342fn typed_array_index_of(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1343 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1344 let search = args.get(1).copied().unwrap_or(JSValue::undefined());
1345 let obj = args[0].as_object();
1346 let len = ta_get_length(ctx, obj);
1347 let from_index = if args.len() >= 3 {
1348 let v = args[2].to_number() as i64;
1349 if v < 0 { (len as i64 + v).max(0) as usize } else { (v as usize).min(len) }
1350 } else {
1351 0
1352 };
1353 for i in from_index..len {
1354 if let Some(val) = ta_get_element(ctx, obj, i) {
1355 if val.strict_eq(&search) {
1356 return JSValue::new_int(i as i64);
1357 }
1358 }
1359 }
1360 JSValue::new_int(-1)
1361}
1362
1363fn typed_array_last_index_of(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1364 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1365 let search = args.get(1).copied().unwrap_or(JSValue::undefined());
1366 let obj = args[0].as_object();
1367 let len = ta_get_length(ctx, obj);
1368 let from_index = if args.len() >= 3 {
1369 let v = args[2].to_number() as i64;
1370 if v < 0 { 0 } else { (v as usize).min(len.saturating_sub(1)) }
1371 } else {
1372 len.saturating_sub(1)
1373 };
1374 for i in (0..=from_index).rev() {
1375 if let Some(val) = ta_get_element(ctx, obj, i) {
1376 if val.strict_eq(&search) {
1377 return JSValue::new_int(i as i64);
1378 }
1379 }
1380 }
1381 JSValue::new_int(-1)
1382}
1383
1384fn typed_array_includes(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1385 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1386 let search = args.get(1).copied().unwrap_or(JSValue::undefined());
1387 let obj = args[0].as_object();
1388 let len = ta_get_length(ctx, obj);
1389 let from_index = if args.len() >= 3 {
1390 let v = args[2].to_number() as i64;
1391 if v < 0 { (len as i64 + v).max(0) as usize } else { (v as usize).min(len) }
1392 } else {
1393 0
1394 };
1395 for i in from_index..len {
1396 if let Some(val) = ta_get_element(ctx, obj, i) {
1397 if val.strict_eq(&search) {
1398 return JSValue::bool(true);
1399 }
1400 if search.is_float() && val.is_float() {
1401 let sv = search.to_number();
1402 let vv = val.to_number();
1403 if sv.is_nan() && vv.is_nan() {
1404 return JSValue::bool(true);
1405 }
1406 }
1407 }
1408 }
1409 JSValue::new_int(0)
1410}
1411
1412fn typed_array_join(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1413 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1414 let separator = args.get(1).copied().unwrap_or(JSValue::undefined());
1415 let sep_str = if separator.is_undefined() {
1416 ",".to_string()
1417 } else if separator.is_string() {
1418 ctx.get_atom_str(separator.get_atom()).to_string()
1419 } else if separator.is_int() {
1420 separator.get_int().to_string()
1421 } else if separator.is_float() {
1422 separator.get_float().to_string()
1423 } else if separator.is_bool() {
1424 separator.get_bool().to_string()
1425 } else if separator.is_null() {
1426 "null".to_string()
1427 } else {
1428 ",".to_string()
1429 };
1430 let obj = args[0].as_object();
1431 let len = ta_get_length(ctx, obj);
1432 let mut parts = Vec::new();
1433 for i in 0..len {
1434 if let Some(val) = ta_get_element(ctx, obj, i) {
1435 if val.is_undefined() || val.is_null() {
1436 parts.push(String::new());
1437 } else if val.is_string() {
1438 parts.push(ctx.get_atom_str(val.get_atom()).to_string());
1439 } else if val.is_int() {
1440 parts.push(val.get_int().to_string());
1441 } else if val.is_float() {
1442 parts.push(val.get_float().to_string());
1443 } else if val.is_bool() {
1444 parts.push(val.get_bool().to_string());
1445 } else {
1446 parts.push(String::new());
1447 }
1448 } else {
1449 parts.push(String::new());
1450 }
1451 }
1452 JSValue::new_string(ctx.intern(&parts.join(&sep_str)))
1453}
1454
1455fn typed_array_at(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1456 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1457 let obj = args[0].as_object();
1458 let len = ta_get_length(ctx, obj) as i64;
1459 let relative_index = args.get(1).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1460 let k = if relative_index >= 0 {
1461 relative_index
1462 } else {
1463 len + relative_index
1464 };
1465 if k < 0 || k >= len {
1466 return JSValue::undefined();
1467 }
1468 ta_get_element(ctx, obj, k as usize).unwrap_or(JSValue::undefined())
1469}
1470
1471fn typed_array_values(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1472 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1473 JSValue::undefined()
1474}
1475
1476fn typed_array_keys(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1477 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1478 JSValue::undefined()
1479}
1480
1481fn typed_array_entries(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1482 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1483 JSValue::undefined()
1484}
1485
1486fn typed_array_to_string(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1487 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1488 typed_array_join(ctx, &[
1489 args[0],
1490 JSValue::undefined(),
1491 ])
1492}
1493
1494fn typed_array_reverse(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1495 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1496 let obj = args[0].as_object_mut();
1497 let len = ta_get_length(ctx, obj);
1498 let mut values: Vec<JSValue> = Vec::with_capacity(len);
1499 for i in 0..len {
1500 values.push(ta_get_element(ctx, obj, i).unwrap_or(JSValue::undefined()));
1501 }
1502 values.reverse();
1503 for i in 0..len {
1504 ta_set_element(ctx, obj, i, values[i]);
1505 }
1506 args[0]
1507}
1508
1509fn typed_array_slice(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1510 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1511 let obj = args[0].as_object();
1512 let len = ta_get_length(ctx, obj) as i64;
1513 let start = {
1514 let v = args.get(1).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1515 if v < 0 { (len + v).max(0) } else { v.min(len) }
1516 };
1517 let end = {
1518 let v = args.get(2).copied().unwrap_or(JSValue::new_int(len)).to_number() as i64;
1519 if v < 0 { (len + v).max(0) } else { v.min(len) }
1520 };
1521 let new_len = (end - start).max(0) as usize;
1522 let kind = obj.get_typed_array_kind().unwrap_or(TypedArrayKind::Int32);
1523 let result = typed_array_from_args(ctx, kind, &[
1524 JSValue::new_int(new_len as i64),
1525 ]);
1526 match result {
1527 Ok(r) => {
1528 let result_obj = r.as_object_mut();
1529 for i in 0..new_len {
1530 if let Some(val) = ta_get_element(ctx, obj, (start as usize) + i) {
1531 ta_set_element(ctx, result_obj, i, val);
1532 }
1533 }
1534 r
1535 }
1536 Err(_) => JSValue::undefined(),
1537 }
1538}
1539
1540fn typed_array_fill(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1541 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1542 let value = args.get(1).copied().unwrap_or(JSValue::undefined());
1543 let obj = args[0].as_object_mut();
1544 let len = ta_get_length(ctx, obj) as i64;
1545 let start = {
1546 let v = args.get(2).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1547 if v < 0 { (len + v).max(0) } else { v.min(len) }
1548 };
1549 let end = {
1550 let v = args.get(3).copied().unwrap_or(JSValue::new_int(len)).to_number() as i64;
1551 if v < 0 { (len + v).max(0) } else { v.min(len) }
1552 };
1553 for i in start..end {
1554 ta_set_element(ctx, obj, i as usize, value);
1555 }
1556 args[0]
1557}
1558
1559fn typed_array_copy_within(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1560 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1561 let obj = args[0].as_object_mut();
1562 let len = ta_get_length(ctx, obj) as i64;
1563 let target = {
1564 let v = args.get(1).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1565 if v < 0 { (len + v).max(0) } else { v.min(len) }
1566 };
1567 let start = {
1568 let v = args.get(2).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1569 if v < 0 { (len + v).max(0) } else { v.min(len) }
1570 };
1571 let end = {
1572 let v = args.get(3).copied().unwrap_or(JSValue::new_int(len)).to_number() as i64;
1573 if v < 0 { (len + v).max(0) } else { v.min(len) }
1574 };
1575 let count = (end - start).min(len - target).max(0) as usize;
1576 let mut values = Vec::with_capacity(count);
1577 for i in 0..count {
1578 values.push(ta_get_element(ctx, obj, (start as usize) + i).unwrap_or(JSValue::undefined()));
1579 }
1580 for (i, val) in values.into_iter().enumerate() {
1581 ta_set_element(ctx, obj, (target as usize) + i, val);
1582 }
1583 args[0]
1584}
1585
1586fn typed_array_sort(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1587 if !ta_check_this(args, ctx) { return JSValue::undefined(); }
1588 let compare_fn = args.get(1).copied().unwrap_or(JSValue::undefined());
1589 let obj = args[0].as_object_mut();
1590 let len = ta_get_length(ctx, obj);
1591 if len <= 1 {
1592 return args[0];
1593 }
1594 let mut values: Vec<JSValue> = Vec::with_capacity(len);
1595 for i in 0..len {
1596 values.push(ta_get_element(ctx, obj, i).unwrap_or(JSValue::undefined()));
1597 }
1598 let compare_is_fn = compare_fn.is_function();
1599 values.sort_by(|a, b| {
1600 if compare_is_fn {
1601 let cb_args = vec![*a, *b];
1602 if let Some(ptr) = ctx.get_register_vm_ptr() {
1603 let vm = unsafe { &mut *(ptr as *mut crate::runtime::vm::VM) };
1604 if let Ok(result) = vm.call_function_with_this(ctx, compare_fn, JSValue::undefined(), &cb_args) {
1605 let n = result.to_number();
1606 if n < 0.0 { std::cmp::Ordering::Less }
1607 else if n > 0.0 { std::cmp::Ordering::Greater }
1608 else { std::cmp::Ordering::Equal }
1609 } else {
1610 std::cmp::Ordering::Equal
1611 }
1612 } else {
1613 std::cmp::Ordering::Equal
1614 }
1615 } else {
1616 let a_str = a.to_number();
1617 let b_str = b.to_number();
1618 a_str.partial_cmp(&b_str).unwrap_or(std::cmp::Ordering::Equal)
1619 }
1620 });
1621 for (i, val) in values.into_iter().enumerate() {
1622 ta_set_element(ctx, obj, i, val);
1623 }
1624 args[0]
1625}
1626
1627fn typed_array_subarray(ctx: &mut JSContext, args: &[JSValue]) -> JSValue {
1628 if args.is_empty() || !args[0].is_object() {
1629 throw_type_error(ctx, "Method called on incompatible receiver");
1630 return JSValue::undefined();
1631 }
1632 let obj = args[0].as_object();
1633 if obj.obj_type() != ObjectType::TypedArray {
1634 throw_type_error(ctx, "Method called on incompatible receiver");
1635 return JSValue::undefined();
1636 }
1637 let len = ta_get_length(ctx, obj) as i64;
1638 let buffer = obj.get(ctx.intern("buffer")).unwrap_or(JSValue::undefined());
1639 let byte_offset = obj.get(ctx.intern("byteOffset"))
1640 .map(|v| v.get_int())
1641 .unwrap_or(0);
1642 let element_size = obj.get_typed_array_kind()
1643 .map(|k| k.bytes_per_element() as i64)
1644 .unwrap_or(1);
1645 let start = {
1646 let v = args.get(1).copied().unwrap_or(JSValue::new_int(0)).to_number() as i64;
1647 if v < 0 { (len + v).max(0) } else { v.min(len) }
1648 };
1649 let end = {
1650 let v = args.get(2).copied().unwrap_or(JSValue::new_int(len)).to_number() as i64;
1651 if v < 0 { (len + v).max(0) } else { v.min(len) }
1652 };
1653 let new_len = (end - start).max(0) as usize;
1654 let new_byte_offset = byte_offset + start * element_size;
1655 let kind = obj.get_typed_array_kind().unwrap_or(TypedArrayKind::Int32);
1656 match create_typed_array(ctx, kind, buffer, new_byte_offset as usize, Some(new_len)) {
1657 Ok(v) => v,
1658 Err(_) => JSValue::undefined(),
1659 }
1660}
1661
1662pub fn init_typed_array(ctx: &mut JSContext) {
1663 let global = ctx.global();
1664 if !global.is_object() {
1665 return;
1666 }
1667 let global_obj = global.as_object_mut();
1668
1669 crate::builtins::global::set_non_enumerable(
1670 global_obj,
1671 ctx.intern("ArrayBuffer"),
1672 create_builtin_function(ctx, "ArrayBuffer"),
1673 );
1674
1675 let mut dv_proto = JSObject::new();
1676 dv_proto.set(ctx.intern("buffer"), create_builtin_function(ctx, "dataview_buffer"));
1677 dv_proto.set(
1678 ctx.intern("byteLength"),
1679 create_builtin_function(ctx, "dataview_byteLength"),
1680 );
1681 dv_proto.set(
1682 ctx.intern("byteOffset"),
1683 create_builtin_function(ctx, "dataview_byteOffset"),
1684 );
1685 dv_proto.set(
1686 ctx.intern("getInt8"),
1687 create_builtin_function(ctx, "dataview_getInt8"),
1688 );
1689 dv_proto.set(
1690 ctx.intern("getUint8"),
1691 create_builtin_function(ctx, "dataview_getUint8"),
1692 );
1693 dv_proto.set(
1694 ctx.intern("setInt8"),
1695 create_builtin_function(ctx, "dataview_setInt8"),
1696 );
1697 dv_proto.set(
1698 ctx.intern("setUint8"),
1699 create_builtin_function(ctx, "dataview_setUint8"),
1700 );
1701 dv_proto.set(
1702 ctx.intern("getInt16"),
1703 create_builtin_function(ctx, "dataview_getInt16"),
1704 );
1705 dv_proto.set(
1706 ctx.intern("getUint16"),
1707 create_builtin_function(ctx, "dataview_getUint16"),
1708 );
1709 dv_proto.set(
1710 ctx.intern("getInt32"),
1711 create_builtin_function(ctx, "dataview_getInt32"),
1712 );
1713 dv_proto.set(
1714 ctx.intern("getUint32"),
1715 create_builtin_function(ctx, "dataview_getUint32"),
1716 );
1717 dv_proto.set(
1718 ctx.intern("getFloat32"),
1719 create_builtin_function(ctx, "dataview_getFloat32"),
1720 );
1721 dv_proto.set(
1722 ctx.intern("getFloat64"),
1723 create_builtin_function(ctx, "dataview_getFloat64"),
1724 );
1725 dv_proto.set(
1726 ctx.intern("getFloat16"),
1727 create_builtin_function(ctx, "dataview_getFloat16"),
1728 );
1729 dv_proto.set(
1730 ctx.intern("setInt16"),
1731 create_builtin_function(ctx, "dataview_setInt16"),
1732 );
1733 dv_proto.set(
1734 ctx.intern("setUint16"),
1735 create_builtin_function(ctx, "dataview_setUint16"),
1736 );
1737 dv_proto.set(
1738 ctx.intern("setInt32"),
1739 create_builtin_function(ctx, "dataview_setInt32"),
1740 );
1741 dv_proto.set(
1742 ctx.intern("setUint32"),
1743 create_builtin_function(ctx, "dataview_setUint32"),
1744 );
1745 dv_proto.set(
1746 ctx.intern("setFloat32"),
1747 create_builtin_function(ctx, "dataview_setFloat32"),
1748 );
1749 dv_proto.set(
1750 ctx.intern("setFloat64"),
1751 create_builtin_function(ctx, "dataview_setFloat64"),
1752 );
1753 dv_proto.set(
1754 ctx.intern("setFloat16"),
1755 create_builtin_function(ctx, "dataview_setFloat16"),
1756 );
1757 dv_proto.set(
1758 ctx.intern("getBigInt64"),
1759 create_builtin_function(ctx, "dataview_getBigInt64"),
1760 );
1761 dv_proto.set(
1762 ctx.intern("getBigUint64"),
1763 create_builtin_function(ctx, "dataview_getBigUint64"),
1764 );
1765 dv_proto.set(
1766 ctx.intern("setBigInt64"),
1767 create_builtin_function(ctx, "dataview_setBigInt64"),
1768 );
1769 dv_proto.set(
1770 ctx.intern("setBigUint64"),
1771 create_builtin_function(ctx, "dataview_setBigUint64"),
1772 );
1773
1774 let to_string_tag_key = crate::builtins::symbol::get_symbol_to_string_tag_prop_key(ctx);
1775 dv_proto.set(to_string_tag_key, JSValue::new_string(ctx.intern("DataView")));
1776
1777 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
1778 dv_proto.prototype = Some(obj_proto_ptr);
1779 }
1780
1781 let dv_proto_ptr = Box::into_raw(Box::new(dv_proto)) as usize;
1782 ctx.runtime_mut().gc_heap_mut().track(dv_proto_ptr);
1783 ctx.set_dataview_prototype(dv_proto_ptr);
1784
1785 let dv_ctor = create_builtin_function(ctx, "DataView");
1786 if dv_ctor.is_function() {
1787 let dv_ctor_obj = dv_ctor.as_object_mut();
1788 dv_ctor_obj.set(ctx.intern("prototype"), JSValue::new_object(dv_proto_ptr));
1789 }
1790 crate::builtins::global::set_non_enumerable(
1791 global_obj,
1792 ctx.intern("DataView"),
1793 dv_ctor,
1794 );
1795
1796 crate::builtins::global::set_non_enumerable(
1797 global_obj,
1798 ctx.intern("Int8Array"),
1799 create_builtin_function(ctx, "Int8Array"),
1800 );
1801 crate::builtins::global::set_non_enumerable(
1802 global_obj,
1803 ctx.intern("Uint8Array"),
1804 create_builtin_function(ctx, "Uint8Array"),
1805 );
1806 crate::builtins::global::set_non_enumerable(
1807 global_obj,
1808 ctx.intern("Uint8ClampedArray"),
1809 create_builtin_function(ctx, "Uint8ClampedArray"),
1810 );
1811 crate::builtins::global::set_non_enumerable(
1812 global_obj,
1813 ctx.intern("Int16Array"),
1814 create_builtin_function(ctx, "Int16Array"),
1815 );
1816 crate::builtins::global::set_non_enumerable(
1817 global_obj,
1818 ctx.intern("Uint16Array"),
1819 create_builtin_function(ctx, "Uint16Array"),
1820 );
1821 crate::builtins::global::set_non_enumerable(
1822 global_obj,
1823 ctx.intern("Int32Array"),
1824 create_builtin_function(ctx, "Int32Array"),
1825 );
1826 crate::builtins::global::set_non_enumerable(
1827 global_obj,
1828 ctx.intern("Uint32Array"),
1829 create_builtin_function(ctx, "Uint32Array"),
1830 );
1831 crate::builtins::global::set_non_enumerable(
1832 global_obj,
1833 ctx.intern("Float32Array"),
1834 create_builtin_function(ctx, "Float32Array"),
1835 );
1836 crate::builtins::global::set_non_enumerable(
1837 global_obj,
1838 ctx.intern("Float64Array"),
1839 create_builtin_function(ctx, "Float64Array"),
1840 );
1841 crate::builtins::global::set_non_enumerable(
1842 global_obj,
1843 ctx.intern("BigInt64Array"),
1844 create_builtin_function(ctx, "BigInt64Array"),
1845 );
1846 crate::builtins::global::set_non_enumerable(
1847 global_obj,
1848 ctx.intern("BigUint64Array"),
1849 create_builtin_function(ctx, "BigUint64Array"),
1850 );
1851
1852 let mut ta_proto = JSObject::new();
1853 ta_proto.set(ctx.intern("forEach"), create_builtin_function(ctx, "ta_forEach"));
1854 ta_proto.set(ctx.intern("every"), create_builtin_function(ctx, "ta_every"));
1855 ta_proto.set(ctx.intern("some"), create_builtin_function(ctx, "ta_some"));
1856 ta_proto.set(ctx.intern("find"), create_builtin_function(ctx, "ta_find"));
1857 ta_proto.set(ctx.intern("findIndex"), create_builtin_function(ctx, "ta_findIndex"));
1858 ta_proto.set(ctx.intern("findLast"), create_builtin_function(ctx, "ta_findLast"));
1859 ta_proto.set(ctx.intern("findLastIndex"), create_builtin_function(ctx, "ta_findLastIndex"));
1860 ta_proto.set(ctx.intern("reduce"), create_builtin_function(ctx, "ta_reduce"));
1861 ta_proto.set(ctx.intern("reduceRight"), create_builtin_function(ctx, "ta_reduceRight"));
1862 ta_proto.set(ctx.intern("map"), create_builtin_function(ctx, "ta_map"));
1863 ta_proto.set(ctx.intern("filter"), create_builtin_function(ctx, "ta_filter"));
1864 ta_proto.set(ctx.intern("indexOf"), create_builtin_function(ctx, "ta_indexOf"));
1865 ta_proto.set(ctx.intern("lastIndexOf"), create_builtin_function(ctx, "ta_lastIndexOf"));
1866 ta_proto.set(ctx.intern("includes"), create_builtin_function(ctx, "ta_includes"));
1867 ta_proto.set(ctx.intern("join"), create_builtin_function(ctx, "ta_join"));
1868 ta_proto.set(ctx.intern("at"), create_builtin_function(ctx, "ta_at"));
1869 ta_proto.set(ctx.intern("values"), create_builtin_function(ctx, "ta_values"));
1870 ta_proto.set(ctx.intern("keys"), create_builtin_function(ctx, "ta_keys"));
1871 ta_proto.set(ctx.intern("entries"), create_builtin_function(ctx, "ta_entries"));
1872 ta_proto.set(ctx.intern("toString"), create_builtin_function(ctx, "ta_toString"));
1873 ta_proto.set(ctx.intern("reverse"), create_builtin_function(ctx, "ta_reverse"));
1874 ta_proto.set(ctx.intern("slice"), create_builtin_function(ctx, "ta_slice"));
1875 ta_proto.set(ctx.intern("fill"), create_builtin_function(ctx, "ta_fill"));
1876 ta_proto.set(ctx.intern("copyWithin"), create_builtin_function(ctx, "ta_copyWithin"));
1877 ta_proto.set(ctx.intern("sort"), create_builtin_function(ctx, "ta_sort"));
1878 ta_proto.set(ctx.intern("subarray"), create_builtin_function(ctx, "ta_subarray"));
1879
1880 let to_string_tag_key = crate::builtins::symbol::get_symbol_to_string_tag_prop_key(ctx);
1881 ta_proto.set(to_string_tag_key, JSValue::new_string(ctx.intern("TypedArray")));
1882
1883 if let Some(obj_proto_ptr) = ctx.get_object_prototype() {
1884 ta_proto.prototype = Some(obj_proto_ptr);
1885 }
1886 let ta_proto_ptr = Box::into_raw(Box::new(ta_proto)) as usize;
1887 ctx.runtime_mut().gc_heap_mut().track(ta_proto_ptr);
1888 ctx.set_typed_array_prototype(ta_proto_ptr);
1889
1890 let ta_names = [
1891 "Int8Array", "Uint8Array", "Uint8ClampedArray",
1892 "Int16Array", "Uint16Array", "Int32Array", "Uint32Array",
1893 "Float32Array", "Float64Array", "BigInt64Array", "BigUint64Array",
1894 ];
1895 for name in &ta_names {
1896 let atom = ctx.intern(name);
1897 if let Some(ctor_val) = global_obj.get(atom) {
1898 if ctor_val.is_function() {
1899 let ctor_obj = ctor_val.as_object_mut();
1900 ctor_obj.set(ctx.intern("prototype"), JSValue::new_object(ta_proto_ptr));
1901 ctor_obj.set(ctx.intern("from"), create_builtin_function(ctx, "typedarray_from"));
1902 ctor_obj.set(ctx.intern("of"), create_builtin_function(ctx, "typedarray_of"));
1903 ctor_obj.set(ctx.intern("name"), JSValue::new_string(ctx.intern(name)));
1904 ctor_obj.set(ctx.intern("length"), JSValue::new_int(1));
1905 let species_fn = create_builtin_function(ctx, "typedarray_species_get");
1906 let species_sym = crate::builtins::symbol::get_symbol_species(ctx);
1907 if !species_sym.is_undefined() {
1908 ctor_obj.set(species_sym.get_atom(), species_fn);
1909 }
1910 }
1911 }
1912 }
1913
1914 let ta_sym_tag = crate::builtins::symbol::get_symbol_to_string_tag(ctx);
1915 if !ta_sym_tag.is_undefined() {
1916 if let Some(proto_obj) = ctx.get_typed_array_prototype() {
1917 unsafe {
1918 (*proto_obj).set(ta_sym_tag.get_atom(), JSValue::new_string(ctx.intern("TypedArray")));
1919 }
1920 }
1921 }
1922}
1923
1924pub fn register_builtins(ctx: &mut JSContext) {
1925 ctx.register_builtin(
1926 "ArrayBuffer",
1927 HostFunction::ctor("ArrayBuffer", 1, array_buffer_constructor),
1928 );
1929 ctx.register_builtin(
1930 "DataView",
1931 HostFunction::ctor("DataView", 1, data_view_constructor),
1932 );
1933
1934 ctx.register_builtin(
1935 "Int8Array",
1936 HostFunction::ctor("Int8Array", 1, int8_array_constructor),
1937 );
1938 ctx.register_builtin(
1939 "Uint8Array",
1940 HostFunction::ctor("Uint8Array", 1, uint8_array_constructor),
1941 );
1942 ctx.register_builtin(
1943 "Uint8ClampedArray",
1944 HostFunction::ctor("Uint8ClampedArray", 1, uint8_clamped_array_constructor),
1945 );
1946 ctx.register_builtin(
1947 "Int16Array",
1948 HostFunction::ctor("Int16Array", 1, int16_array_constructor),
1949 );
1950 ctx.register_builtin(
1951 "Uint16Array",
1952 HostFunction::ctor("Uint16Array", 1, uint16_array_constructor),
1953 );
1954 ctx.register_builtin(
1955 "Int32Array",
1956 HostFunction::ctor("Int32Array", 1, int32_array_constructor),
1957 );
1958 ctx.register_builtin(
1959 "Uint32Array",
1960 HostFunction::ctor("Uint32Array", 1, uint32_array_constructor),
1961 );
1962 ctx.register_builtin(
1963 "Float32Array",
1964 HostFunction::ctor("Float32Array", 1, float32_array_constructor),
1965 );
1966 ctx.register_builtin(
1967 "Float64Array",
1968 HostFunction::ctor("Float64Array", 1, float64_array_constructor),
1969 );
1970 ctx.register_builtin(
1971 "BigInt64Array",
1972 HostFunction::ctor("BigInt64Array", 1, bigint64_array_constructor),
1973 );
1974 ctx.register_builtin(
1975 "BigUint64Array",
1976 HostFunction::ctor("BigUint64Array", 1, biguint64_array_constructor),
1977 );
1978
1979 ctx.register_builtin(
1980 "typedarray_buffer",
1981 HostFunction::method("buffer", 0, typed_array_get_buffer),
1982 );
1983 ctx.register_builtin(
1984 "typedarray_byteLength",
1985 HostFunction::method("byteLength", 0, typed_array_get_byte_length),
1986 );
1987 ctx.register_builtin(
1988 "typedarray_byteOffset",
1989 HostFunction::method("byteOffset", 0, typed_array_get_byte_offset),
1990 );
1991 ctx.register_builtin(
1992 "typedarray_length",
1993 HostFunction::method("length", 0, typed_array_get_length),
1994 );
1995
1996 ctx.register_builtin(
1997 "arraybuffer_byteLength",
1998 HostFunction::method("byteLength", 0, array_buffer_get_byte_length),
1999 );
2000
2001 ctx.register_builtin(
2002 "dataview_buffer",
2003 HostFunction::method("buffer", 0, data_view_get_buffer),
2004 );
2005 ctx.register_builtin(
2006 "dataview_byteLength",
2007 HostFunction::method("byteLength", 0, data_view_get_byte_length),
2008 );
2009 ctx.register_builtin(
2010 "dataview_byteOffset",
2011 HostFunction::method("byteOffset", 0, data_view_get_byte_offset),
2012 );
2013 ctx.register_builtin(
2014 "dataview_getInt8",
2015 HostFunction::method("getInt8", 1, data_view_get_int8),
2016 );
2017 ctx.register_builtin(
2018 "dataview_getUint8",
2019 HostFunction::method("getUint8", 1, data_view_get_uint8),
2020 );
2021 ctx.register_builtin(
2022 "dataview_setInt8",
2023 HostFunction::method("setInt8", 2, data_view_set_int8),
2024 );
2025 ctx.register_builtin(
2026 "dataview_setUint8",
2027 HostFunction::method("setUint8", 2, data_view_set_uint8),
2028 );
2029 ctx.register_builtin(
2030 "dataview_getInt16",
2031 HostFunction::method("getInt16", 2, data_view_get_int16),
2032 );
2033 ctx.register_builtin(
2034 "dataview_getUint16",
2035 HostFunction::method("getUint16", 2, data_view_get_uint16),
2036 );
2037 ctx.register_builtin(
2038 "dataview_getInt32",
2039 HostFunction::method("getInt32", 2, data_view_get_int32),
2040 );
2041 ctx.register_builtin(
2042 "dataview_getUint32",
2043 HostFunction::method("getUint32", 2, data_view_get_uint32),
2044 );
2045 ctx.register_builtin(
2046 "dataview_getFloat32",
2047 HostFunction::method("getFloat32", 2, data_view_get_float32),
2048 );
2049 ctx.register_builtin(
2050 "dataview_getFloat64",
2051 HostFunction::method("getFloat64", 2, data_view_get_float64),
2052 );
2053 ctx.register_builtin(
2054 "dataview_getFloat16",
2055 HostFunction::method("getFloat16", 2, data_view_get_float16),
2056 );
2057 ctx.register_builtin(
2058 "dataview_setFloat16",
2059 HostFunction::method("setFloat16", 3, data_view_set_float16),
2060 );
2061 ctx.register_builtin(
2062 "dataview_setInt16",
2063 HostFunction::method("setInt16", 3, data_view_set_int16),
2064 );
2065 ctx.register_builtin(
2066 "dataview_setUint16",
2067 HostFunction::method("setUint16", 3, data_view_set_uint16),
2068 );
2069 ctx.register_builtin(
2070 "dataview_setInt32",
2071 HostFunction::method("setInt32", 3, data_view_set_int32),
2072 );
2073 ctx.register_builtin(
2074 "dataview_setUint32",
2075 HostFunction::method("setUint32", 3, data_view_set_uint32),
2076 );
2077 ctx.register_builtin(
2078 "dataview_setFloat32",
2079 HostFunction::method("setFloat32", 3, data_view_set_float32),
2080 );
2081 ctx.register_builtin(
2082 "dataview_setFloat64",
2083 HostFunction::method("setFloat64", 3, data_view_set_float64),
2084 );
2085 ctx.register_builtin(
2086 "dataview_getBigInt64",
2087 HostFunction::method("getBigInt64", 2, data_view_get_bigint64),
2088 );
2089 ctx.register_builtin(
2090 "dataview_getBigUint64",
2091 HostFunction::method("getBigUint64", 2, data_view_get_biguint64),
2092 );
2093 ctx.register_builtin(
2094 "dataview_setBigInt64",
2095 HostFunction::method("setBigInt64", 3, data_view_set_bigint64),
2096 );
2097 ctx.register_builtin(
2098 "dataview_setBigUint64",
2099 HostFunction::method("setBigUint64", 3, data_view_set_biguint64),
2100 );
2101 ctx.register_builtin(
2102 "ta_forEach",
2103 HostFunction::method("forEach", 1, typed_array_for_each),
2104 );
2105 ctx.register_builtin(
2106 "ta_every",
2107 HostFunction::method("every", 1, typed_array_every),
2108 );
2109 ctx.register_builtin(
2110 "ta_some",
2111 HostFunction::method("some", 1, typed_array_some),
2112 );
2113 ctx.register_builtin(
2114 "ta_find",
2115 HostFunction::method("find", 1, typed_array_find),
2116 );
2117 ctx.register_builtin(
2118 "ta_findIndex",
2119 HostFunction::method("findIndex", 1, typed_array_find_index),
2120 );
2121 ctx.register_builtin(
2122 "ta_findLast",
2123 HostFunction::method("findLast", 1, typed_array_find_last),
2124 );
2125 ctx.register_builtin(
2126 "ta_findLastIndex",
2127 HostFunction::method("findLastIndex", 1, typed_array_find_last_index),
2128 );
2129 ctx.register_builtin(
2130 "ta_reduce",
2131 HostFunction::method("reduce", 1, typed_array_reduce),
2132 );
2133 ctx.register_builtin(
2134 "ta_reduceRight",
2135 HostFunction::method("reduceRight", 1, typed_array_reduce_right),
2136 );
2137 ctx.register_builtin(
2138 "ta_map",
2139 HostFunction::method("map", 1, typed_array_map),
2140 );
2141 ctx.register_builtin(
2142 "ta_filter",
2143 HostFunction::method("filter", 1, typed_array_filter),
2144 );
2145 ctx.register_builtin(
2146 "ta_indexOf",
2147 HostFunction::method("indexOf", 1, typed_array_index_of),
2148 );
2149 ctx.register_builtin(
2150 "ta_lastIndexOf",
2151 HostFunction::method("lastIndexOf", 1, typed_array_last_index_of),
2152 );
2153 ctx.register_builtin(
2154 "ta_includes",
2155 HostFunction::method("includes", 1, typed_array_includes),
2156 );
2157 ctx.register_builtin(
2158 "ta_join",
2159 HostFunction::method("join", 1, typed_array_join),
2160 );
2161 ctx.register_builtin(
2162 "ta_at",
2163 HostFunction::method("at", 1, typed_array_at),
2164 );
2165 ctx.register_builtin(
2166 "ta_values",
2167 HostFunction::method("values", 0, typed_array_values),
2168 );
2169 ctx.register_builtin(
2170 "ta_keys",
2171 HostFunction::method("keys", 0, typed_array_keys),
2172 );
2173 ctx.register_builtin(
2174 "ta_entries",
2175 HostFunction::method("entries", 0, typed_array_entries),
2176 );
2177 ctx.register_builtin(
2178 "ta_toString",
2179 HostFunction::method("toString", 0, typed_array_to_string),
2180 );
2181 ctx.register_builtin(
2182 "ta_reverse",
2183 HostFunction::method("reverse", 0, typed_array_reverse),
2184 );
2185 ctx.register_builtin(
2186 "ta_slice",
2187 HostFunction::method("slice", 2, typed_array_slice),
2188 );
2189 ctx.register_builtin(
2190 "ta_fill",
2191 HostFunction::method("fill", 1, typed_array_fill),
2192 );
2193 ctx.register_builtin(
2194 "ta_copyWithin",
2195 HostFunction::method("copyWithin", 2, typed_array_copy_within),
2196 );
2197 ctx.register_builtin(
2198 "ta_sort",
2199 HostFunction::method("sort", 1, typed_array_sort),
2200 );
2201 ctx.register_builtin(
2202 "ta_subarray",
2203 HostFunction::method("subarray", 2, typed_array_subarray),
2204 );
2205 ctx.register_builtin(
2206 "typedarray_from",
2207 HostFunction::method("from", 1, typedarray_from),
2208 );
2209 ctx.register_builtin(
2210 "typedarray_of",
2211 HostFunction::method("of", 0, typedarray_of),
2212 );
2213 ctx.register_builtin(
2214 "typedarray_species_get",
2215 HostFunction::new("get [Symbol.species]", 0, typedarray_species_get),
2216 );
2217}