Browse Source

Adding TryFromJs implementations for BTreeMap and HashMap (#3844)

pull/3873/head
Hans Larsen 7 months ago committed by GitHub
parent
commit
109dd3d395
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 47
      core/engine/src/value/conversions/try_from_js.rs
  2. 64
      core/engine/src/value/conversions/try_from_js/collections.rs

47
core/engine/src/value/conversions/try_from_js.rs

@ -4,6 +4,8 @@ use num_bigint::BigInt;
use crate::{js_string, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsValue};
mod collections;
/// This trait adds a fallible and efficient conversions from a [`JsValue`] to Rust types.
pub trait TryFromJs: Sized {
/// This function tries to convert a JavaScript value into `Self`.
@ -364,3 +366,48 @@ fn value_into_vec() {
),
]);
}
#[test]
fn value_into_map() {
use boa_engine::{run_test_actions, TestAction};
use indoc::indoc;
run_test_actions([
TestAction::assert_with_op(indoc! {r#" ({ a: 1, b: 2, c: 3 }) "#}, |value, context| {
let value = std::collections::BTreeMap::<String, i32>::try_from_js(&value, context);
match value {
Ok(value) => {
value
== vec![
("a".to_string(), 1),
("b".to_string(), 2),
("c".to_string(), 3),
]
.into_iter()
.collect::<std::collections::BTreeMap<String, i32>>()
}
_ => false,
}
}),
TestAction::assert_with_op(indoc! {r#" ({ a: 1, b: 2, c: 3 }) "#}, |value, context| {
let value = std::collections::HashMap::<String, i32>::try_from_js(&value, context);
match value {
Ok(value) => {
value
== std::collections::HashMap::from_iter(
vec![
("a".to_string(), 1),
("b".to_string(), 2),
("c".to_string(), 3),
]
.into_iter()
.collect::<std::collections::BTreeMap<String, i32>>(),
)
}
_ => false,
}
}),
]);
}

64
core/engine/src/value/conversions/try_from_js/collections.rs

@ -0,0 +1,64 @@
//! [`JsValue`] conversions for std collections.
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use crate::value::TryFromJs;
use crate::{Context, JsNativeError, JsResult, JsValue};
impl<K, V> TryFromJs for BTreeMap<K, V>
where
K: TryFromJs + Ord,
V: TryFromJs,
{
fn try_from_js(value: &JsValue, context: &mut Context) -> JsResult<Self> {
let JsValue::Object(object) = value else {
return Err(JsNativeError::typ()
.with_message("cannot convert value to a BTreeMap")
.into());
};
let keys = object.__own_property_keys__(context)?;
keys.into_iter()
.map(|key| {
let js_value = object.get(key.clone(), context)?;
let js_key: JsValue = key.into();
let key = K::try_from_js(&js_key, context)?;
let value = V::try_from_js(&js_value, context)?;
Ok((key, value))
})
.collect()
}
}
impl<K, V, S> TryFromJs for HashMap<K, V, S>
where
K: TryFromJs + Ord + Hash,
V: TryFromJs,
S: std::hash::BuildHasher + Default,
{
fn try_from_js(value: &JsValue, context: &mut Context) -> JsResult<Self> {
let JsValue::Object(object) = value else {
return Err(JsNativeError::typ()
.with_message("cannot convert value to a BTreeMap")
.into());
};
let keys = object.__own_property_keys__(context)?;
keys.into_iter()
.map(|key| {
let js_value = object.get(key.clone(), context)?;
let js_key: JsValue = key.into();
let key = K::try_from_js(&js_key, context)?;
let value = V::try_from_js(&js_value, context)?;
Ok((key, value))
})
.collect()
}
}
Loading…
Cancel
Save