rquickjs_core/value/function/
ffi.rs

1use crate::{
2    class::{JsCell, JsClass, Readable, Trace, Tracer},
3    qjs,
4    value::function::Params,
5    Ctx, Function, JsLifetime, Object, Result, Value,
6};
7
8use super::Constructor;
9
10pub unsafe extern "C" fn defer_call_job(
11    ctx: *mut qjs::JSContext,
12    argc: qjs::c_int,
13    argv: *mut qjs::JSValue,
14) -> qjs::JSValue {
15    let func = *argv.offset((argc - 1) as _);
16    let this = *argv.offset((argc - 2) as _);
17    let argc = argc - 2;
18    qjs::JS_Call(ctx, func, this, argc, argv)
19}
20
21/// A trait for dynamic callbacks to Rust.
22pub trait RustFunc<'js> {
23    /// Call the actual function with a given set of parameters and return a function.
24    fn call<'a>(&self, params: Params<'a, 'js>) -> Result<Value<'js>>;
25}
26
27impl<'js, F> RustFunc<'js> for F
28where
29    for<'a> F: Fn(Params<'a, 'js>) -> Result<Value<'js>>,
30{
31    fn call<'a>(&self, params: Params<'a, 'js>) -> Result<Value<'js>> {
32        (self)(params)
33    }
34}
35
36/// The class used for wrapping closures, rquickjs implements callbacks by creating an instances of
37/// this class.
38pub struct RustFunction<'js>(pub Box<dyn RustFunc<'js> + 'js>);
39
40unsafe impl<'js> JsLifetime<'js> for RustFunction<'js> {
41    type Changed<'to> = RustFunction<'to>;
42}
43
44impl<'js> Trace<'js> for RustFunction<'js> {
45    fn trace<'a>(&self, _tracer: Tracer<'a, 'js>) {}
46}
47
48impl<'js> JsClass<'js> for RustFunction<'js> {
49    const NAME: &'static str = "RustFunction";
50
51    type Mutable = Readable;
52
53    const CALLABLE: bool = true;
54
55    fn prototype(ctx: &Ctx<'js>) -> Result<Option<Object<'js>>> {
56        Ok(Some(Function::prototype(ctx.clone())))
57    }
58
59    fn constructor(_ctx: &Ctx<'js>) -> Result<Option<Constructor<'js>>> {
60        Ok(None)
61    }
62
63    fn call<'a>(this: &JsCell<'js, Self>, params: Params<'a, 'js>) -> Result<Value<'js>> {
64        this.borrow().0.call(params)
65    }
66}