Skip to content

Commit

Permalink
Adding TryFromJs implementations for tuples (#3843)
Browse files Browse the repository at this point in the history
* Adding TryFromJs implementations for tuples

* rustfmt and clippies

* rustfmt

* Remove unit type

* Clippies
  • Loading branch information
hansl authored and jasonwilliams committed Jun 25, 2024
1 parent ee7b119 commit 5359528
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
51 changes: 51 additions & 0 deletions core/engine/src/value/conversions/try_from_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use num_bigint::BigInt;
use crate::{js_string, Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsValue};

mod collections;
mod tuples;

/// This trait adds a fallible and efficient conversions from a [`JsValue`] to Rust types.
pub trait TryFromJs: Sized {
Expand Down Expand Up @@ -367,6 +368,56 @@ fn value_into_vec() {
]);
}

#[test]
fn value_into_tuple() {
use boa_engine::{run_test_actions, TestAction};
use indoc::indoc;

run_test_actions([
TestAction::assert_with_op(indoc! {r#" [42, "hello", true] "#}, |value, context| {
type TestType = (i32, String, bool);
TestType::try_from_js(&value, context).unwrap() == (42, "hello".to_string(), true)
}),
TestAction::assert_with_op(indoc! {r#" [42, "hello", true] "#}, |value, context| {
type TestType = (i32, String, Option<bool>, Option<u8>);
TestType::try_from_js(&value, context).unwrap()
== (42, "hello".to_string(), Some(true), None)
}),
TestAction::assert_with_op(indoc! {r#" [] "#}, |value, context| {
type TestType = (
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
Option<bool>,
);
TestType::try_from_js(&value, context).unwrap()
== (None, None, None, None, None, None, None, None, None, None)
}),
TestAction::assert_with_op(indoc!(r#"[42, "hello", {}]"#), |value, context| {
type TestType = (i32, String, bool);
let Err(value) = TestType::try_from_js(&value, context) else {
return false;
};
assert!(value.to_string().contains("TypeError"));
true
}),
TestAction::assert_with_op(indoc!(r#"[42, "hello"]"#), |value, context| {
type TestType = (i32, String, bool);
let Err(value) = TestType::try_from_js(&value, context) else {
return false;
};
assert!(value.to_string().contains("TypeError"));
true
}),
]);
}

#[test]
fn value_into_map() {
use boa_engine::{run_test_actions, TestAction};
Expand Down
41 changes: 41 additions & 0 deletions core/engine/src/value/conversions/try_from_js/tuples.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! Implementation of [`TryFromJs`] for tuples.
//!
//! Tuples are converted from a JavaScript array, using similar semantics to `TypeScript` tuples:
//! - If the tuple is shorter than the array, the extra elements are ignored.
//! - If the tuple is longer than the array, the extra elements are `undefined`.
//! - If the array is empty, all elements are `undefined`.
//!
//! A tuple of size 0 (unit type) does not implement [`TryFromJs`].

use crate::value::JsValue;
use crate::{Context, JsResult};

use super::TryFromJs;

macro_rules! impl_try_from_js_for_tuples {
($($name:ident),*) => {
impl<$($name: TryFromJs),*> TryFromJs for ($($name,)*) {
fn try_from_js(value: &JsValue, context: &mut Context) -> JsResult<Self> {
let vec: Vec<JsValue> = value.try_js_into(context)?;
let mut iter = vec.into_iter();

Ok((
$(
$name::try_from_js(&iter.next().unwrap_or_else(JsValue::undefined), context)?,
)*
))
}
}
};
}

impl_try_from_js_for_tuples!(A);
impl_try_from_js_for_tuples!(A, B);
impl_try_from_js_for_tuples!(A, B, C);
impl_try_from_js_for_tuples!(A, B, C, D);
impl_try_from_js_for_tuples!(A, B, C, D, E);
impl_try_from_js_for_tuples!(A, B, C, D, E, F);
impl_try_from_js_for_tuples!(A, B, C, D, E, F, G);
impl_try_from_js_for_tuples!(A, B, C, D, E, F, G, H);
impl_try_from_js_for_tuples!(A, B, C, D, E, F, G, H, I);
impl_try_from_js_for_tuples!(A, B, C, D, E, F, G, H, I, J);

0 comments on commit 5359528

Please sign in to comment.