pub use emlite;
pub use emlite::Console;
pub use emlite::FromVal;
use alloc::{format, vec};
pub use crate::any::{Any, AnyHandle};
pub use crate::array::{
Array, ArrayBuffer, DataView, Endian, Float32Array, Float64Array, FrozenArray, Int8Array,
Int32Array, ObservableArray, TypedArray, Uint8Array, Uint32Array,
};
pub use crate::bigint::BigInt;
pub use crate::date::Date;
pub use crate::error::*;
pub use crate::function::{Closure, Function};
pub use crate::json::JSON;
pub use crate::map::*;
pub use crate::math::Math;
pub use crate::null::Null;
pub use crate::number::Number;
pub use crate::object::Object;
pub use crate::promise::Promise;
pub use crate::record::Record;
pub use crate::reflect::Reflect;
pub use crate::regexp::{RegExp, RegExpFlags};
pub use crate::response::{fetch, fetch_val};
pub use crate::set::*;
pub use crate::string::JsString;
pub use crate::symbol::Symbol;
pub use crate::text::{TextDecoder, TextEncoder};
pub use crate::time::*;
pub use crate::undefined::Undefined;
pub use crate::url::URL;
pub fn parse_int(src: &str, radix: Option<i32>) -> Result<i32, JsError> {
let g = emlite::Val::global("parseInt");
let result = match radix {
Some(r) => {
if !(2..=36).contains(&r) {
return Err(JsError::new("Radix must be between 2 and 36"));
}
g.invoke(&[src.into(), r.into()])
}
None => g.invoke(&[src.into()]),
};
if is_nan(&result) {
Err(JsError::new(&format!("Invalid number format: '{}'", src)))
} else {
Ok(result.as_::<i32>())
}
}
pub fn parse_float(src: &str) -> Result<f64, JsError> {
let result = emlite::Val::global("parseFloat").invoke(&[src.into()]);
if is_nan(&result) {
Err(JsError::new(&format!("Invalid number format: '{}'", src)))
} else {
Ok(result.as_::<f64>())
}
}
pub trait DynCast
where
Self: AsRef<emlite::Val> + Into<emlite::Val> + AsMut<emlite::Val>,
{
fn has_type<T>(&self) -> bool
where
T: DynCast,
{
T::is_type_of(self.as_ref())
}
fn dyn_into<T>(self) -> Result<T, Self>
where
T: DynCast,
{
if self.has_type::<T>() {
Ok(self.unchecked_into())
} else {
Err(self)
}
}
fn dyn_ref<T>(&self) -> Option<&T>
where
T: DynCast,
{
if self.has_type::<T>() {
Some(self.unchecked_ref())
} else {
None
}
}
fn dyn_mut<T>(&mut self) -> Option<&mut T>
where
T: DynCast,
{
if self.has_type::<T>() {
Some(self.unchecked_mut())
} else {
None
}
}
fn unchecked_into<T>(self) -> T
where
T: DynCast,
{
T::unchecked_from_val(self.into())
}
fn unchecked_ref<T>(&self) -> &T
where
T: DynCast,
{
T::unchecked_from_val_ref(self.as_ref())
}
fn unchecked_mut<T>(&mut self) -> &mut T
where
T: DynCast,
{
T::unchecked_from_val_mut(self.as_mut())
}
fn is_instance_of<T>(&self) -> bool
where
T: DynCast,
{
T::instanceof(self.as_ref())
}
fn instanceof(val: &emlite::Val) -> bool;
fn is_type_of(val: &emlite::Val) -> bool {
Self::instanceof(val)
}
fn unchecked_from_val(v: emlite::Val) -> Self;
fn unchecked_from_val_ref(v: &emlite::Val) -> &Self;
fn unchecked_from_val_mut(v: &mut emlite::Val) -> &mut Self;
}
#[cold]
#[inline(never)]
pub fn throw_str(s: &str) -> ! {
throw_val(s.into())
}
#[cold]
#[inline(never)]
pub fn throw_val(s: Any) -> ! {
let handle = s.as_handle();
core::mem::forget(s);
emlite::Val::throw(emlite::Val::take_ownership(handle));
}
pub trait UnwrapThrowExt<T>: Sized {
fn unwrap_throw(self) -> T {
let loc = core::panic::Location::caller();
let msg = alloc::format!(
"called `{}::unwrap_throw()` ({}:{}:{})",
core::any::type_name::<Self>(),
loc.file(),
loc.line(),
loc.column()
);
self.expect_throw(&msg)
}
fn expect_throw(self, message: &str) -> T;
}
impl<T> UnwrapThrowExt<T> for Option<T> {
fn unwrap_throw(self) -> T {
const MSG: &str = "called `Option::unwrap_throw()` on a `None` value";
if let Some(val) = self {
val
} else if cfg!(debug_assertions) {
let loc = core::panic::Location::caller();
let msg = alloc::format!("{} ({}:{}:{})", MSG, loc.file(), loc.line(), loc.column(),);
throw_str(&msg)
} else {
throw_str(MSG)
}
}
fn expect_throw(self, message: &str) -> T {
if let Some(val) = self {
val
} else if cfg!(debug_assertions) {
let loc = core::panic::Location::caller();
let msg = alloc::format!(
"{} ({}:{}:{})",
message,
loc.file(),
loc.line(),
loc.column(),
);
throw_str(&msg)
} else {
throw_str(message)
}
}
}
impl<T, E> UnwrapThrowExt<T> for Result<T, E>
where
E: core::fmt::Debug,
{
fn unwrap_throw(self) -> T {
const MSG: &str = "called `Result::unwrap_throw()` on an `Err` value";
match self {
Ok(val) => val,
Err(err) => {
if cfg!(debug_assertions) {
let loc = core::panic::Location::caller();
let msg = alloc::format!(
"{} ({}:{}:{}): {:?}",
MSG,
loc.file(),
loc.line(),
loc.column(),
err
);
throw_str(&msg)
} else {
throw_str(MSG)
}
}
}
}
fn expect_throw(self, message: &str) -> T {
match self {
Ok(val) => val,
Err(err) => {
if cfg!(debug_assertions) {
let loc = core::panic::Location::caller();
let msg = alloc::format!(
"{} ({}:{}:{}): {:?}",
message,
loc.file(),
loc.line(),
loc.column(),
err
);
throw_str(&msg)
} else {
throw_str(message)
}
}
}
}
}
pub fn btoa(data: &JsString) -> Result<JsString, JsError> {
let result = emlite::Val::global("btoa").invoke(&[data.into()]);
result.as_::<Result<JsString, JsError>>()
}
pub fn atob(encoded: &JsString) -> Result<JsString, JsError> {
let result = emlite::Val::global("atob").invoke(&[encoded.into()]);
result.as_::<Result<JsString, JsError>>()
}
pub fn is_nan<V: Into<emlite::Val>>(value: V) -> bool {
emlite::Val::global("isNaN")
.invoke(&[value.into()])
.as_::<bool>()
}
pub fn queue_microtask<C: Into<emlite::Val>>(callback: C) {
emlite::Val::global("queueMicrotask").invoke(&[callback.into()]);
}
pub fn import_module(specifier: &str) -> Promise<Result<Object, JsError>> {
let import_promise = emlite::Val::global("import").invoke(&[specifier.into()]);
Promise::take_ownership(import_promise.as_handle())
}
pub fn require_module(specifier: &str) -> Result<Object, JsError> {
let require_fn = emlite::Val::global("require");
if require_fn.is_undefined() {
return Err(JsError::new("require is not available in this environment"));
}
let module_exports = require_fn.invoke(&[specifier.into()]);
Ok(Object::from_val(&module_exports.as_::<Any>()))
}
pub fn create_require<V: Into<emlite::Val>>(import_meta_url: V) -> Result<Function, JsError> {
let module_obj = emlite::Val::global("module");
if module_obj.is_undefined() {
return Err(JsError::new(
"module.createRequire not supported in this environment",
));
}
let create_require_fn = module_obj.get("createRequire");
if create_require_fn.is_undefined() {
return Err(JsError::new("module.createRequire not available"));
}
let require_fn = create_require_fn.invoke(&[import_meta_url.into()]);
Ok(Function::from_val(&require_fn.as_::<Any>()))
}
#[derive(Clone, Debug)]
pub struct JsStructuredSerializeOptions {
inner: emlite::Val,
}
impl JsStructuredSerializeOptions {
pub fn new() -> Self {
Self {
inner: emlite::Val::object(),
}
}
pub fn transfer(&self) -> Option<TypedArray<Object>> {
let val = self.inner.get("transfer");
if val.is_undefined() {
None
} else {
Some(val.as_::<TypedArray<Object>>())
}
}
pub fn set_transfer(&self, transfer: &TypedArray<Object>) {
self.inner.set("transfer", transfer);
}
}
impl Default for JsStructuredSerializeOptions {
fn default() -> Self {
Self::new()
}
}
impl AsRef<emlite::Val> for JsStructuredSerializeOptions {
fn as_ref(&self) -> &emlite::Val {
&self.inner
}
}
impl From<JsStructuredSerializeOptions> for emlite::Val {
fn from(options: JsStructuredSerializeOptions) -> Self {
options.inner
}
}
impl From<&JsStructuredSerializeOptions> for emlite::Val {
fn from(options: &JsStructuredSerializeOptions) -> Self {
options.inner.clone()
}
}
pub fn structured_clone<T>(value: &T, options: Option<&JsStructuredSerializeOptions>) -> T
where
T: emlite::FromVal + AsRef<emlite::Val>,
{
let args = match options {
Some(opts) => vec![value.as_ref().clone(), opts.into()],
None => vec![value.as_ref().clone()],
};
emlite::Val::global("structuredClone")
.invoke(&args)
.as_::<T>()
}