Skip to content

Commit 9398a9f

Browse files
committed
Introduce context::ffi
1 parent 0638b78 commit 9398a9f

File tree

3 files changed

+74
-23
lines changed

3 files changed

+74
-23
lines changed

src/context/ffi.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use super::internal::{ContextInternal, Env, Scope, ScopeMetadata};
2+
use super::Context;
3+
use neon_runtime::raw;
4+
5+
/// Opaque type representing the underlying env of a context
6+
///
7+
/// See `Context::with_raw_env` for details.
8+
#[repr(C)]
9+
pub struct RawEnv {
10+
// Create opaque type as suggested in https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
11+
_data: [u8; 0],
12+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
13+
}
14+
15+
impl RawEnv {
16+
/// Creates a context in the env
17+
pub fn with_context<T, F>(&mut self, f: F) -> T
18+
where
19+
F: for<'b> FnOnce(RawContext<'b>) -> T,
20+
{
21+
let env = unsafe { std::mem::transmute(self) };
22+
RawContext::with(env, f)
23+
}
24+
}
25+
26+
pub struct RawContext<'a> {
27+
scope: Scope<'a, raw::HandleScope>,
28+
}
29+
30+
impl<'a> ContextInternal<'a> for RawContext<'a> {
31+
fn scope_metadata(&self) -> &ScopeMetadata {
32+
&self.scope.metadata
33+
}
34+
}
35+
36+
impl<'a> Context<'a> for RawContext<'a> {}
37+
38+
impl<'a> RawContext<'a> {
39+
fn with<T, F>(env: Env, f: F) -> T
40+
where
41+
F: for<'b> FnOnce(RawContext<'b>) -> T,
42+
{
43+
Scope::with(env, |scope| f(RawContext { scope }))
44+
}
45+
}

src/context/mod.rs

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@
146146
//! [iterator]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
147147
//! [question-mark]: https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
148148
149+
#[cfg(feature = "napi-1")]
150+
pub mod ffi;
149151
pub(crate) mod internal;
150152

151153
use crate::borrow::internal::Ledger;
@@ -181,6 +183,8 @@ use std::marker::PhantomData;
181183
use std::os::raw::c_void;
182184
use std::panic::UnwindSafe;
183185

186+
#[cfg(feature = "napi-1")]
187+
use self::ffi::RawEnv;
184188
use self::internal::{ContextInternal, Scope, ScopeMetadata};
185189

186190
#[repr(C)]
@@ -294,10 +298,21 @@ impl<'a> Lock<'a> {
294298
///
295299
/// A context has a lifetime `'a`, which ensures the safety of handles managed by the JS garbage collector. All handles created during the lifetime of a context are kept alive for that duration and cannot outlive the context.
296300
pub trait Context<'a>: ContextInternal<'a> {
297-
/// Get the underlying `napi-env` of the context
301+
/// Gets the underlying env handle of the context
302+
///
303+
/// RawEnv is an opaque C struct, so `&mut RawEnv` is allowed to be converted to a `*mut void`, passed
304+
/// across FFI boundaries, and converted back to `&mut RawEnv`.
298305
#[cfg(feature = "napi-1")]
299-
fn as_mut_ptr(&mut self) -> *mut c_void {
300-
self.env().to_raw() as *mut c_void
306+
fn with_raw_env<T, F>(&mut self, f: F) -> T
307+
where
308+
F: for<'b> FnOnce(&'b mut RawEnv) -> T,
309+
{
310+
self.check_active();
311+
self.deactivate();
312+
let raw_env = unsafe { &mut *(self.env().to_raw().cast::<RawEnv>()) };
313+
let result = f(raw_env);
314+
self.activate();
315+
result
301316
}
302317

303318
/// Lock the JavaScript engine, returning an RAII guard that keeps the lock active as long as the guard is alive.
@@ -824,20 +839,7 @@ impl<'a> TaskContext<'a> {
824839
Scope::with(env, |scope| f(TaskContext { scope }))
825840
}
826841

827-
/// Constructs a context from a raw pointer.
828-
///
829-
/// # Safety
830-
/// The raw pointer `env` must be a `napi_env` that remains valid during the call of this method.
831-
#[cfg(feature = "napi-1")]
832-
pub unsafe fn with_raw_env<T, F: for<'b> FnOnce(TaskContext<'b>) -> T>(
833-
env: *mut c_void,
834-
f: F,
835-
) -> T {
836-
let env = std::mem::transmute(env);
837-
Self::with_context(env, f)
838-
}
839-
840-
#[cfg(feature = "napi-1")]
842+
#[cfg(all(feature = "napi-4", feature = "channel-api"))]
841843
pub(crate) fn with_context<T, F: for<'b> FnOnce(TaskContext<'b>) -> T>(env: Env, f: F) -> T {
842844
Scope::with(env, |scope| f(TaskContext { scope }))
843845
}

test/napi/src/lib.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ use js::objects::*;
2525
use js::strings::*;
2626
use js::threads::*;
2727
use js::types::*;
28+
use neon::context::ffi::RawEnv;
29+
use std::os::raw::c_void;
2830

2931
#[neon::main]
3032
fn main(mut cx: ModuleContext) -> NeonResult<()> {
@@ -107,13 +109,15 @@ fn main(mut cx: ModuleContext) -> NeonResult<()> {
107109
.collect::<Result<Vec<_>, _>>()?;
108110
assert_eq!(property_names, &["0", "a", "whatever"]);
109111

110-
let raw_env = cx.as_mut_ptr();
111-
let forty_two = unsafe {
112-
TaskContext::with_raw_env(raw_env, |mut cx| {
113-
let forty_two = cx.number(42);
114-
forty_two.value(&mut cx) as u8
112+
let forty_two = cx.with_raw_env(|mut env| {
113+
let env_ptr = env as *mut RawEnv as *mut c_void;
114+
let env = unsafe { &mut *(env_ptr.cast::<RawEnv>()) };
115+
env.with_context(|mut cx| {
116+
let num = cx.number(42);
117+
num.value(&mut cx) as u8
115118
})
116-
};
119+
});
120+
117121
assert_eq!(forty_two, 42);
118122

119123
cx.export_value("rustCreated", rust_created)?;

0 commit comments

Comments
 (0)