Skip to content

Commit

Permalink
Add a test for dyncall
Browse files Browse the repository at this point in the history
  • Loading branch information
filmor committed Aug 2, 2024
1 parent 756cc57 commit e3f9059
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ members = [
"rustler_tests/native/rustler_serde_test",
"rustler_tests/native/dynamic_load",
"rustler_tests/native/rustler_compile_tests",
"rustler_tests/native/resource_dyncall",
"rustler_benchmarks/native/benchmark",
]
default-members = [
Expand Down
4 changes: 4 additions & 0 deletions rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@ pub mod serde;

#[cfg(feature = "serde")]
pub use crate::serde::SerdeTerm;

pub mod sys {
pub use rustler_sys::*;
}
11 changes: 11 additions & 0 deletions rustler_tests/lib/resource_dyncall.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
if System.otp_release() >= "26" do
defmodule ResourceDyncall do
use Rustler,
otp_app: :rustler_test,
crate: :resource_dyncall

def new(_), do: err()

defp err(), do: :erlang.nif_error(:nif_not_loaded)
end
end
4 changes: 4 additions & 0 deletions rustler_tests/lib/rustler_test.ex
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,8 @@ defmodule RustlerTest do
def greeting_person_from_tuple(_tuple), do: err()

def append_to_path(_path, _to_append), do: err()

if System.otp_release() >= "26" do
def perform_dyncall(_res, _a, _b, _c), do: err()
end
end
11 changes: 11 additions & 0 deletions rustler_tests/native/resource_dyncall/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "resource_dyncall"
version = "0.1.0"
edition = "2021"

[lib]
name = "resource_dyncall"
crate-type = ["cdylib"]

[dependencies]
rustler = { path = "../../../rustler", features = ["allocator", "nif_version_2_16"] }
32 changes: 32 additions & 0 deletions rustler_tests/native/resource_dyncall/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use rustler::{Env, LocalPid, Resource, ResourceArc};

#[repr(C)]
struct Params {
a: i64,
b: i64,
c: i64,
sent_to: Option<LocalPid>,
}

struct ResourceWithDyncall {
pid: LocalPid,
}

#[rustler::resource_impl(name = "resource_with_dyncall")]
impl Resource for ResourceWithDyncall {
unsafe fn dyncall<'a>(&'a self, env: Env<'a>, call_data: *mut rustler::sys::c_void) {
let p = &mut *(call_data as *mut Params);
if let Ok(()) = env.send(&self.pid, (p.a, p.b, p.c)) {
p.sent_to = Some(self.pid);
} else {
p.sent_to = None
}
}
}

#[rustler::nif]
fn new(pid: LocalPid) -> ResourceArc<ResourceWithDyncall> {
ResourceWithDyncall { pid }.into()
}

rustler::init!("Elixir.ResourceDyncall");
2 changes: 2 additions & 0 deletions rustler_tests/native/rustler_test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ mod test_resource;
mod test_term;
mod test_thread;
mod test_tuple;
// #[cfg(feature = "nif_version_2_16")]
mod test_dyncall;

// Intentional usage of the explicit form (in an "invalid" way, listing a wrong set of functions) to ensure that the warning stays alive
rustler::init!("Elixir.RustlerTest", [deprecated, usage], load = load);
Expand Down
37 changes: 37 additions & 0 deletions rustler_tests/native/rustler_test/src/test_dyncall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use rustler::{Env, LocalPid, Term};

rustler::atoms! {
module = "Elixir.ResourceDyncall",
resource_name = "resource_with_dyncall",
}

#[repr(C)]
struct Params {
a: i64,
b: i64,
c: i64,
sent_to: Option<LocalPid>,
}

#[rustler::nif]
pub fn perform_dyncall<'a>(
env: Env<'a>,
resource: Term<'a>,
a: i64,
b: i64,
c: i64,
) -> Option<LocalPid> {
let mut params = Params {
a,
b,
c,
sent_to: None,
};

unsafe {
let params_ptr = std::ptr::addr_of_mut!(params) as *mut rustler::sys::c_void;
let _ = env.dynamic_resource_call(module(), resource_name(), resource, params_ptr);
}

params.sent_to
}
22 changes: 22 additions & 0 deletions rustler_tests/test/resource_dyncall_tests.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
if System.otp_release() >= "26" do
defmodule RustlerTest.ResourceDyncallTest do
use ExUnit.Case, async: true

test "perform dyncall" do
pid = self()

res = ResourceDyncall.new(pid)

call_res = RustlerTest.perform_dyncall(res, 1, 2, 3)

assert call_res == pid

receive do
{1, 2, 3} -> true
after
50 ->
raise "fail"
end
end
end
end

0 comments on commit e3f9059

Please sign in to comment.