Skip to content

Commit 51d8823

Browse files
committed
feat: support stable compiler and implement initial machinery for args
1 parent 6e56e8d commit 51d8823

File tree

9 files changed

+169
-179
lines changed

9 files changed

+169
-179
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[workspace]
22
members = [
33
"napi",
4+
"napi-derive",
45
"napi-sys",
5-
"napi-codegen",
66
"example",
77
]

example/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ crate-type = ["staticlib"]
88

99
[dependencies]
1010
napi = { path = "../napi" }
11-
napi-codegen = { path = "../napi-codegen" }
11+
napi-derive = { path = "../napi-derive" }

example/src/binding.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <node_api.h>
22

33
#define FUNCTIONS_MAP(V) \
4-
V(initialize, napi_rs_cb_initialize)
4+
V(initialize, example_initialize)
55

66
#define V(name, func) \
77
extern napi_value func(napi_env env, napi_callback_info info);

example/src/lib.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
#![feature(plugin)]
2-
#![plugin(napi_codegen)]
3-
1+
#[macro_use]
42
extern crate napi;
3+
#[macro_use]
4+
extern crate napi_derive;
5+
6+
use napi::{NapiArgs, NapiEnv, NapiResult, NapiUndefined};
57

6-
use napi::{NapiEnv, NapiResult, NapiUndefined};
8+
#[derive(NapiArgs)]
9+
struct InitializeArgs();
710

8-
#[napi_callback("initialize")]
9-
fn initialize(env: &NapiEnv) -> NapiResult<NapiUndefined> {
11+
fn initialize(
12+
env: &NapiEnv,
13+
_args: InitializeArgs,
14+
) -> NapiResult<NapiUndefined> {
1015
println!("Hello from the Rust land!");
1116
NapiUndefined::new(env)
1217
}
18+
19+
napi_callback!(example_initialize, initialize);

napi-codegen/src/lib.rs

Lines changed: 0 additions & 164 deletions
This file was deleted.
Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
[package]
2-
name = "napi-codegen"
3-
version = "0.1.0"
42
authors = ["Alexey Orlenko <[email protected]>"]
5-
6-
[lib]
7-
plugin = true
3+
name = "napi-derive"
4+
version = "0.1.0"
85

96
[dependencies]
10-
napi = { path = "../napi" }
7+
quote = "0.3.15"
8+
syn = "0.11.11"
9+
10+
[lib]
11+
proc-macro = true

napi-derive/src/lib.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#![recursion_limit = "128"]
2+
3+
extern crate proc_macro;
4+
#[macro_use]
5+
extern crate quote;
6+
extern crate syn;
7+
8+
use proc_macro::TokenStream;
9+
10+
#[proc_macro_derive(NapiArgs)]
11+
pub fn napi_args(input: TokenStream) -> TokenStream {
12+
let ast = syn::parse_derive_input(&input.to_string()).unwrap();
13+
match impl_napi_args(&ast) {
14+
Ok(generated) => generated.parse().unwrap(),
15+
Err(message) => panic!(message),
16+
}
17+
}
18+
19+
fn impl_napi_args(
20+
ast: &syn::DeriveInput,
21+
) -> Result<quote::Tokens, &'static str> {
22+
let name = &ast.ident;
23+
24+
let variant_data = match ast.body {
25+
syn::Body::Struct(ref data) => data,
26+
_ => return Err("NapiArgs can only be derived for structs"),
27+
};
28+
29+
let fields = match variant_data {
30+
&syn::VariantData::Tuple(ref fields) => fields,
31+
_ => return Err("NapiArgs can only be derived for tuple-structs"),
32+
};
33+
let count = fields.len();
34+
35+
Ok(quote! {
36+
impl NapiArgs for #name {
37+
fn from_cb_info(
38+
env: &::napi::NapiEnv,
39+
cb_info: ::napi::sys::napi_callback_info,
40+
) -> ::napi::NapiResult<Self> {
41+
use ::napi::sys;
42+
use ::napi::{NapiError, NapiString};
43+
44+
use ::std::ptr;
45+
46+
let mut argc = #count;
47+
let mut argv = [ptr::null_mut(); #count];
48+
49+
env.handle_status(unsafe {
50+
sys::napi_get_cb_info(
51+
env.as_sys_env(),
52+
cb_info,
53+
&mut argc,
54+
argv.as_mut_ptr(),
55+
ptr::null_mut(),
56+
ptr::null_mut(),
57+
)
58+
})?;
59+
60+
if argc != #count {
61+
let message = NapiString::from_str(env, &format!(
62+
"Expected {} arguments, but got {}",
63+
#count,
64+
argc,
65+
))?;
66+
return Err(NapiError::type_error(env, &message));
67+
}
68+
69+
Ok(#name())
70+
}
71+
}
72+
})
73+
}

napi/src/args.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
use env::NapiEnv;
2+
use result::NapiResult;
3+
use sys;
4+
5+
pub trait NapiArgs: Sized {
6+
fn from_cb_info(
7+
env: &NapiEnv,
8+
cb_info: sys::napi_callback_info,
9+
) -> NapiResult<Self>;
10+
}

napi/src/lib.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
extern crate napi_sys;
22

3+
mod args;
34
mod env;
45
mod result;
56
mod value;
67

8+
pub use args::NapiArgs;
79
pub use env::NapiEnv;
810
pub use result::{NapiError, NapiErrorKind, NapiResult};
911
pub use value::{AsNapiObject, NapiAny, NapiArray, NapiArrayBuffer,
@@ -13,3 +15,64 @@ pub use value::{AsNapiObject, NapiAny, NapiArray, NapiArrayBuffer,
1315
pub mod sys {
1416
pub use napi_sys::*;
1517
}
18+
19+
#[macro_export]
20+
macro_rules! napi_callback {
21+
($wrapper:ident, $handler:expr) => {
22+
#[no_mangle]
23+
pub extern "C" fn $wrapper(
24+
env: $crate::sys::napi_env,
25+
cb_info: $crate::sys::napi_callback_info,
26+
) -> $crate::sys::napi_value {
27+
use std::error::Error;
28+
use std::ffi::CString;
29+
use std::ptr;
30+
31+
use $crate::{NapiArgs, NapiEnv, NapiResult, NapiValue};
32+
use $crate::sys::{napi_get_undefined, napi_throw,
33+
napi_throw_error, napi_value};
34+
35+
let env_wrapper = NapiEnv::from(env);
36+
37+
fn typecheck_result<'a, T: NapiValue<'a>>(_: &NapiResult<T>) {}
38+
39+
let result = <_ as NapiArgs>::from_cb_info(&env_wrapper, cb_info)
40+
.and_then(|args| {
41+
let result = $handler(&env_wrapper, args);
42+
typecheck_result(&result);
43+
result
44+
});
45+
46+
match result {
47+
Ok(value) => value.as_sys_value(),
48+
Err(error) => {
49+
if let Some(exception) = error.exception {
50+
unsafe {
51+
napi_throw(env, exception);
52+
}
53+
} else {
54+
let message = format!("{}", &error);
55+
let c_string =
56+
CString::new(message).unwrap_or_else(|_| {
57+
CString::new(error.description()).unwrap()
58+
});
59+
60+
unsafe {
61+
napi_throw_error(
62+
env,
63+
ptr::null(),
64+
c_string.as_ptr(),
65+
);
66+
}
67+
}
68+
69+
let mut result: napi_value = ptr::null_mut();
70+
unsafe {
71+
napi_get_undefined(env, &mut result);
72+
}
73+
result
74+
}
75+
}
76+
}
77+
};
78+
}

0 commit comments

Comments
 (0)