Skip to content

Commit

Permalink
Add resource dyncall support
Browse files Browse the repository at this point in the history
  • Loading branch information
filmor committed Aug 5, 2024
1 parent d7e8e53 commit adcecd0
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 2 deletions.
23 changes: 23 additions & 0 deletions rustler/src/resource/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,29 @@ impl<'a> Env<'a> {
pub fn demonitor<T: Resource>(&self, resource: &ResourceArc<T>, mon: &Monitor) -> bool {
resource.demonitor(Some(*self), mon)
}

#[cfg(feature = "nif_version_2_16")]
pub unsafe fn dynamic_resource_call(
self,
module: crate::Atom,
name: crate::Atom,
resource: Term<'a>,
call_data: *mut rustler_sys::c_void,
) -> Result<(), super::DynamicResourceCallError> {
let res = rustler_sys::enif_dynamic_resource_call(
self.as_c_arg(),
module.as_c_arg(),
name.as_c_arg(),
resource.as_c_arg(),
call_data,
);

if res == 0 {
Ok(())
} else {
Err(super::DynamicResourceCallError)
}
}
}

impl<T> Deref for ResourceArc<T>
Expand Down
5 changes: 5 additions & 0 deletions rustler/src/resource/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/// Indicates that a resource has not been registered successfully
#[derive(Clone, Copy, Debug)]
pub struct ResourceInitError;

/// Indicates that a dynamic resource call failed
#[allow(dead_code)]
#[derive(Clone, Copy, Debug)]
pub struct DynamicResourceCallError;
2 changes: 1 addition & 1 deletion rustler/src/resource/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod traits;
mod util;

pub use arc::ResourceArc;
pub use error::ResourceInitError;
pub use error::*;
pub use monitor::Monitor;
pub use registration::Registration;
pub use traits::Resource;
Expand Down
52 changes: 51 additions & 1 deletion rustler/src/resource/registration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl Registration {
}
.maybe_add_destructor_callback::<T>()
.maybe_add_down_callback::<T>()
.maybe_add_dyncall_callback::<T>()
}

pub const fn with_name(self, name: &'static str) -> Self {
Expand Down Expand Up @@ -104,6 +105,28 @@ impl Registration {
}
}

#[cfg(not(feature = "nif_version_2_16"))]
#[allow(clippy::extra_unused_type_parameters)]
const fn maybe_add_dyncall_callback<T: Resource>(self) -> Self {
self
}

#[cfg(feature = "nif_version_2_16")]
const fn maybe_add_dyncall_callback<T: Resource>(self) -> Self {
if T::IMPLEMENTS_DYNCALL {
Self {
init: ErlNifResourceTypeInit {
dyncall: resource_dyncall::<T> as *const rustler_sys::ErlNifResourceDynCall,
members: max(self.init.members, 4),
..self.init
},
..self
}
} else {
self
}
}

/// Try to register the resource type for which this registration was created. This function
/// will only succeed when called from the `load` callback and if this type has not yet been
/// registered.
Expand Down Expand Up @@ -162,6 +185,19 @@ unsafe extern "C" fn resource_down<T: Resource>(
res.down(env, pid, mon);
}

#[cfg(feature = "nif_version_2_16")]
unsafe extern "C" fn resource_dyncall<T: Resource>(
env: *mut ErlNifEnv,
obj: *mut c_void,
call_data: *mut c_void,
) {
let env = Env::new_internal(&env, env, EnvKind::Callback);
let aligned = align_alloced_mem_for_struct::<T>(obj);
let res = &*(aligned as *const T);

res.dyncall(env, call_data);
}

pub unsafe fn open_resource_type(
env: *mut ErlNifEnv,
name: &[u8],
Expand All @@ -175,7 +211,7 @@ pub unsafe fn open_resource_type(

let res = {
let mut tried = MaybeUninit::uninit();
rustler_sys::enif_open_resource_type_x(env, name_p, &init, flags, tried.as_mut_ptr())
OPEN_RESOURCE_TYPE(env, name_p, &init, flags, tried.as_mut_ptr())
};

if res.is_null() {
Expand All @@ -185,6 +221,20 @@ pub unsafe fn open_resource_type(
}
}

type OpenResourceTypeFn = unsafe extern "C" fn(
*mut ErlNifEnv,
*const c_char,
*const ErlNifResourceTypeInit,
ErlNifResourceFlags,
*mut ErlNifResourceFlags,
) -> *const ErlNifResourceType;

#[cfg(feature = "nif_version_2_16")]
static OPEN_RESOURCE_TYPE: OpenResourceTypeFn = rustler_sys::enif_init_resource_type;

#[cfg(not(feature = "nif_version_2_16"))]
static OPEN_RESOURCE_TYPE: OpenResourceTypeFn = rustler_sys::enif_open_resource_type_x;

const fn max(i: i32, j: i32) -> i32 {
if i > j {
i
Expand Down
7 changes: 7 additions & 0 deletions rustler/src/resource/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ pub trait Resource: Sized + Send + Sync + 'static {
const IMPLEMENTS_DESTRUCTOR: bool = false;
const IMPLEMENTS_DOWN: bool = false;

#[cfg(feature = "nif_version_2_16")]
const IMPLEMENTS_DYNCALL: bool = false;

/// Callback function that is executed right before dropping a resource object.
///
/// This callback does not have to be implemented to release associated resources or run
Expand All @@ -51,6 +54,10 @@ pub trait Resource: Sized + Send + Sync + 'static {
/// by `ResourceArc<T>::monitor`.
#[allow(unused)]
fn down<'a>(&'a self, env: Env<'a>, pid: LocalPid, monitor: Monitor) {}

#[cfg(feature = "nif_version_2_16")]
#[allow(unused)]
unsafe fn dyncall<'a>(&'a self, env: Env<'a>, call_data: *mut rustler_sys::c_void) {}
}

#[doc(hidden)]
Expand Down

0 comments on commit adcecd0

Please sign in to comment.