Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core/engine/src/builtins/weak_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::{
};
use boa_gc::{Finalize, Trace};

type NativeWeakMap = boa_gc::WeakMap<ErasedVTableObject, JsValue>;
pub(crate) type NativeWeakMap = boa_gc::WeakMap<ErasedVTableObject, JsValue>;

#[derive(Debug, Trace, Finalize)]
pub(crate) struct WeakMap;
Expand Down
179 changes: 179 additions & 0 deletions core/engine/src/object/builtins/jsweakmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//! A Rust API wrapper for the `WeakMap` Builtin ECMAScript Object
use std::ops::Deref;

use boa_gc::{Finalize, Trace};

use crate::{
Context, JsResult, JsValue,
builtins::weak_map::{NativeWeakMap, WeakMap},
error::JsNativeError,
object::JsObject,
value::TryFromJs,
};

/// `JsWeakMap` provides a wrapper for Boa's implementation of the ECMAScript `WeakMap` object.
#[derive(Debug, Clone, Trace, Finalize)]
pub struct JsWeakMap {
inner: JsObject,
}

impl JsWeakMap {
/// Creates a new empty `WeakMap`.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/WeakMap
#[inline]
pub fn new(context: &mut Context) -> Self {
Self {
inner: JsObject::from_proto_and_data_with_shared_shape(
context.root_shape(),
context.intrinsics().constructors().weak_map().prototype(),
NativeWeakMap::new(),
)
.upcast(),
}
}

/// Returns the value associated with the specified key in the `WeakMap`,
/// or `undefined` if the key is not present.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get
#[inline]
pub fn get(&self, key: &JsObject, context: &mut Context) -> JsResult<JsValue> {
WeakMap::get(&self.inner.clone().into(), &[key.clone().into()], context)
}

/// Inserts a key-value pair into the `WeakMap`.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set
#[inline]
pub fn set(&self, key: &JsObject, value: JsValue, context: &mut Context) -> JsResult<JsValue> {
WeakMap::set(
&self.inner.clone().into(),
&[key.clone().into(), value],
context,
)
}

/// Returns `true` if the specified key exists in the `WeakMap`.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has
#[inline]
pub fn has(&self, key: &JsObject, context: &mut Context) -> JsResult<bool> {
WeakMap::has(&self.inner.clone().into(), &[key.clone().into()], context)
.map(|v| v.as_boolean().unwrap_or(false))
}

/// Removes the element associated with the specified key.
/// Returns `true` if the element existed, `false` otherwise.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete
#[inline]
pub fn delete(&self, key: &JsObject, context: &mut Context) -> JsResult<bool> {
WeakMap::delete(&self.inner.clone().into(), &[key.clone().into()], context)
.map(|v| v.as_boolean().unwrap_or(false))
}

/// Returns the value associated with the key if it exists; otherwise inserts
/// the provided default value and returns it.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/getOrInsert
#[inline]
pub fn get_or_insert(
&self,
key: &JsObject,
default: JsValue,
context: &mut Context,
) -> JsResult<JsValue> {
WeakMap::get_or_insert(
&self.inner.clone().into(),
&[key.clone().into(), default],
context,
)
}

/// Returns the value associated with the key if it exists; otherwise calls
/// the provided callback with the key, inserts the result, and returns it.
///
/// More information:
/// - [MDN documentation][mdn]
///
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/getOrInsertComputed
#[inline]
pub fn get_or_insert_computed(
&self,
key: &JsObject,
callback: JsValue,
context: &mut Context,
) -> JsResult<JsValue> {
WeakMap::get_or_insert_computed(
&self.inner.clone().into(),
&[key.clone().into(), callback],
context,
)
}

/// Creates a `JsWeakMap` from a `JsObject`, or returns the original object as `Err`
/// if it is not a `WeakMap`.
#[inline]
pub fn from_object(object: JsObject) -> Result<Self, JsObject> {
if object.downcast_ref::<NativeWeakMap>().is_some() {
Ok(Self { inner: object })
} else {
Err(object)
}
}
}

impl From<JsWeakMap> for JsObject {
#[inline]
fn from(o: JsWeakMap) -> Self {
o.inner.clone()
}
}

impl From<JsWeakMap> for JsValue {
#[inline]
fn from(o: JsWeakMap) -> Self {
o.inner.clone().into()
}
}

impl Deref for JsWeakMap {
type Target = JsObject;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl TryFromJs for JsWeakMap {
fn try_from_js(value: &JsValue, _context: &mut Context) -> JsResult<Self> {
if let Some(o) = value.as_object()
&& let Ok(weak_map) = Self::from_object(o.clone())
{
Ok(weak_map)
} else {
Err(JsNativeError::typ()
.with_message("value is not a WeakMap object")
.into())
}
}
}
2 changes: 2 additions & 0 deletions core/engine/src/object/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ mod jsset;
mod jsset_iterator;
mod jssharedarraybuffer;
mod jstypedarray;
mod jsweakmap;

pub use jsarray::*;
pub use jsarraybuffer::*;
Expand All @@ -33,3 +34,4 @@ pub use jsset::*;
pub use jsset_iterator::*;
pub use jssharedarraybuffer::*;
pub use jstypedarray::*;
pub use jsweakmap::JsWeakMap;
36 changes: 36 additions & 0 deletions examples/src/bin/jsweakmap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Example demonstrating the `JsWeakMap` API wrapper.
use boa_engine::{Context, js_string, object::builtins::JsWeakMap};

fn main() {
let mut context = Context::default();

// Create a new WeakMap
let weak_map = JsWeakMap::new(&mut context);

// Create an object to use as a key
let key = context
.eval(boa_engine::Source::from_bytes("({})"))
.unwrap();
let key_obj = key.as_object().unwrap().clone();

// Set a value
weak_map
.set(&key_obj, js_string!("hello").into(), &mut context)
.unwrap();

// Get the value
let val = weak_map.get(&key_obj, &mut context).unwrap();
println!("get: {}", val.display());

// Has the key
let has = weak_map.has(&key_obj, &mut context).unwrap();
println!("has: {has}");

// Delete the key
let deleted = weak_map.delete(&key_obj, &mut context).unwrap();
println!("deleted: {deleted}");

// Has after delete
let has_after = weak_map.has(&key_obj, &mut context).unwrap();
println!("has after delete: {has_after}");
}
Loading