extern crate alloc;
use alloc::boxed::Box;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::ffi::c_char;
use core::ptr;
use crate::value::{CheapClone, PropertyKey};
use crate::{JsError, JsString, JsValue, OrderId, OrderResponse, RuntimeValue};
use super::{
TsRunContext, TsRunOrderResponse, TsRunResult, TsRunValue, TsRunValueResult, c_str_to_str,
};
#[unsafe(no_mangle)]
pub extern "C" fn tsrun_fulfill_orders(
ctx: *mut TsRunContext,
responses: *const TsRunOrderResponse,
count: usize,
) -> TsRunResult {
let ctx = match unsafe { ctx.as_mut() } {
Some(c) => c,
None => {
return TsRunResult {
ok: false,
error: c"NULL context".as_ptr(),
};
}
};
if responses.is_null() && count > 0 {
return TsRunResult::err(ctx, "NULL responses array".to_string());
}
let rust_responses: Vec<OrderResponse> = (0..count)
.map(|i| unsafe {
let resp = &*responses.add(i);
let result = if resp.error.is_null() {
if let Some(val) = resp.value.as_ref() {
Ok(RuntimeValue::unguarded(val.value().clone()))
} else {
Ok(RuntimeValue::unguarded(JsValue::Undefined))
}
} else {
let error_str = c_str_to_str(resp.error).unwrap_or("Unknown error");
Err(JsError::type_error(error_str))
};
OrderResponse {
id: OrderId(resp.id),
result,
}
})
.collect();
ctx.interp.fulfill_orders(rust_responses);
TsRunResult::success()
}
#[unsafe(no_mangle)]
pub extern "C" fn tsrun_create_pending_order(
ctx: *mut TsRunContext,
payload: *mut TsRunValue,
order_id_out: *mut u64,
) -> TsRunValueResult {
let ctx = match unsafe { ctx.as_mut() } {
Some(c) => c,
None => {
return TsRunValueResult {
value: ptr::null_mut(),
error: c"NULL context".as_ptr(),
};
}
};
let payload_value = match unsafe { payload.as_ref() } {
Some(v) => v.value().clone(),
None => JsValue::Undefined,
};
let id = crate::OrderId(ctx.interp.next_order_id);
ctx.interp.next_order_id += 1;
if !order_id_out.is_null() {
unsafe { *order_id_out = id.0 };
}
let payload_rv = if let JsValue::Object(ref obj) = payload_value {
let payload_guard = ctx.interp.heap.create_guard();
payload_guard.guard(obj.clone());
RuntimeValue::with_guard(payload_value.clone(), payload_guard)
} else {
RuntimeValue::unguarded(payload_value)
};
ctx.interp.pending_orders.push(crate::Order {
id,
payload: payload_rv,
});
let marker_guard = ctx.interp.heap.create_guard();
let marker = marker_guard.alloc();
marker.borrow_mut().exotic = crate::value::ExoticObject::PendingOrder { id: id.0 };
TsRunValueResult::ok(Box::new(TsRunValue {
inner: RuntimeValue::with_guard(JsValue::Object(marker), marker_guard),
}))
}
#[unsafe(no_mangle)]
pub extern "C" fn tsrun_create_order_promise(
ctx: *mut TsRunContext,
order_id: u64,
) -> TsRunValueResult {
let ctx = match unsafe { ctx.as_mut() } {
Some(c) => c,
None => {
return TsRunValueResult {
value: ptr::null_mut(),
error: c"NULL context".as_ptr(),
};
}
};
let promise = crate::api::create_order_promise(&mut ctx.interp, OrderId(order_id));
TsRunValueResult::ok(TsRunValue::from_runtime_value(promise))
}
#[unsafe(no_mangle)]
pub extern "C" fn tsrun_resolve_promise(
ctx: *mut TsRunContext,
promise: *mut TsRunValue,
value: *mut TsRunValue,
) -> TsRunResult {
let ctx = match unsafe { ctx.as_mut() } {
Some(c) => c,
None => {
return TsRunResult {
ok: false,
error: c"NULL context".as_ptr(),
};
}
};
let promise_val = match unsafe { promise.as_ref() } {
Some(v) => v,
None => return TsRunResult::err(ctx, "NULL promise".to_string()),
};
let value_val = match unsafe { value.as_ref() } {
Some(v) => RuntimeValue::unguarded(v.value().clone()),
None => RuntimeValue::unguarded(JsValue::Undefined),
};
let promise_rv = RuntimeValue::unguarded(promise_val.value().clone());
match crate::api::resolve_promise(&mut ctx.interp, &promise_rv, value_val) {
Ok(()) => TsRunResult::success(),
Err(e) => TsRunResult::err(ctx, e.to_string()),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn tsrun_reject_promise(
ctx: *mut TsRunContext,
promise: *mut TsRunValue,
error: *const c_char,
) -> TsRunResult {
let ctx = match unsafe { ctx.as_mut() } {
Some(c) => c,
None => {
return TsRunResult {
ok: false,
error: c"NULL context".as_ptr(),
};
}
};
let promise_val = match unsafe { promise.as_ref() } {
Some(v) => v,
None => return TsRunResult::err(ctx, "NULL promise".to_string()),
};
let error_str = unsafe { c_str_to_str(error) }.unwrap_or("Unknown error");
let guard = ctx.interp.heap.create_guard();
let error_obj = guard.alloc();
{
let mut obj_ref = error_obj.borrow_mut();
obj_ref.prototype = Some(ctx.interp.error_prototype.cheap_clone());
obj_ref.set_property(
PropertyKey::String(JsString::from("message")),
JsValue::String(JsString::from(error_str)),
);
obj_ref.set_property(
PropertyKey::String(JsString::from("name")),
JsValue::String(JsString::from("Error")),
);
}
let error_rv = RuntimeValue::with_guard(JsValue::Object(error_obj), guard);
let promise_rv = RuntimeValue::unguarded(promise_val.value().clone());
match crate::api::reject_promise(&mut ctx.interp, &promise_rv, error_rv) {
Ok(()) => TsRunResult::success(),
Err(e) => TsRunResult::err(ctx, e.to_string()),
}
}