1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
extern crate napi_sys;

mod args;
mod env;
mod result;
mod value;

pub use args::NapiArgs;
pub use env::NapiEnv;
pub use result::{NapiError, NapiErrorKind, NapiResult};
pub use value::{AsNapiObject, NapiAny, NapiArray, NapiArrayBuffer,
                NapiBoolean, NapiBuffer, NapiNull, NapiNumber, NapiObject,
                NapiString, NapiUndefined, NapiValue, NapiValueType};

pub mod sys {
    pub use napi_sys::*;
}

#[macro_export]
macro_rules! napi_callback {
    ($wrapper:ident, $handler:expr) => {
        #[no_mangle]
        pub extern "C" fn $wrapper(
            env: $crate::sys::napi_env,
            cb_info: $crate::sys::napi_callback_info,
        ) -> $crate::sys::napi_value {
            use std::error::Error;
            use std::ffi::CString;
            use std::ptr;

            use $crate::{NapiArgs, NapiEnv, NapiResult, NapiValue};
            use $crate::sys::{napi_get_undefined, napi_throw,
                              napi_throw_error, napi_value};

            let env_wrapper = NapiEnv::from(env);

            fn typecheck_result<'a, T: NapiValue<'a>>(_: &NapiResult<T>) {}

            let result = <_ as NapiArgs>::from_cb_info(&env_wrapper, cb_info)
                .and_then(|args| {
                    let result = $handler(&env_wrapper, &args);
                    typecheck_result(&result);
                    result
                });

            match result {
                Ok(value) => value.as_sys_value(),
                Err(error) => {
                    if let Some(exception) = error.exception {
                        unsafe {
                            napi_throw(env, exception);
                        }
                    } else {
                        let message = format!("{}", &error);
                        let c_string =
                            CString::new(message).unwrap_or_else(|_| {
                                CString::new(error.description()).unwrap()
                            });

                        unsafe {
                            napi_throw_error(
                                env,
                                ptr::null(),
                                c_string.as_ptr(),
                            );
                        }
                    }

                    let mut result: napi_value = ptr::null_mut();
                    unsafe {
                        napi_get_undefined(env, &mut result);
                    }
                    result
                }
            }
        }
    };
}