mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 10:41:11 +08:00
refactor: array 排序与迭代协议拆出 sort_iterator 模块
This commit is contained in:
@@ -1,11 +1,8 @@
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
mod common;
|
||||
pub(crate) use common::*;
|
||||
@@ -19,243 +16,8 @@ pub use element::*;
|
||||
mod iterate;
|
||||
pub use iterate::*;
|
||||
|
||||
/// `Array.prototype.sort(compareFn)`:原地排序。默认按字符串字典序;
|
||||
/// 提供比较函数时按其返回值(<0/=0/>0)排序,回调抛错则中止。
|
||||
/// 对元素向量执行 Array.prototype.sort 的比较语义(原地)。
|
||||
/// 比较回调抛错时中止并把异常返回;默认按字符串字典序。
|
||||
fn sort_values_inner<H: VmHost>(vm: &mut H, vals: &mut [JsValue], comparator: Option<JsValue>) -> Result<(), JsValue> {
|
||||
let mut sort_error = None;
|
||||
vals.sort_by(|a, b| {
|
||||
if sort_error.is_some() {
|
||||
return std::cmp::Ordering::Equal;
|
||||
}
|
||||
if let Some(callback) = comparator {
|
||||
match invoke_native_callback(vm, callback, JsValue::undefined(), &[*a, *b]) {
|
||||
NativeResult::Ok(result) => {
|
||||
let n = oxide_runtime_api::to_number(result);
|
||||
if n.is_nan() || n == 0.0 {
|
||||
std::cmp::Ordering::Equal
|
||||
} else if n < 0.0 {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
sort_error = Some(err);
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
sort_error = Some(crate::error::create_type_error(vm, "unexpected tail call in array callback"));
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let sa = oxide_runtime_api::to_string(*a);
|
||||
let sb = oxide_runtime_api::to_string(*b);
|
||||
sa.cmp(&sb)
|
||||
}
|
||||
});
|
||||
if let Some(err) = sort_error {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 解析 sort/toSorted 的比较回调参数(undefined 视为默认排序)。
|
||||
fn parse_sort_comparator<H: VmHost>(vm: &mut H, candidate: JsValue) -> Result<Option<JsValue>, JsValue> {
|
||||
if candidate.is_undefined() {
|
||||
return Ok(None);
|
||||
}
|
||||
match require_callback(vm, candidate) {
|
||||
Ok(callback) => Ok(Some(callback)),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.sort called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let len = unsafe { (*arr_ptr).prop_count() as usize };
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| unsafe { (*arr_ptr).get_prop_at(i) }).collect();
|
||||
let comparator = if args.len() > 1 {
|
||||
match parse_sort_comparator(vm, vm.reg(args[1])) {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Err(err) = sort_values_inner(vm, &mut vals, comparator) {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
for (i, &v) in vals.iter().enumerate() {
|
||||
arr.set_prop_at(i, v);
|
||||
}
|
||||
NativeResult::Ok(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
/// `Array.prototype.values()`:返回迭代数组元素的迭代器(%ArrayIteratorPrototype%)。
|
||||
pub fn array_values<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.values called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_VALUES) {
|
||||
Ok(iterator) => NativeResult::Ok(iterator),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.values: invalid receiver");
|
||||
NativeResult::Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Array Iterator 的内部 kind 编码:0=values,1=keys,2=entries。
|
||||
/// TypedArray 迭代器复用同一编码与 %ArrayIteratorPrototype%(规范同族)。
|
||||
pub(crate) const ARRAY_ITER_KIND_VALUES: i32 = 0;
|
||||
pub(crate) const ARRAY_ITER_KIND_KEYS: i32 = 1;
|
||||
pub(crate) const ARRAY_ITER_KIND_ENTRIES: i32 = 2;
|
||||
|
||||
const ARRAY_ITER_TARGET_PROP: &str = "__target__";
|
||||
const ARRAY_ITER_INDEX_PROP: &str = "__index__";
|
||||
const ARRAY_ITER_KIND_PROP: &str = "__kind__";
|
||||
|
||||
/// 创建 Array/TA Iterator 对象:记录目标、当前下标与迭代种类,原型挂
|
||||
/// `%ArrayIteratorPrototype%`(链到 `%IteratorPrototype%`,Array 与 TA 共享)。
|
||||
/// `next` 不挂实例 own——由原型提供。
|
||||
pub(crate) fn make_array_iterator<H: VmHost>(vm: &mut H, this_val: JsValue, kind: i32) -> Result<JsValue, JsValue> {
|
||||
let target = match oxide_runtime_api::to_object(this_val, vm) {
|
||||
Ok(v) => v,
|
||||
Err(msg) => return Err(array_type_error(vm, &msg)),
|
||||
};
|
||||
let array_iter_proto = vm.session().builtin_world().array_iterator_proto.as_ptr() as *mut JsObject;
|
||||
let iter = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(array_iter_proto)));
|
||||
let target_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_TARGET_PROP).0;
|
||||
let index_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_INDEX_PROP).0;
|
||||
let kind_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_KIND_PROP).0;
|
||||
let iter_ref = unsafe { &mut *iter };
|
||||
vm.set_or_create_prop_value(iter_ref, target_si, target);
|
||||
vm.set_or_create_prop_value(iter_ref, index_si, JsValue::int(0));
|
||||
vm.set_or_create_prop_value(iter_ref, kind_si, JsValue::int(kind));
|
||||
Ok(JsValue::from_js_object(iter))
|
||||
}
|
||||
|
||||
/// Array.prototype.entries():返回按索引产出 [index, value] 对的迭代器。
|
||||
pub fn array_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.entries called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_ENTRIES) {
|
||||
Ok(iter) => NativeResult::Ok(iter),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Array.prototype.keys():返回按索引产出下标的迭代器。
|
||||
pub fn array_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.keys called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_KEYS) {
|
||||
Ok(iter) => NativeResult::Ok(iter),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Array Iterator 的 next:读取目标当前下标处的值,按种类产出后推进下标。
|
||||
pub fn array_iterator_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
if !this_val.is_object() {
|
||||
return NativeResult::Err(array_type_error(vm, "Array Iterator next called on non-object"));
|
||||
}
|
||||
let iter = unsafe { &mut *this_val.as_js_object_ptr() };
|
||||
let target_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_TARGET_PROP).0;
|
||||
let index_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_INDEX_PROP).0;
|
||||
let kind_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_KIND_PROP).0;
|
||||
let target = match vm.ordinary_get(iter, target_si, this_val) {
|
||||
Ok(v) if v.is_undefined() => {
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
Ok(v) if v.is_object() => v,
|
||||
_ => return NativeResult::Err(array_type_error(vm, "Array Iterator has no iterated object")),
|
||||
};
|
||||
let index = vm
|
||||
.ordinary_get(iter, index_si, this_val)
|
||||
.ok()
|
||||
.and_then(|v| if v.is_int() { Some(v.as_int()) } else { None })
|
||||
.unwrap_or(0);
|
||||
let kind = vm
|
||||
.ordinary_get(iter, kind_si, this_val)
|
||||
.ok()
|
||||
.and_then(|v| if v.is_int() { Some(v.as_int()) } else { None })
|
||||
.unwrap_or(ARRAY_ITER_KIND_VALUES);
|
||||
|
||||
let target_obj = unsafe { &*target.as_js_object_ptr() };
|
||||
// TypedArray 目标走底层 buffer 读取(元素非普通属性,length 语义不同):
|
||||
// 与 Array 共享 %ArrayIteratorPrototype%,须在此分支区分两种取数路径。
|
||||
if target_obj.is_typed_array_obj() {
|
||||
let view = match crate::typed_array::get_typed_array_data(vm, target) {
|
||||
Ok(view) => view,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
if (index as usize) >= view.length {
|
||||
vm.set_or_create_prop_value(iter, target_si, JsValue::undefined());
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
let element = match crate::typed_array::typed_array_element_get(vm, target_obj, index as u32) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(crate::error::create_type_error(vm, &e)),
|
||||
};
|
||||
let value = match kind {
|
||||
ARRAY_ITER_KIND_KEYS => JsValue::int(index),
|
||||
ARRAY_ITER_KIND_ENTRIES => {
|
||||
let pair = create_new_array(vm, 2);
|
||||
let pair_ref = unsafe { &mut *pair };
|
||||
pair_ref.set_prop_at(0, JsValue::int(index));
|
||||
pair_ref.set_prop_at(1, element);
|
||||
JsValue::from_js_object(pair)
|
||||
}
|
||||
_ => element,
|
||||
};
|
||||
if let Err(msg) = vm.ordinary_set(iter, index_si, JsValue::int(index + 1), this_val, true) {
|
||||
return NativeResult::Err(crate::error::create_from_text(vm, &msg));
|
||||
}
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, value, false));
|
||||
}
|
||||
|
||||
let length_key = vm.new_string("length");
|
||||
let length_si = vm.property_key_si(length_key);
|
||||
let len_val = match vm.ordinary_get(target_obj, length_si, target) {
|
||||
Ok(v) => v,
|
||||
Err(err) => return NativeResult::Err(crate::error::create_from_text(vm, &err)),
|
||||
};
|
||||
let len_num = vm.coerce_number_bounded(len_val).unwrap_or(0.0);
|
||||
let len = if !len_num.is_finite() || len_num <= 0.0 { 0 } else { len_num as usize };
|
||||
|
||||
if (index as usize) >= len {
|
||||
vm.set_or_create_prop_value(iter, target_si, JsValue::undefined());
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
|
||||
let _ = target_obj.is_array();
|
||||
let element = arraylike_get_or_err!(vm, target.as_js_object_ptr(), index as usize);
|
||||
let value = match kind {
|
||||
ARRAY_ITER_KIND_KEYS => JsValue::int(index),
|
||||
ARRAY_ITER_KIND_ENTRIES => {
|
||||
let pair = create_new_array(vm, 2);
|
||||
let pair_ref = unsafe { &mut *pair };
|
||||
pair_ref.set_prop_at(0, JsValue::int(index));
|
||||
pair_ref.set_prop_at(1, element);
|
||||
JsValue::from_js_object(pair)
|
||||
}
|
||||
_ => element,
|
||||
};
|
||||
if let Err(msg) = vm.ordinary_set(iter, index_si, JsValue::int(index + 1), this_val, true) {
|
||||
return NativeResult::Err(crate::error::create_from_text(vm, &msg));
|
||||
}
|
||||
NativeResult::Ok(crate::iterator::make_iter_result(vm, value, false))
|
||||
}
|
||||
mod sort_iterator;
|
||||
pub use sort_iterator::*;
|
||||
|
||||
/// Array.prototype.toReversed():返回元素逆序的新数组,原数组不变。
|
||||
pub fn array_to_reversed<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||||
use oxide_types::object::JsObject;
|
||||
use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::builtins_debug;
|
||||
use crate::builtins_error;
|
||||
|
||||
use super::common::{
|
||||
array_ptr, array_type_error, arraylike_get, arraylike_get_or_err, create_new_array, get_this_array_ref,
|
||||
invoke_native_callback, require_callback,
|
||||
};
|
||||
|
||||
/// `Array.prototype.sort(compareFn)`:原地排序。默认按字符串字典序;
|
||||
/// 提供比较函数时按其返回值(<0/=0/>0)排序,回调抛错则中止。
|
||||
/// 对元素向量执行 Array.prototype.sort 的比较语义(原地)。
|
||||
/// 比较回调抛错时中止并把异常返回;默认按字符串字典序。
|
||||
pub(crate) fn sort_values_inner<H: VmHost>(
|
||||
vm: &mut H, vals: &mut [JsValue], comparator: Option<JsValue>,
|
||||
) -> Result<(), JsValue> {
|
||||
let mut sort_error = None;
|
||||
vals.sort_by(|a, b| {
|
||||
if sort_error.is_some() {
|
||||
return std::cmp::Ordering::Equal;
|
||||
}
|
||||
if let Some(callback) = comparator {
|
||||
match invoke_native_callback(vm, callback, JsValue::undefined(), &[*a, *b]) {
|
||||
NativeResult::Ok(result) => {
|
||||
let n = oxide_runtime_api::to_number(result);
|
||||
if n.is_nan() || n == 0.0 {
|
||||
std::cmp::Ordering::Equal
|
||||
} else if n < 0.0 {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
}
|
||||
NativeResult::Err(err) => {
|
||||
sort_error = Some(err);
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
NativeResult::TailCall { .. } => {
|
||||
sort_error = Some(crate::error::create_type_error(vm, "unexpected tail call in array callback"));
|
||||
std::cmp::Ordering::Equal
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let sa = oxide_runtime_api::to_string(*a);
|
||||
let sb = oxide_runtime_api::to_string(*b);
|
||||
sa.cmp(&sb)
|
||||
}
|
||||
});
|
||||
if let Some(err) = sort_error {
|
||||
return Err(err);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 解析 sort/toSorted 的比较回调参数(undefined 视为默认排序)。
|
||||
pub(crate) fn parse_sort_comparator<H: VmHost>(vm: &mut H, candidate: JsValue) -> Result<Option<JsValue>, JsValue> {
|
||||
if candidate.is_undefined() {
|
||||
return Ok(None);
|
||||
}
|
||||
match require_callback(vm, candidate) {
|
||||
Ok(callback) => Ok(Some(callback)),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_sort<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.sort called with {} args", args.len());
|
||||
let arr_ptr = array_ptr!(vm, args);
|
||||
let len = unsafe { (*arr_ptr).prop_count() as usize };
|
||||
let mut vals: Vec<JsValue> = (0..len).map(|i| unsafe { (*arr_ptr).get_prop_at(i) }).collect();
|
||||
let comparator = if args.len() > 1 {
|
||||
match parse_sort_comparator(vm, vm.reg(args[1])) {
|
||||
Ok(c) => c,
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Err(err) = sort_values_inner(vm, &mut vals, comparator) {
|
||||
builtins_error!("Array.prototype.sort: invalid receiver");
|
||||
return NativeResult::Err(err);
|
||||
}
|
||||
let arr = unsafe { &mut *arr_ptr };
|
||||
for (i, &v) in vals.iter().enumerate() {
|
||||
arr.set_prop_at(i, v);
|
||||
}
|
||||
NativeResult::Ok(vm.reg(args[0]))
|
||||
}
|
||||
|
||||
/// `Array.prototype.values()`:返回迭代数组元素的迭代器(%ArrayIteratorPrototype%)。
|
||||
pub fn array_values<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.values called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_VALUES) {
|
||||
Ok(iterator) => NativeResult::Ok(iterator),
|
||||
Err(err) => {
|
||||
builtins_error!("Array.prototype.values: invalid receiver");
|
||||
NativeResult::Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Array Iterator 的内部 kind 编码:0=values,1=keys,2=entries。
|
||||
/// TypedArray 迭代器复用同一编码与 %ArrayIteratorPrototype%(规范同族)。
|
||||
pub(crate) const ARRAY_ITER_KIND_VALUES: i32 = 0;
|
||||
pub(crate) const ARRAY_ITER_KIND_KEYS: i32 = 1;
|
||||
pub(crate) const ARRAY_ITER_KIND_ENTRIES: i32 = 2;
|
||||
|
||||
const ARRAY_ITER_TARGET_PROP: &str = "__target__";
|
||||
const ARRAY_ITER_INDEX_PROP: &str = "__index__";
|
||||
const ARRAY_ITER_KIND_PROP: &str = "__kind__";
|
||||
|
||||
/// 创建 Array/TA Iterator 对象:记录目标、当前下标与迭代种类,原型挂
|
||||
/// `%ArrayIteratorPrototype%`(链到 `%IteratorPrototype%`,Array 与 TA 共享)。
|
||||
/// `next` 不挂实例 own——由原型提供。
|
||||
pub(crate) fn make_array_iterator<H: VmHost>(vm: &mut H, this_val: JsValue, kind: i32) -> Result<JsValue, JsValue> {
|
||||
let target = match oxide_runtime_api::to_object(this_val, vm) {
|
||||
Ok(v) => v,
|
||||
Err(msg) => return Err(array_type_error(vm, &msg)),
|
||||
};
|
||||
let array_iter_proto = vm.session().builtin_world().array_iterator_proto.as_ptr() as *mut JsObject;
|
||||
let iter = vm.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(array_iter_proto)));
|
||||
let target_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_TARGET_PROP).0;
|
||||
let index_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_INDEX_PROP).0;
|
||||
let kind_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_KIND_PROP).0;
|
||||
let iter_ref = unsafe { &mut *iter };
|
||||
vm.set_or_create_prop_value(iter_ref, target_si, target);
|
||||
vm.set_or_create_prop_value(iter_ref, index_si, JsValue::int(0));
|
||||
vm.set_or_create_prop_value(iter_ref, kind_si, JsValue::int(kind));
|
||||
Ok(JsValue::from_js_object(iter))
|
||||
}
|
||||
|
||||
/// Array.prototype.entries():返回按索引产出 [index, value] 对的迭代器。
|
||||
pub fn array_entries<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.entries called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_ENTRIES) {
|
||||
Ok(iter) => NativeResult::Ok(iter),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Array.prototype.keys():返回按索引产出下标的迭代器。
|
||||
pub fn array_keys<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
builtins_debug!("Array.prototype.keys called with {} args", args.len());
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
match make_array_iterator(vm, this_val, ARRAY_ITER_KIND_KEYS) {
|
||||
Ok(iter) => NativeResult::Ok(iter),
|
||||
Err(err) => NativeResult::Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Array Iterator 的 next:读取目标当前下标处的值,按种类产出后推进下标。
|
||||
pub fn array_iterator_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||||
if !this_val.is_object() {
|
||||
return NativeResult::Err(array_type_error(vm, "Array Iterator next called on non-object"));
|
||||
}
|
||||
let iter = unsafe { &mut *this_val.as_js_object_ptr() };
|
||||
let target_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_TARGET_PROP).0;
|
||||
let index_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_INDEX_PROP).0;
|
||||
let kind_si = vm.kernel_core().perm_interner().intern(ARRAY_ITER_KIND_PROP).0;
|
||||
let target = match vm.ordinary_get(iter, target_si, this_val) {
|
||||
Ok(v) if v.is_undefined() => {
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
Ok(v) if v.is_object() => v,
|
||||
_ => return NativeResult::Err(array_type_error(vm, "Array Iterator has no iterated object")),
|
||||
};
|
||||
let index = vm
|
||||
.ordinary_get(iter, index_si, this_val)
|
||||
.ok()
|
||||
.and_then(|v| if v.is_int() { Some(v.as_int()) } else { None })
|
||||
.unwrap_or(0);
|
||||
let kind = vm
|
||||
.ordinary_get(iter, kind_si, this_val)
|
||||
.ok()
|
||||
.and_then(|v| if v.is_int() { Some(v.as_int()) } else { None })
|
||||
.unwrap_or(ARRAY_ITER_KIND_VALUES);
|
||||
|
||||
let target_obj = unsafe { &*target.as_js_object_ptr() };
|
||||
// TypedArray 目标走底层 buffer 读取(元素非普通属性,length 语义不同):
|
||||
// 与 Array 共享 %ArrayIteratorPrototype%,须在此分支区分两种取数路径。
|
||||
if target_obj.is_typed_array_obj() {
|
||||
let view = match crate::typed_array::get_typed_array_data(vm, target) {
|
||||
Ok(view) => view,
|
||||
Err(err) => return NativeResult::Err(err),
|
||||
};
|
||||
if (index as usize) >= view.length {
|
||||
vm.set_or_create_prop_value(iter, target_si, JsValue::undefined());
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
let element = match crate::typed_array::typed_array_element_get(vm, target_obj, index as u32) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return NativeResult::Err(crate::error::create_type_error(vm, &e)),
|
||||
};
|
||||
let value = match kind {
|
||||
ARRAY_ITER_KIND_KEYS => JsValue::int(index),
|
||||
ARRAY_ITER_KIND_ENTRIES => {
|
||||
let pair = create_new_array(vm, 2);
|
||||
let pair_ref = unsafe { &mut *pair };
|
||||
pair_ref.set_prop_at(0, JsValue::int(index));
|
||||
pair_ref.set_prop_at(1, element);
|
||||
JsValue::from_js_object(pair)
|
||||
}
|
||||
_ => element,
|
||||
};
|
||||
if let Err(msg) = vm.ordinary_set(iter, index_si, JsValue::int(index + 1), this_val, true) {
|
||||
return NativeResult::Err(crate::error::create_from_text(vm, &msg));
|
||||
}
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, value, false));
|
||||
}
|
||||
|
||||
let length_key = vm.new_string("length");
|
||||
let length_si = vm.property_key_si(length_key);
|
||||
let len_val = match vm.ordinary_get(target_obj, length_si, target) {
|
||||
Ok(v) => v,
|
||||
Err(err) => return NativeResult::Err(crate::error::create_from_text(vm, &err)),
|
||||
};
|
||||
let len_num = vm.coerce_number_bounded(len_val).unwrap_or(0.0);
|
||||
let len = if !len_num.is_finite() || len_num <= 0.0 { 0 } else { len_num as usize };
|
||||
|
||||
if (index as usize) >= len {
|
||||
vm.set_or_create_prop_value(iter, target_si, JsValue::undefined());
|
||||
return NativeResult::Ok(crate::iterator::make_iter_result(vm, JsValue::undefined(), true));
|
||||
}
|
||||
|
||||
let _ = target_obj.is_array();
|
||||
let element = arraylike_get_or_err!(vm, target.as_js_object_ptr(), index as usize);
|
||||
let value = match kind {
|
||||
ARRAY_ITER_KIND_KEYS => JsValue::int(index),
|
||||
ARRAY_ITER_KIND_ENTRIES => {
|
||||
let pair = create_new_array(vm, 2);
|
||||
let pair_ref = unsafe { &mut *pair };
|
||||
pair_ref.set_prop_at(0, JsValue::int(index));
|
||||
pair_ref.set_prop_at(1, element);
|
||||
JsValue::from_js_object(pair)
|
||||
}
|
||||
_ => element,
|
||||
};
|
||||
if let Err(msg) = vm.ordinary_set(iter, index_si, JsValue::int(index + 1), this_val, true) {
|
||||
return NativeResult::Err(crate::error::create_from_text(vm, &msg));
|
||||
}
|
||||
NativeResult::Ok(crate::iterator::make_iter_result(vm, value, false))
|
||||
}
|
||||
Reference in New Issue
Block a user