Skip to content

Commit

Permalink
Merge pull request #456 from Qqwy/whereis_pid
Browse files Browse the repository at this point in the history
Adds Env.whereis_pid
  • Loading branch information
evnu authored May 30, 2022
2 parents 170c218 + a8b7993 commit a880bb3
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 0 deletions.
35 changes: 35 additions & 0 deletions rustler/src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,41 @@ impl<'a> Env<'a> {
}
}

/// Attempts to find the PID of a process registered by `name_or_pid`
///
/// Safe wrapper around [`enif_whereis_pid`](https://www.erlang.org/doc/man/erl_nif.html#enif_whereis_pid).
///
/// # Returns
/// - `Some(pid)` if `name_or_pid` is already a PID.
/// - `Some(pid)` if `name_or_pid` is an atom and an alive process is currently registered under the given name.
/// - `None` if `name_or_pid` is an atom but there is no alive process registered under this name.
/// - `None` if `name_or_pid` is not a PID or atom.
pub fn whereis_pid(&self, name_or_pid: Term<'a>) -> Option<LocalPid> {
if name_or_pid.is_pid() {
return Some(name_or_pid.decode().unwrap());
}

let mut enif_pid = std::mem::MaybeUninit::uninit();

if unsafe {
rustler_sys::enif_whereis_pid(
self.as_c_arg(),
name_or_pid.as_c_arg(),
enif_pid.as_mut_ptr(),
)
} == 0
{
// If `name_or_pid` is not an atom, or not the name of a registered process
None
} else {
// Safety: Initialized by successful enif_whereis_pid call
let enif_pid = unsafe { enif_pid.assume_init() };

let pid = LocalPid::from_c_arg(enif_pid);
Some(pid)
}
}

/// Decodes binary data to a term.
///
/// Follows the erlang
Expand Down
4 changes: 4 additions & 0 deletions rustler/src/types/local_pid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ impl LocalPid {
pub fn as_c_arg(&self) -> &ErlNifPid {
&self.c
}

pub fn from_c_arg(erl_nif_pid: ErlNifPid) -> Self {
LocalPid { c: erl_nif_pid }
}
}

impl<'a> Decoder<'a> for LocalPid {
Expand Down
1 change: 1 addition & 0 deletions rustler_tests/lib/rustler_test.ex
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ defmodule RustlerTest do
def threaded_sleep(_), do: err()

def send_all(_, _), do: err()
def whereis_pid(_), do: err()
def sublists(_), do: err()

def tuple_echo(_), do: err()
Expand Down
1 change: 1 addition & 0 deletions rustler_tests/native/rustler_test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ rustler::init!(
test_thread::threaded_fac,
test_thread::threaded_sleep,
test_env::send_all,
test_env::whereis_pid,
test_env::sublists,
test_codegen::tuple_echo,
test_codegen::record_echo,
Expand Down
6 changes: 6 additions & 0 deletions rustler_tests/native/rustler_test/src/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ pub fn send_all<'a>(env: Env<'a>, pids: Vec<LocalPid>, msg: Term<'a>) -> Term<'a
msg
}

#[rustler::nif]
pub fn whereis_pid<'a>(env: Env<'a>, term: Term<'a>) -> Term<'a> {
let result = env.whereis_pid(term);
result.encode(env)
}

#[rustler::nif]
pub fn sublists<'a>(env: Env<'a>, list: Term<'a>) -> NifResult<Atom> {
// This is a "threaded NIF": it spawns a thread that sends a message back
Expand Down
10 changes: 10 additions & 0 deletions rustler_tests/test/env_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,14 @@ defmodule RustlerTest.EnvTest do
]
end
end

test "whereis_pid" do
assert self() == RustlerTest.whereis_pid(self())

{:ok, agent_pid} = Agent.start(fn -> 42 end, name: MyAgentName)
assert agent_pid == RustlerTest.whereis_pid(MyAgentName)

assert nil == RustlerTest.whereis_pid("not a PID")
assert nil == RustlerTest.whereis_pid(:not_a_registered_name)
end
end

0 comments on commit a880bb3

Please sign in to comment.