use napi::{Env, JsValue, bindgen_prelude::*};
use rspack_napi::WeakRef;
#[napi(object)]
pub struct JsHelpers<'env> {
#[napi(ts_type = "<T>(source: ReadonlyArray<T>, target: T[], commands: Uint32Array) => void")]
pub apply_indexed_array_updates: Function<'env>,
#[napi(ts_type = "<T>(array: T[], removedIndices: Uint32Array) => void")]
pub swap_remove_array_elements: Function<'env>,
}
pub(crate) struct JsHelperRefs {
apply_indexed_array_updates: WeakRef,
swap_remove_array_elements: WeakRef,
}
impl JsHelperRefs {
pub(crate) fn new(
env: &Env,
owner: &mut Object<'_>,
helpers: JsHelpers<'_>,
) -> napi::Result<Self> {
let references = Self {
apply_indexed_array_updates: WeakRef::new(
env.raw(),
&mut helpers.apply_indexed_array_updates.coerce_to_object()?,
)?,
swap_remove_array_elements: WeakRef::new(
env.raw(),
&mut helpers.swap_remove_array_elements.coerce_to_object()?,
)?,
};
owner.define_properties(&[Property::new()
.with_name(env, env.create_symbol(Some("rspack.jsHelpers"))?)?
.with_napi_value(env, helpers)?
.with_property_attributes(PropertyAttributes::Default)])?;
Ok(references)
}
pub(crate) fn swap_remove_array_elements(
&self,
env: &Env,
array: Array<'_>,
removed_indices: &Uint32ArraySlice<'_>,
) -> napi::Result<()> {
let function = unsafe {
Function::<FnArgs<(Array, &Uint32ArraySlice)>, ()>::from_napi_value(
env.raw(),
ToNapiValue::to_napi_value(env.raw(), &self.swap_remove_array_elements)?,
)?
};
function.call((array, removed_indices).into())
}
}
pub(crate) fn js_owned_ref(
env: &Env,
owner: &mut Object<'_>,
name: &str,
mut value: Object<'_>,
) -> napi::Result<WeakRef> {
let reference = WeakRef::new(env.raw(), &mut value)?;
owner.define_properties(&[Property::new()
.with_name(env, env.create_symbol(Some(name))?)?
.with_value(&value)
.with_property_attributes(PropertyAttributes::Default)])?;
Ok(reference)
}
#[derive(Default)]
pub(crate) struct IndexedArrayUpdate<'env> {
pub(crate) source: Option<Array<'env>>,
pub(crate) target: Option<Array<'env>>,
pub(crate) commands: Vec<u32>,
}
impl IndexedArrayUpdate<'_> {
pub(crate) fn apply(self, env: &Env, helpers: &JsHelperRefs) -> napi::Result<()> {
if self.commands.is_empty() {
return Ok(());
}
let function = unsafe {
Function::<FnArgs<(Array, Array, Uint32ArraySlice)>, ()>::from_napi_value(
env.raw(),
ToNapiValue::to_napi_value(env.raw(), &helpers.apply_indexed_array_updates)?,
)?
};
let commands = Uint32ArraySlice::from_data(env, self.commands)?;
function.call(
(
self
.source
.expect("nonempty indexed array update has a source array"),
self
.target
.expect("nonempty indexed array update has a target array"),
commands,
)
.into(),
)
}
}