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