mirror of https://github.com/boa-dev/boa.git
Browse Source
* 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 * clippiespull/4003/head
Hans Larsen
2 months ago
committed by
GitHub
7 changed files with 237 additions and 1 deletions
@ -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) |
||||
); |
||||
} |
@ -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); |
||||
} |
@ -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\"" |
||||
); |
||||
} |
@ -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); |
||||
} |
Loading…
Reference in new issue