-
-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add TryFromJs for TypedJsFunction and more tests (#3981)
* Add TryFromJs for TypedJsFunction and more tests Includes adding TryFromJs for "()". * Fix clippies and fmt * Prettier * Add From<TypedJsFunction> for JsValue to allow conversion * Implement comments * clippies
- Loading branch information
Showing
7 changed files
with
237 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* Calculate a fibonacci number by calling callbacks with intermediate results, | ||
* switching between Rust and JavaScript. | ||
* @param {number} a The fibonacci number to calculate. | ||
* @param {function} callback_a A callback method. | ||
* @param {function} callback_b A callback method. | ||
* @returns {number} The {a}th fibonacci number. | ||
*/ | ||
export function fibonacci(a, callback_a, callback_b) { | ||
if (a <= 1) { | ||
return a; | ||
} | ||
|
||
// Switch the callbacks around. | ||
return ( | ||
callback_a(a - 1, callback_b, callback_a) + | ||
callback_b(a - 2, callback_b, callback_a) | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
/** | ||
* Calculate the greatest common divisor of two numbers. | ||
* @param {number} a | ||
* @param {number} b | ||
* @param {function} callback A callback method to call with the result. | ||
* @returns {number|*} The greatest common divisor of {a} and {b}. | ||
* @throws {TypeError} If either {a} or {b} is not finite. | ||
*/ | ||
export function gcd_callback(a, b, callback) { | ||
a = +a; | ||
b = +b; | ||
if (!Number.isFinite(a) || !Number.isFinite(b)) { | ||
throw new TypeError("Invalid input"); | ||
} | ||
|
||
// Euclidean algorithm | ||
function inner_gcd(a, b) { | ||
while (b !== 0) { | ||
let t = b; | ||
b = a % b; | ||
a = t; | ||
} | ||
return a; | ||
} | ||
|
||
let result = inner_gcd(a, b); | ||
callback(result); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#![allow(unused_crate_dependencies)] | ||
//! A test that goes back and forth between JavaScript and Rust. | ||
// You can execute this example with `cargo run --example gcd` | ||
|
||
use boa_engine::object::builtins::{JsFunction, TypedJsFunction}; | ||
use boa_engine::{js_error, js_str, Context, JsResult, Module, Source}; | ||
use boa_interop::IntoJsFunctionCopied; | ||
use std::path::PathBuf; | ||
|
||
#[allow(clippy::needless_pass_by_value)] | ||
fn fibonacci( | ||
a: usize, | ||
cb_a: TypedJsFunction<(usize, JsFunction, JsFunction), usize>, | ||
cb_b: TypedJsFunction<(usize, JsFunction, JsFunction), usize>, | ||
context: &mut Context, | ||
) -> JsResult<usize> { | ||
if a <= 1 { | ||
Ok(a) | ||
} else { | ||
Ok( | ||
cb_a.call(context, (a - 1, cb_b.clone().into(), cb_a.clone().into()))? | ||
+ cb_b.call(context, (a - 2, cb_b.clone().into(), cb_a.clone().into()))?, | ||
) | ||
} | ||
} | ||
|
||
fn fibonacci_throw( | ||
a: usize, | ||
cb_a: TypedJsFunction<(usize, JsFunction, JsFunction), usize>, | ||
cb_b: TypedJsFunction<(usize, JsFunction, JsFunction), usize>, | ||
context: &mut Context, | ||
) -> JsResult<usize> { | ||
if a < 5 { | ||
Err(js_error!("a is too small")) | ||
} else { | ||
fibonacci(a, cb_a, cb_b, context) | ||
} | ||
} | ||
|
||
#[test] | ||
fn fibonacci_test() { | ||
let assets_dir = | ||
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("tests/assets"); | ||
|
||
// Create the engine. | ||
let context = &mut Context::default(); | ||
|
||
// Load the JavaScript code. | ||
let gcd_path = assets_dir.join("fibonacci.js"); | ||
let source = Source::from_filepath(&gcd_path).unwrap(); | ||
let module = Module::parse(source, None, context).unwrap(); | ||
module | ||
.load_link_evaluate(context) | ||
.await_blocking(context) | ||
.unwrap(); | ||
|
||
let fibonacci_js = module | ||
.get_typed_fn::<(usize, JsFunction, JsFunction), usize>(js_str!("fibonacci"), context) | ||
.unwrap(); | ||
|
||
let fibonacci_rust = fibonacci | ||
.into_js_function_copied(context) | ||
.to_js_function(context.realm()); | ||
|
||
assert_eq!( | ||
fibonacci_js | ||
.call( | ||
context, | ||
( | ||
10, | ||
fibonacci_rust.clone(), | ||
fibonacci_js.as_js_function().clone() | ||
) | ||
) | ||
.unwrap(), | ||
55 | ||
); | ||
|
||
let fibonacci_throw = fibonacci_throw | ||
.into_js_function_copied(context) | ||
.to_js_function(context.realm()); | ||
assert_eq!( | ||
fibonacci_js | ||
.call( | ||
context, | ||
( | ||
10, | ||
fibonacci_throw.clone(), | ||
fibonacci_js.as_js_function().clone() | ||
) | ||
) | ||
.unwrap_err() | ||
.to_string(), | ||
"\"a is too small\"" | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
#![allow(unused_crate_dependencies)] | ||
//! A test that mimics the `boa_engine`'s GCD test with a typed callback. | ||
use boa_engine::object::builtins::JsFunction; | ||
use boa_engine::{js_str, Context, Module, Source}; | ||
use boa_gc::Gc; | ||
use boa_interop::{ContextData, IntoJsFunctionCopied}; | ||
use std::path::PathBuf; | ||
use std::sync::atomic::{AtomicUsize, Ordering}; | ||
|
||
fn callback_from_js(ContextData(r): ContextData<Gc<AtomicUsize>>, result: usize) { | ||
r.store(result, Ordering::Relaxed); | ||
} | ||
|
||
#[test] | ||
fn gcd_callback() { | ||
let assets_dir = | ||
PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("tests/assets"); | ||
|
||
// Create the engine. | ||
let context = &mut Context::default(); | ||
let result = Gc::new(AtomicUsize::new(0)); | ||
context.insert_data(result.clone()); | ||
|
||
// Load the JavaScript code. | ||
let gcd_path = assets_dir.join("gcd_callback.js"); | ||
let source = Source::from_filepath(&gcd_path).unwrap(); | ||
let module = Module::parse(source, None, context).unwrap(); | ||
module | ||
.load_link_evaluate(context) | ||
.await_blocking(context) | ||
.unwrap(); | ||
|
||
let js_gcd = module | ||
.get_typed_fn::<(i32, i32, JsFunction), ()>(js_str!("gcd_callback"), context) | ||
.unwrap(); | ||
|
||
let function = callback_from_js | ||
.into_js_function_copied(context) | ||
.to_js_function(context.realm()); | ||
|
||
result.store(0, Ordering::Relaxed); | ||
assert_eq!(js_gcd.call(context, (6, 9, function.clone())), Ok(())); | ||
assert_eq!(result.load(Ordering::Relaxed), 3); | ||
|
||
result.store(0, Ordering::Relaxed); | ||
assert_eq!(js_gcd.call(context, (9, 6, function)), Ok(())); | ||
assert_eq!(result.load(Ordering::Relaxed), 3); | ||
} |