mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 02:31:13 +08:00
415 lines
19 KiB
Rust
415 lines
19 KiB
Rust
//! AsyncFromSyncIterator:把同步迭代器包装为异步迭代器,供 for-await-of 回退消费。
|
||
//!
|
||
//! GetAsyncIterator 对没有 `@@asyncIterator` 的普通可迭代对象(数组/字符串等)
|
||
//! 走同步迭代协议取迭代器,再包一层 AsyncFromSyncIterator:其 `next`/`return`/`throw`
|
||
//! 转发内层同步迭代器并把结果包成 Promise(非对象结果按 TypeError 拒绝),
|
||
//! `@@asyncIterator` 返回自身。
|
||
|
||
use oxide_builtins::iterator::make_iter_result;
|
||
use oxide_kernel::shape_forge::EMPTY_SHAPE_ID;
|
||
use oxide_runtime_api::NativeResult;
|
||
use oxide_types::object::{JsObject, NativeFnPtr};
|
||
use oxide_types::private_key::encode_symbol_key;
|
||
use oxide_types::value::JsValue;
|
||
|
||
use crate::vm::Vm;
|
||
|
||
/// AsyncFromSyncIterator 对象上存内层同步迭代器的属性名。
|
||
const INNER_PROP: &str = "__inner__";
|
||
/// `@@asyncIterator` 的 well-known symbol 键序号。
|
||
const ASYNC_ITERATOR_SYMBOL_ID: u32 = 8;
|
||
|
||
/// GetAsyncIterator(ECMA-262):取 `value[@@asyncIterator]`,可调用则调用;
|
||
/// undefined/null 时回退同步迭代器并包 AsyncFromSyncIterator;
|
||
/// 已定义但不可调用时抛 TypeError。
|
||
///
|
||
/// # 步骤
|
||
/// 1. ToObject 后读取 `@@asyncIterator`,可调用则调用并校验结果为对象。
|
||
/// 2. 已定义但不可调用时抛 TypeError(GetMethod 步 4)。
|
||
/// 3. undefined/null 时经同步迭代协议取迭代器包装器,包成 AsyncFromSyncIterator。
|
||
///
|
||
/// # 返回值
|
||
/// - `Ok(iterator)`:异步迭代器对象;
|
||
/// - `Err`:`@@asyncIterator` getter/调用抛错或 ToObject 失败(透传原异常值),
|
||
/// 或已定义但不可调用(构造 TypeError)。
|
||
pub(crate) fn make_async_iterator(vm: &mut Vm, value: JsValue) -> Result<JsValue, JsValue> {
|
||
let obj_value = if value.is_object() {
|
||
value
|
||
} else {
|
||
match oxide_runtime_api::to_object(value, vm) {
|
||
Ok(o) => o,
|
||
Err(e) => return Err(oxide_builtins::error::create_type_error(vm, &e)),
|
||
}
|
||
};
|
||
let obj = unsafe { &*obj_value.as_js_object_ptr() };
|
||
let aiter_key = encode_symbol_key(vm.realm_id(), ASYNC_ITERATOR_SYMBOL_ID);
|
||
let method = match vm.ordinary_get(obj, aiter_key, obj_value) {
|
||
Ok(m) => m,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_type_error(vm, &e));
|
||
return Err(exc);
|
||
}
|
||
};
|
||
if oxide_builtins::iterator::is_callable(method) {
|
||
let iterator = match vm.call_function_sync(method, obj_value, &[]) {
|
||
Ok(it) => it,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_type_error(vm, &e));
|
||
return Err(exc);
|
||
}
|
||
};
|
||
if !iterator.is_object() {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
vm,
|
||
"Result of the Symbol.asyncIterator method is not an object",
|
||
));
|
||
}
|
||
return Ok(iterator);
|
||
}
|
||
if !method.is_null() && !method.is_undefined() {
|
||
// GetMethod 步 4:已定义非可调用方法 → TypeError,不落入同步回退。
|
||
return Err(oxide_builtins::error::create_type_error(vm, "value is not async iterable"));
|
||
}
|
||
let sync = oxide_builtins::iterator::make_iterator_for_value(vm, value)?;
|
||
Ok(vm.create_async_from_sync_iterator(sync))
|
||
}
|
||
|
||
impl Vm {
|
||
/// 创建 AsyncFromSyncIterator 包装器:挂内层同步迭代器,装 next/return/throw 与
|
||
/// `@@asyncIterator`(返回自身)方法。
|
||
pub(crate) fn create_async_from_sync_iterator(&mut self, sync_iter: JsValue) -> JsValue {
|
||
let next_fn = make_wrapper_fn(self, async_from_sync_next as *const ());
|
||
let return_fn = make_wrapper_fn(self, async_from_sync_return as *const ());
|
||
let throw_fn = make_wrapper_fn(self, async_from_sync_throw as *const ());
|
||
let self_fn = make_wrapper_fn(self, async_from_sync_symbol_async_iterator as *const ());
|
||
let object_proto = self.realm.session.borrow().builtin_world().object_proto.as_ptr() as *mut JsObject;
|
||
let ptr = self.alloc_object(JsObject::new_empty(EMPTY_SHAPE_ID, JsValue::from_js_object(object_proto)));
|
||
let obj = unsafe { &mut *ptr };
|
||
let inner_si = self.kernel_core.perm_interner().intern(INNER_PROP).0;
|
||
self.set_or_create_prop_value(obj, inner_si, sync_iter);
|
||
let next_si = self.kernel_core.perm_interner().intern("next").0;
|
||
self.set_or_create_prop_value(obj, next_si, next_fn);
|
||
let return_si = self.kernel_core.perm_interner().intern("return").0;
|
||
self.set_or_create_prop_value(obj, return_si, return_fn);
|
||
let throw_si = self.kernel_core.perm_interner().intern("throw").0;
|
||
self.set_or_create_prop_value(obj, throw_si, throw_fn);
|
||
let aiter_key = encode_symbol_key(self.realm_id(), ASYNC_ITERATOR_SYMBOL_ID);
|
||
self.set_or_create_prop_value(obj, aiter_key, self_fn);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
}
|
||
|
||
/// 构造包装器方法 native 函数对象(name/length 属性由 `add_fn_name_length` 补全)。
|
||
fn make_wrapper_fn(vm: &mut Vm, native_fn: *const ()) -> JsValue {
|
||
let fn_proto = vm.realm.session.borrow().builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: native_fn 来自 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(native_fn) }));
|
||
func.set_native_arg_count(1);
|
||
let ptr = vm.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
vm.add_fn_name_length(obj, "", 1);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// 读取包装器对象上的内层同步迭代器;接收者非法或内层缺失时返回 TypeError。
|
||
fn sync_inner(vm: &mut Vm, this_val: JsValue) -> Result<JsValue, JsValue> {
|
||
if !this_val.is_object() {
|
||
return Err(oxide_builtins::error::create_type_error(
|
||
vm,
|
||
"AsyncFromSyncIterator methods called on non-object",
|
||
));
|
||
}
|
||
let obj = unsafe { &*this_val.as_js_object_ptr() };
|
||
let inner_si = vm.kernel_core.perm_interner().intern(INNER_PROP).0;
|
||
match vm.ordinary_get(obj, inner_si, this_val) {
|
||
Ok(inner) if !inner.is_undefined() => Ok(inner),
|
||
_ => Err(oxide_builtins::error::create_type_error(vm, "AsyncFromSyncIterator has no sync iterator")),
|
||
}
|
||
}
|
||
|
||
/// AsyncFromSyncIteratorContinuation 的 unwrap 函数闭包上存目标 resolve 的属性名。
|
||
const ASFS_RESOLVE_PROP: &str = "__oxide_asfs_resolve__";
|
||
/// unwrap 函数闭包上存 done 标志的属性名。
|
||
const ASFS_DONE_PROP: &str = "__oxide_asfs_done__";
|
||
/// reject-close 闭包上存目标 reject 的属性名。
|
||
const ASFS_REJECT_PROP: &str = "__oxide_asfs_reject__";
|
||
/// reject-close 闭包上存内层同步迭代器的属性名。
|
||
const ASFS_INNER_PROP: &str = "__oxide_asfs_inner__";
|
||
|
||
/// AsyncFromSyncIteratorContinuation:解出同步迭代器结果对象的 done/value,
|
||
/// value 经 PromiseResolve 后 await,最终以 `{value: 解开值, done}` 结算能力。
|
||
/// 任一步骤抛错(done/value getter、PromiseResolve 的 constructor getter)都拒绝;
|
||
/// `close_on_rejection` 时 valueWrapper 拒绝还会先关闭内层同步迭代器。
|
||
///
|
||
/// # 参数
|
||
/// - `inner`:内层同步迭代器(关闭目标)。
|
||
/// - `result`:内层同步方法调用结果(`Err` 为调用抛出的字符串展平文本)。
|
||
fn continue_async_from_sync(
|
||
vm: &mut Vm, inner: JsValue, result: Result<JsValue, String>, close_on_rejection: bool,
|
||
) -> NativeResult {
|
||
let (promise, resolve, reject) = vm.new_promise_capability();
|
||
let reject_with = |vm: &mut Vm, exc: JsValue| {
|
||
if close_on_rejection {
|
||
close_sync_iterator(vm, inner);
|
||
}
|
||
let _ = vm.reject_promise(promise, exc);
|
||
};
|
||
match result {
|
||
Ok(r) if r.is_object() => {
|
||
let result_obj = unsafe { &*r.as_js_object_ptr() };
|
||
let done_si = vm.kernel_core.perm_interner().intern("done").0;
|
||
let done = match vm.ordinary_get(result_obj, done_si, r) {
|
||
Ok(d) => oxide_runtime_api::to_boolean(d),
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
reject_with(vm, exc);
|
||
return NativeResult::Ok(promise);
|
||
}
|
||
};
|
||
let value_si = vm.kernel_core.perm_interner().intern("value").0;
|
||
let value = match vm.ordinary_get(result_obj, value_si, r) {
|
||
Ok(v) => v,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
reject_with(vm, exc);
|
||
return NativeResult::Ok(promise);
|
||
}
|
||
};
|
||
let value_wrapper = match vm.promise_resolve(value) {
|
||
Ok(w) => w,
|
||
Err(e) => {
|
||
reject_with(vm, e);
|
||
return NativeResult::Ok(promise);
|
||
}
|
||
};
|
||
let fulfill = make_unwrap_fn(vm, resolve, done);
|
||
let on_rejected = if close_on_rejection {
|
||
make_reject_close_fn(vm, reject, inner)
|
||
} else {
|
||
reject
|
||
};
|
||
let _ = vm.perform_promise_then(value_wrapper, fulfill, on_rejected);
|
||
NativeResult::Ok(promise)
|
||
}
|
||
Ok(_) => {
|
||
let err = oxide_builtins::error::create_type_error(vm, "sync iterator result is not an object");
|
||
reject_with(vm, err);
|
||
NativeResult::Ok(promise)
|
||
}
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
reject_with(vm, exc);
|
||
NativeResult::Ok(promise)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 同步关闭内层迭代器(IteratorClose 的 return 调用),忽略 return 自身抛错。
|
||
fn close_sync_iterator(vm: &mut Vm, inner: JsValue) {
|
||
if !inner.is_object() {
|
||
return;
|
||
}
|
||
let inner_obj = unsafe { &*inner.as_js_object_ptr() };
|
||
let return_si = vm.kernel_core.perm_interner().intern("return").0;
|
||
let return_fn = match vm.ordinary_get(inner_obj, return_si, inner) {
|
||
Ok(f) => f,
|
||
Err(_) => return,
|
||
};
|
||
if oxide_builtins::iterator::is_callable(return_fn) {
|
||
// return() 的抛错被忽略,其值不得外泄进槽覆盖在途异常。
|
||
let saved_uncaught = vm.last_uncaught_value.take();
|
||
let _ = vm.call_function_sync(return_fn, inner, &[]);
|
||
vm.last_uncaught_value = saved_uncaught;
|
||
}
|
||
}
|
||
|
||
/// 构造 valueWrapper 拒绝时关闭迭代器的闭包:携带目标 reject 与内层同步迭代器。
|
||
fn make_reject_close_fn(vm: &mut Vm, reject: JsValue, inner: JsValue) -> JsValue {
|
||
let fn_proto = vm.realm.session.borrow().builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: async_from_sync_reject_close 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_from_sync_reject_close as *const ()) }));
|
||
func.set_native_arg_count(1);
|
||
let ptr = vm.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
let rej_si = vm.kernel_core.perm_interner().intern(ASFS_REJECT_PROP).0;
|
||
vm.set_or_create_prop_value(obj, rej_si, reject);
|
||
let inner_si = vm.kernel_core.perm_interner().intern(ASFS_INNER_PROP).0;
|
||
vm.set_or_create_prop_value(obj, inner_si, inner);
|
||
vm.add_fn_name_length(obj, "", 1);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// reject-close 闭包:关闭内层同步迭代器后以原拒绝原因结算能力。
|
||
fn async_from_sync_reject_close(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let callee = vm.reg(254);
|
||
if !callee.is_object() {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "reject handler is invalid"));
|
||
}
|
||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let rej_si = vm.kernel_core.perm_interner().intern(ASFS_REJECT_PROP).0;
|
||
let reject = vm.resolve_property(callee_obj, rej_si).unwrap_or(JsValue::undefined());
|
||
let inner_si = vm.kernel_core.perm_interner().intern(ASFS_INNER_PROP).0;
|
||
let inner = vm.resolve_property(callee_obj, inner_si).unwrap_or(JsValue::undefined());
|
||
let error = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
close_sync_iterator(vm, inner);
|
||
let _ = vm.call_function_sync(reject, JsValue::undefined(), &[error]);
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// 构造 AsyncFromSyncIteratorContinuation 的 value unwrap 闭包:携带目标 resolve 与
|
||
/// done 标志,valueWrapper settle 后把解开值包成 `{value, done}` 结算。
|
||
fn make_unwrap_fn(vm: &mut Vm, resolve: JsValue, done: bool) -> JsValue {
|
||
let fn_proto = vm.realm.session.borrow().builtin_world().fn_proto_val();
|
||
let mut func = JsObject::new_empty(EMPTY_SHAPE_ID, fn_proto);
|
||
func.set_function(true);
|
||
// SAFETY: async_from_sync_unwrap 是 NativeFn 函数项。
|
||
func.set_native_fn(Some(unsafe { NativeFnPtr::from_raw(async_from_sync_unwrap as *const ()) }));
|
||
func.set_native_arg_count(1);
|
||
let ptr = vm.alloc_object(func);
|
||
let obj = unsafe { &mut *ptr };
|
||
let res_si = vm.kernel_core.perm_interner().intern(ASFS_RESOLVE_PROP).0;
|
||
vm.set_or_create_prop_value(obj, res_si, resolve);
|
||
let done_si = vm.kernel_core.perm_interner().intern(ASFS_DONE_PROP).0;
|
||
vm.set_or_create_prop_value(obj, done_si, JsValue::bool(done));
|
||
vm.add_fn_name_length(obj, "", 1);
|
||
JsValue::from_js_object(ptr)
|
||
}
|
||
|
||
/// value unwrap 闭包:读自身 prop 的 resolve 与 done,把入参包装为迭代器结果结算。
|
||
fn async_from_sync_unwrap(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let callee = vm.reg(254);
|
||
if !callee.is_object() {
|
||
return NativeResult::Err(oxide_builtins::error::create_type_error(vm, "unwrap handler is invalid"));
|
||
}
|
||
let callee_obj = unsafe { &*callee.as_js_object_ptr() };
|
||
let res_si = vm.kernel_core.perm_interner().intern(ASFS_RESOLVE_PROP).0;
|
||
let resolve = vm.resolve_property(callee_obj, res_si).unwrap_or(JsValue::undefined());
|
||
let done_si = vm.kernel_core.perm_interner().intern(ASFS_DONE_PROP).0;
|
||
let done = vm
|
||
.resolve_property(callee_obj, done_si)
|
||
.is_some_and(oxide_runtime_api::to_boolean);
|
||
let value = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let result = make_iter_result(vm, value, done);
|
||
let _ = vm.call_function_sync(resolve, JsValue::undefined(), &[result]);
|
||
NativeResult::Ok(JsValue::undefined())
|
||
}
|
||
|
||
/// `AsyncFromSyncIterator.next(value)`:转发内层 `next`,结果经 continuation 结算。
|
||
/// 未传实参时不向 `next` 传参(与 IteratorNext 的空实参调用一致)。
|
||
fn async_from_sync_next(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let inner = match sync_inner(vm, this_val) {
|
||
Ok(i) => i,
|
||
Err(e) => return NativeResult::Err(e),
|
||
};
|
||
let next_si = vm.kernel_core.perm_interner().intern("next").0;
|
||
let next_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, next_si, inner) {
|
||
Ok(f) => f,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
let result = if args.len() > 1 {
|
||
vm.call_function_sync(next_fn, inner, &[vm.reg(args[1])])
|
||
} else {
|
||
vm.call_function_sync(next_fn, inner, &[])
|
||
};
|
||
continue_async_from_sync(vm, inner, result, true)
|
||
}
|
||
|
||
/// `AsyncFromSyncIterator.return(value)`:内层无 `return` 时直接以 `{value, done:true}`
|
||
/// 完成,否则转发并经 continuation 结算。
|
||
fn async_from_sync_return(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let inner = match sync_inner(vm, this_val) {
|
||
Ok(i) => i,
|
||
Err(e) => return NativeResult::Err(e),
|
||
};
|
||
let return_si = vm.kernel_core.perm_interner().intern("return").0;
|
||
let return_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, return_si, inner) {
|
||
Ok(f) => f,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
if !oxide_builtins::iterator::is_callable(return_fn) {
|
||
let result = make_iter_result(vm, arg, true);
|
||
let (promise, _, _) = vm.new_promise_capability();
|
||
let _ = vm.resolve_promise(promise, result);
|
||
return NativeResult::Ok(promise);
|
||
}
|
||
let result = if args.len() > 1 {
|
||
vm.call_function_sync(return_fn, inner, &[arg])
|
||
} else {
|
||
vm.call_function_sync(return_fn, inner, &[])
|
||
};
|
||
continue_async_from_sync(vm, inner, result, false)
|
||
}
|
||
|
||
/// `AsyncFromSyncIterator.throw(value)`:内层无 `throw` 时拒绝,否则转发并经 continuation 结算。
|
||
fn async_from_sync_throw(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
let arg = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||
let inner = match sync_inner(vm, this_val) {
|
||
Ok(i) => i,
|
||
Err(e) => return NativeResult::Err(e),
|
||
};
|
||
let throw_si = vm.kernel_core.perm_interner().intern("throw").0;
|
||
let throw_fn = match vm.ordinary_get(unsafe { &*inner.as_js_object_ptr() }, throw_si, inner) {
|
||
Ok(f) => f,
|
||
Err(e) => {
|
||
let exc = vm
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(vm, &e));
|
||
return NativeResult::Err(exc);
|
||
}
|
||
};
|
||
if !oxide_builtins::iterator::is_callable(throw_fn) {
|
||
let (promise, _, _reject) = vm.new_promise_capability();
|
||
let err = oxide_builtins::error::create_type_error(vm, "sync iterator has no throw method");
|
||
let _ = vm.reject_promise(promise, err);
|
||
return NativeResult::Ok(promise);
|
||
}
|
||
let result = if args.len() > 1 {
|
||
vm.call_function_sync(throw_fn, inner, &[arg])
|
||
} else {
|
||
vm.call_function_sync(throw_fn, inner, &[])
|
||
};
|
||
continue_async_from_sync(vm, inner, result, false)
|
||
}
|
||
|
||
/// `AsyncFromSyncIterator[@@asyncIterator]`:返回自身。
|
||
fn async_from_sync_symbol_async_iterator(vm: &mut Vm, args: &[u8]) -> NativeResult {
|
||
let this_val = vm.reg(if args.is_empty() { 0 } else { args[0] });
|
||
NativeResult::Ok(this_val)
|
||
}
|