neon 0.4.0

A safe abstraction layer for Node.js.
Documentation
use std::mem;
use std::os::raw::c_void;
use std::ptr::null_mut;
use neon_runtime;
use neon_runtime::raw;
use super::{Class, ClassInternal, Callback};
use handle::{Handle, Managed};
use context::{CallbackInfo, CallContext, Context};
use context::internal::ContextInternal;
use result::{NeonResult, JsResult, Throw};
use types::{JsValue, JsObject, JsFunction, JsUndefined, build};
use types::error::convert_panics;

#[repr(C)]
pub struct MethodCallback<T: Class>(pub fn(CallContext<T>) -> JsResult<JsValue>);

impl<T: Class> Callback<()> for MethodCallback<T> {
    extern "C" fn invoke(info: &CallbackInfo) {
        unsafe {
            info.with_cx::<T, _, _>(|mut cx| {
                let data = info.data();
                let this: Handle<JsValue> = Handle::new_internal(JsValue::from_raw(info.this(&mut cx)));
                if !this.is_a::<T>() {
                    if let Ok(metadata) = T::metadata(&mut cx) {
                        neon_runtime::class::throw_this_error(mem::transmute(cx.env()), metadata.pointer);
                    }
                    return;
                };
                let dynamic_callback: fn(CallContext<T>) -> JsResult<JsValue> =
                    mem::transmute(neon_runtime::fun::get_dynamic_callback(data.to_raw()));
                if let Ok(value) = convert_panics(|| { dynamic_callback(cx) }) {
                    info.set_return(value);
                }
            })
        }
        }

    fn as_ptr(self) -> *mut c_void {
        self.0 as *mut c_void
    }
}

#[repr(C)]
pub struct ConstructorCallCallback(pub fn(CallContext<JsValue>) -> JsResult<JsValue>);

impl ConstructorCallCallback {
    pub(crate) fn default<T: Class>() -> Self {
        fn callback<T: Class>(mut cx: CallContext<JsValue>) -> JsResult<JsValue> {
            unsafe {
                if let Ok(metadata) = T::metadata(&mut cx) {
                    neon_runtime::class::throw_call_error(mem::transmute(cx.env()), metadata.pointer);
                }
            }
            Err(Throw)
        }

        ConstructorCallCallback(callback::<T>)
    }
}

impl Callback<()> for ConstructorCallCallback {
    extern "C" fn invoke(info: &CallbackInfo) {
        unsafe {
            info.with_cx(|cx| {
                let data = info.data();
                let kernel: fn(CallContext<JsValue>) -> JsResult<JsValue> =
                    mem::transmute(neon_runtime::class::get_call_kernel(data.to_raw()));
                if let Ok(value) = convert_panics(|| { kernel(cx) }) {
                    info.set_return(value);
                }
            })
        }
    }

    fn as_ptr(self) -> *mut c_void {
        self.0 as *mut c_void
    }
}

#[repr(C)]
pub struct AllocateCallback<T: Class>(pub fn(CallContext<JsUndefined>) -> NeonResult<T::Internals>);

impl<T: Class> Callback<*mut c_void> for AllocateCallback<T> {
    extern "C" fn invoke(info: &CallbackInfo) -> *mut c_void {
        unsafe {
            info.with_cx(|cx| {
                let data = info.data();
                let kernel: fn(CallContext<JsUndefined>) -> NeonResult<T::Internals> =
                    mem::transmute(neon_runtime::class::get_allocate_kernel(data.to_raw()));
                if let Ok(value) = convert_panics(|| { kernel(cx) }) {
                    let p = Box::into_raw(Box::new(value));
                    mem::transmute(p)
                } else {
                    null_mut()
                }
            })
        }
    }

    fn as_ptr(self) -> *mut c_void {
        self.0 as *mut c_void
    }
}

#[repr(C)]
pub struct ConstructCallback<T: Class>(pub fn(CallContext<T>) -> NeonResult<Option<Handle<JsObject>>>);

impl<T: Class> Callback<bool> for ConstructCallback<T> {
    extern "C" fn invoke(info: &CallbackInfo) -> bool {
        unsafe {
            info.with_cx(|cx| {
                let data = info.data();
                let kernel: fn(CallContext<T>) -> NeonResult<Option<Handle<JsObject>>> =
                    mem::transmute(neon_runtime::class::get_construct_kernel(data.to_raw()));
                match convert_panics(|| { kernel(cx) }) {
                    Ok(None) => true,
                    Ok(Some(obj)) => {
                        info.set_return(obj);
                        true
                    }
                    _ => false
                }
            })
        }
    }

    fn as_ptr(self) -> *mut c_void {
        self.0 as *mut c_void
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct ClassMetadata {
    pub(crate) pointer: *mut c_void
}

impl ClassMetadata {
    pub unsafe fn constructor<'a, T: Class, C: Context<'a>>(&self, cx: &mut C) -> JsResult<'a, JsFunction<T>> {
        build(|out| {
            neon_runtime::class::metadata_to_constructor(out, mem::transmute(cx.env()), self.pointer)
        })
    }

    pub unsafe fn has_instance(&self, value: raw::Local) -> bool {
        neon_runtime::class::has_instance(self.pointer, value)
    }
}