Skip to content

Commit

Permalink
Refactor Resources (#617)
Browse files Browse the repository at this point in the history
* Refactor resources

- Move storage of "Type->NIF Resource Type Handle" to a OnceLock map to
  allow implementing resource types without resorting to dynamic trait
  implementations
- Add direct access methods to get an immutable reference to the wrapped
  objects
- Add corresponding converters
- Add monitor resource implementation
- Require explicit trait implementation (not when using the existing
  macro for compatibility)
- Allow implementing a "destructor" function that runs just before
  `Drop` but has access to the caller environment
* Update documentation and changelog
  • Loading branch information
filmor committed Jul 7, 2024
1 parent 7fef3c5 commit 6101085
Show file tree
Hide file tree
Showing 24 changed files with 767 additions and 382 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,19 @@ versions.

### Added

- Resource type registration has been refactored to eventually remove the
`rustler::resource!` macro (#617, necessary due to a pending deprecation of a
Rust feature, #606)
- Resources can (and should) now explicitly implement the new `Resource` trait
and provide a custom `destructor` function that is run before `drop` and
receives an `Env` parameter (#617)
- Process monitoring via resources can now be used on resource types that
implement the `Resource::down` callback (#617)

### Fixed

- Unwinding in the `on_load` callback is now caught and leads to a panic (#617)

### Changed

- NIF implementations are now discovered automatically and the respective
Expand Down
3 changes: 3 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ This document is intended to simplify upgrading to newer versions by extending t
2. The functionality related to the `derive` feature is now unconditionally
active. The feature flag is kept for compatibility for now but will be
removed in the future.
3. To register a type as a resource, the new `#[derive(Resource)]` can be used
now. It is implicitly registered and does not require (or work in) the old
explicit registration with `rustler::resource!` a custom `load` function.

## 0.32 -> 0.33

Expand Down
15 changes: 6 additions & 9 deletions rustler/src/codegen_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use inventory;
pub use crate::wrapper::exception::raise_exception;
pub use crate::wrapper::{
c_char, c_int, c_uint, c_void, get_nif_resource_type_init_size, DEF_NIF_ENTRY, DEF_NIF_FUNC,
MUTABLE_NIF_RESOURCE_HANDLE, NIF_ENV, NIF_MAJOR_VERSION, NIF_MINOR_VERSION, NIF_TERM,
NIF_ENV, NIF_MAJOR_VERSION, NIF_MINOR_VERSION, NIF_TERM,
};

#[cfg(windows)]
Expand Down Expand Up @@ -100,15 +100,12 @@ impl fmt::Debug for NifReturned {
/// # Unsafe
///
/// This takes arguments, including raw pointers, that must be correct.
pub unsafe fn handle_nif_init_call(
function: Option<for<'a> fn(Env<'a>, Term<'a>) -> bool>,
r_env: NIF_ENV,
load_info: NIF_TERM,
pub unsafe fn handle_nif_init_call<'a>(
function: for<'b> fn(Env<'b>, Term<'b>) -> bool,
env: Env<'a>,
load_info: Term<'a>,
) -> c_int {
let env = Env::new(&(), r_env);
let term = Term::new(env, load_info);

function.map_or(0, |inner| i32::from(!inner(env, term)))
std::panic::catch_unwind(|| function(env, load_info)).map_or(1, |x| i32::from(!x))
}

pub fn handle_nif_result<T>(
Expand Down
12 changes: 11 additions & 1 deletion rustler/src/env.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::thread::is_scheduler_thread;
use crate::types::LocalPid;
use crate::wrapper::{NIF_ENV, NIF_TERM};
use crate::{Encoder, Term};
Expand All @@ -17,6 +18,7 @@ type EnvId<'a> = PhantomData<*mut &'a u8>;
/// There is no way to allocate a Env at the moment, but this may be possible in the future.
#[derive(Clone, Copy)]
pub struct Env<'a> {
pub(crate) init: bool,
env: NIF_ENV,
id: EnvId<'a>,
}
Expand Down Expand Up @@ -47,11 +49,19 @@ impl<'a> Env<'a> {
/// Don't create multiple `Env`s with the same lifetime.
pub unsafe fn new<T>(_lifetime_marker: &'a T, env: NIF_ENV) -> Env<'a> {
Env {
init: false,
env,
id: PhantomData,
}
}

#[doc(hidden)]
pub unsafe fn new_init_env<T>(_lifetime_marker: &'a T, env: NIF_ENV) -> Env<'a> {
let mut res = Self::new(_lifetime_marker, env);
res.init = true;
res
}

pub fn as_c_arg(self) -> NIF_ENV {
self.env
}
Expand Down Expand Up @@ -229,7 +239,7 @@ impl OwnedEnv {
F: FnOnce(Env<'a>) -> T,
T: Encoder,
{
if unsafe { rustler_sys::enif_thread_type() } != rustler_sys::ERL_NIF_THR_UNDEFINED {
if is_scheduler_thread() {
panic!("send_and_clear: current thread is managed");
}

Expand Down
4 changes: 2 additions & 2 deletions rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ pub use crate::types::{
#[cfg(feature = "big_integer")]
pub use crate::types::BigInt;

pub mod resource;
pub use crate::resource::ResourceArc;
mod resource;
pub use crate::resource::{Monitor, Resource, ResourceArc, ResourceInitError};

#[doc(hidden)]
pub mod dynamic;
Expand Down
Loading

0 comments on commit 6101085

Please sign in to comment.