rmquickjs 0.0.1

High-level binding API for MicroQuickJS
use alloc::boxed::Box;
use core::ffi::c_int;
use rmquickjs_sys::{JS_Call, JS_PushArg, JSGCRef};

use crate::{Context, Error, Result, Value};

pub struct Function<'ctx> {
    gc_ref: Box<JSGCRef>,
    ctx: &'ctx Context,
}

impl Into<Value> for Function<'_> {
    fn into(self) -> Value {
        Value::from_raw(self.gc_ref.val)
    }
}

impl<'ctx> Function<'ctx> {
    pub(crate) fn new(gc_ref: Box<JSGCRef>, ctx: &'ctx Context) -> Self {
        Self { gc_ref, ctx }
    }

    pub fn call(&self, args: &[Value]) -> Result<Value> {
        unsafe {
            for arg in args.iter().rev() {
                JS_PushArg(self.ctx.as_ptr(), arg.into_raw());
            }

            JS_PushArg(self.ctx.as_ptr(), self.gc_ref.val);
            JS_PushArg(self.ctx.as_ptr(), Value::null().into_raw());

            let ret: Value = Value::from_raw(JS_Call(self.ctx.as_ptr(), args.len() as c_int));
            if ret.is_exception() {
                Err(Error {
                    message: ret.to_string(self.ctx),
                    exception: ret,
                })
            } else {
                Ok(ret)
            }
        }
    }
}