#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "legacy-runtime")]
pub mod borrow;
pub mod context;
#[cfg(any(
feature = "event-handler-api",
all(feature = "napi-1", feature = "task-api"),
all(feature = "napi-4", feature = "channel-api")
))]
pub mod event;
pub mod handle;
pub mod meta;
pub mod object;
pub mod prelude;
#[cfg(feature = "napi-1")]
pub mod reflect;
pub mod result;
#[cfg(feature = "legacy-runtime")]
pub mod task;
pub mod types;
#[doc(hidden)]
pub mod macro_internal;
#[cfg(feature = "proc-macros")]
#[cfg_attr(docsrs, doc(cfg(feature = "proc-macros")))]
pub use neon_macros::*;
#[cfg(feature = "napi-6")]
mod lifecycle;
#[cfg(all(feature = "legacy-runtime", feature = "napi-1"))]
compile_error!("Cannot enable both `legacy-runtime` and `napi-*` features.\n\nTo use `napi-*`, disable `legacy-runtime` by setting `default-features` to `false` in Cargo.toml\nor with cargo's --no-default-features flag.");
#[cfg(all(feature = "napi-1", not(feature = "legacy-runtime")))]
#[doc(hidden)]
#[macro_export]
macro_rules! register_module {
($module:pat, $init:block) => {
register_module!(|$module| $init);
};
(|$module:pat| $init:block) => {
#[no_mangle]
pub unsafe extern "C" fn napi_register_module_v1(
env: $crate::macro_internal::runtime::raw::Env,
m: $crate::macro_internal::runtime::raw::Local
) -> $crate::macro_internal::runtime::raw::Local
{
#[cfg(not(feature = "default-panic-hook"))]
::std::panic::set_hook(::std::boxed::Box::new(|_| { }));
fn __init_neon_module($module: $crate::context::ModuleContext) -> $crate::result::NeonResult<()> $init
$crate::macro_internal::initialize_module(
env,
std::mem::transmute(m),
__init_neon_module,
);
m
}
}
}
#[cfg(feature = "legacy-runtime")]
#[macro_export]
macro_rules! register_module {
($module:pat, $init:block) => {
#[allow(improper_ctypes)]
#[cfg_attr(target_os = "freebsd", link_section = ".ctors")]
#[cfg_attr(target_os = "linux", link_section = ".ctors")]
#[cfg_attr(target_os = "android", link_section = ".ctors")]
#[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "ios", link_section = "__DATA,__mod_init_func")]
#[cfg_attr(target_os = "windows", link_section = ".CRT$XCU")]
#[used]
pub static __LOAD_NEON_MODULE: extern "C" fn() = {
fn __init_neon_module($module: $crate::context::ModuleContext) -> $crate::result::NeonResult<()> $init
extern "C" fn __load_neon_module() {
#[repr(C)]
struct __NodeModule {
version: i32,
flags: u32,
dso_handle: *mut u8,
filename: *const u8,
register_func: Option<extern "C" fn(
$crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8)>,
context_register_func: Option<extern "C" fn(
$crate::handle::Handle<$crate::types::JsObject>, *mut u8, *mut u8, *mut u8)>,
modname: *const u8,
priv_data: *mut u8,
link: *mut __NodeModule
}
#[cfg_attr(test, used)]
static mut __NODE_MODULE: __NodeModule = __NodeModule {
version: 0,
flags: 0,
dso_handle: 0 as *mut _,
filename: b"neon_source.rs\0" as *const u8,
register_func: Some(__register_neon_module),
context_register_func: None,
modname: b"neon_module\0" as *const u8,
priv_data: 0 as *mut _,
link: 0 as *mut _
};
extern "C" fn __register_neon_module(
m: $crate::handle::Handle<$crate::types::JsObject>, _: *mut u8, _: *mut u8) {
$crate::macro_internal::initialize_module(m, __init_neon_module);
}
extern "C" {
fn node_module_register(module: *mut __NodeModule);
}
#[cfg(not(feature = "default-panic-hook"))]
::std::panic::set_hook(::std::boxed::Box::new(|_| { }));
#[cfg(not(test))]
unsafe {
__NODE_MODULE.version = $crate::macro_internal::runtime::module::get_version();
node_module_register(&mut __NODE_MODULE);
}
}
__load_neon_module
};
}
}
#[cfg(feature = "legacy-runtime")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! class_definition {
( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; init($cx:pat) $body:block $($rest:tt)* ) => {
class_definition!($cls ;
$cname ;
$typ ;
{
fn _______allocator_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsUndefined>) -> $crate::result::NeonResult<$typ> {
$body
}
$crate::macro_internal::AllocateCallback(_______allocator_rust_y_u_no_hygienic_items_______)
} ;
$call_ctor ;
$new_ctor ;
$mnames ;
$mdefs ;
$($rest)*);
};
( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; ($($mname:tt)*) ; ($($mdef:tt)*) ; method $name:ident($cx:pat) $body:block $($rest:tt)* ) => {
class_definition!($cls ;
$cname ;
$typ ;
$allocator ;
$call_ctor ;
$new_ctor ;
($($mname)* $name) ;
($($mdef)* {
fn _______method_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::JsResult<$crate::types::JsValue> {
$body
}
$crate::macro_internal::MethodCallback(_______method_rust_y_u_no_hygienic_items_______)
}) ;
$($rest)*);
};
( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; constructor($cx:pat) $body:block $($rest:tt)* ) => {
class_definition!($cls ;
$cname ;
$typ ;
$allocator ;
$call_ctor ;
({
fn _______constructor_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$cls>) -> $crate::result::NeonResult<Option<$crate::handle::Handle<$crate::types::JsObject>>> {
$body
}
$crate::macro_internal::ConstructCallback(_______constructor_rust_y_u_no_hygienic_items_______)
}) ;
$mnames ;
$mdefs ;
$($rest)*);
};
( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:tt ; $call_ctor:tt ; $new_ctor:tt ; $mnames:tt ; $mdefs:tt ; call($cx:pat) $body:block $($rest:tt)* ) => {
class_definition!($cls ;
$cname ;
$typ ;
$allocator ;
({
fn _______call_rust_y_u_no_hygienic_items_______($cx: $crate::context::CallContext<$crate::types::JsValue>) -> $crate::result::JsResult<$crate::types::JsValue> {
$body
}
$crate::macro_internal::ConstructorCallCallback(_______call_rust_y_u_no_hygienic_items_______)
}) ;
$new_ctor ;
$mnames ;
$mdefs ;
$($rest)*);
};
( $cls:ident ; $cname:ident ; $typ:ty ; $allocator:block ; ($($call_ctor:block)*) ; ($($new_ctor:block)*) ; ($($mname:ident)*) ; ($($mdef:block)*) ; $($rest:tt)* ) => {
impl $crate::object::Class for $cls {
type Internals = $typ;
fn setup<'a, C: $crate::context::Context<'a>>(_: &mut C) -> $crate::result::NeonResult<$crate::object::ClassDescriptor<'a, Self>> {
::std::result::Result::Ok(Self::describe(neon_stringify!($cname), $allocator)
$(.construct($new_ctor))*
$(.call($call_ctor))*
$(.method(neon_stringify!($mname), $mdef))*)
}
}
};
}
#[cfg(feature = "legacy-runtime")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_managed {
($cls:ident) => {
unsafe impl $crate::macro_internal::TransparentNoCopyWrapper for $cls {
type Inner = $crate::macro_internal::runtime::raw::Local;
fn into_inner(self) -> Self::Inner {
self.0
}
}
impl $crate::handle::Managed for $cls {
fn to_raw(&self) -> $crate::macro_internal::runtime::raw::Local {
self.0
}
fn from_raw(
_env: neon::macro_internal::Env,
raw: $crate::macro_internal::runtime::raw::Local,
) -> Self {
$cls(raw)
}
}
};
}
#[cfg(feature = "legacy-runtime")]
#[macro_export(local_inner_macros)]
macro_rules! declare_types {
{ $(#[$attr:meta])* pub class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
declare_types! { $(#[$attr])* pub class $cls as $typ for $typ { $($body)* } $($rest)* }
};
{ $(#[$attr:meta])* class $cls:ident for $typ:ident { $($body:tt)* } $($rest:tt)* } => {
declare_types! { $(#[$attr])* class $cls as $typ for $typ { $($body)* } $($rest)* }
};
{ $(#[$attr:meta])* pub class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
#[derive(Debug)]
#[repr(transparent)]
$(#[$attr])*
pub struct $cls($crate::macro_internal::runtime::raw::Local);
impl_managed!($cls);
class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);
declare_types! { $($rest)* }
};
{ $(#[$attr:meta])* class $cls:ident as $cname:ident for $typ:ty { $($body:tt)* } $($rest:tt)* } => {
#[derive(Copy, Clone)]
#[repr(C)]
$(#[$attr])*
struct $cls($crate::macro_internal::runtime::raw::Local);
impl_managed!($cls);
class_definition!($cls ; $cname ; $typ ; () ; () ; () ; () ; () ; $($body)*);
declare_types! { $($rest)* }
};
{ } => { };
}
#[cfg(feature = "legacy-runtime")]
#[doc(hidden)]
#[macro_export]
macro_rules! neon_stringify {
($($inner:tt)*) => {
stringify! { $($inner)* }
}
}
#[cfg(test)]
mod tests {
use lazy_static::lazy_static;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Mutex;
lazy_static! {
static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
}
fn project_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).to_path_buf()
}
fn log(test_name: &str) {
eprintln!("======================================================");
eprintln!("Neon test: {}", test_name);
eprintln!("======================================================");
}
fn run(cmd: &str, dir: &Path) {
let (shell, command_flag) = if cfg!(windows) {
("cmd", "/C")
} else {
("sh", "-c")
};
eprintln!("Running Neon test: {} {} {}", shell, command_flag, cmd);
assert!(Command::new(&shell)
.current_dir(dir)
.args(&[&command_flag, cmd])
.status()
.unwrap_or_else(|_| panic!(
"failed to execute test command: {} {} {}",
shell, command_flag, cmd
))
.success());
}
fn static_test_impl() {
let _guard = TEST_MUTEX.lock();
log("static_test");
run("cargo test", &project_root().join("test").join("static"));
}
#[rustversion::beta]
#[cfg(feature = "enable-static-tests")]
#[test]
fn static_test() {
static_test_impl()
}
#[rustversion::beta]
#[cfg(not(feature = "enable-static-tests"))]
#[test]
#[ignore]
fn static_test() {
static_test_impl()
}
#[rustversion::not(beta)]
#[cfg(feature = "enable-static-tests")]
compile_error!(
"The `enable-static-tests` feature can only be enabled with the Rust beta toolchain."
);
#[rustversion::not(beta)]
#[test]
#[ignore]
fn static_test() {
static_test_impl()
}
#[test]
#[ignore]
fn package_test() {
let _guard = TEST_MUTEX.lock();
log("package_test");
let test_package = project_root().join("crates").join("neon-runtime");
if std::env::var("CI") == Ok("true".to_string()) {
run("cargo package", &test_package);
} else {
run("cargo package --allow-dirty", &test_package);
}
}
}