Skip to content

Commit

Permalink
Add reference type and make_ref call
Browse files Browse the repository at this point in the history
  • Loading branch information
filmor committed Oct 13, 2024
1 parent 348f3fd commit 5dd58c5
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 4 deletions.
2 changes: 1 addition & 1 deletion rustler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ mod term;
pub use crate::term::Term;
pub use crate::types::{
Atom, Binary, Decoder, Encoder, ErlOption, ListIterator, LocalPid, MapIterator, NewBinary,
OwnedBinary,
OwnedBinary, Reference,
};

#[cfg(feature = "big_integer")]
Expand Down
9 changes: 7 additions & 2 deletions rustler/src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ use crate::{Env, Error, NifResult, Term};

#[macro_use]
pub mod atom;
pub mod i128;
pub mod path;
pub use crate::types::atom::Atom;

pub mod binary;
Expand Down Expand Up @@ -32,6 +30,13 @@ pub mod tuple;
pub mod local_pid;
pub use self::local_pid::LocalPid;

#[doc(hidden)]
pub mod reference;
pub use self::reference::Reference;

pub mod i128;
pub mod path;

pub mod truthy;

pub mod elixir_struct;
Expand Down
52 changes: 52 additions & 0 deletions rustler/src/types/reference.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use std::ops::Deref;

use crate::{Decoder, Encoder, Env, Error, NifResult, Term};

use crate::sys::enif_make_ref;

#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Reference<'a>(Term<'a>);

impl<'a> Deref for Reference<'a> {
type Target = Term<'a>;

fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<'a> Into<Term<'a>> for Reference<'a> {
fn into(self) -> Term<'a> {
self.0
}
}

impl<'a> TryFrom<Term<'a>> for Reference<'a> {
type Error = Error;

fn try_from(term: Term<'a>) -> Result<Self, Self::Error> {
if term.is_ref() {
Ok(Reference(term))
} else {
Err(Error::BadArg)
}
}
}

impl<'a> Decoder<'a> for Reference<'a> {
fn decode(term: Term<'a>) -> NifResult<Self> {
term.try_into()
}
}

impl<'a> Encoder for Reference<'a> {
fn encode<'b>(&self, env: Env<'b>) -> Term<'b> {
self.0.encode(env)
}
}

impl<'a> Env<'a> {
pub fn make_ref(self) -> Reference<'a> {
unsafe { Reference(Term::new(self, enif_make_ref(self.as_c_arg()))) }
}
}
1 change: 1 addition & 0 deletions rustler_tests/lib/rustler_test.ex
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ defmodule RustlerTest do
def whereis_pid(_), do: err()
def is_process_alive(_), do: err()
def sublists(_), do: err()
def make_refs(), do: err()

def tuple_echo(_), do: err()
def record_echo(_), do: err()
Expand Down
9 changes: 8 additions & 1 deletion rustler_tests/native/rustler_test/src/test_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use rustler::env::{OwnedEnv, SavedTerm, SendError};
use rustler::types::atom;
use rustler::types::list::ListIterator;
use rustler::types::LocalPid;
use rustler::{Atom, Encoder, Env, NifResult, Term};
use rustler::{Atom, Encoder, Env, NifResult, Reference, Term};
use std::thread;

// Send a message to several PIDs.
Expand Down Expand Up @@ -84,3 +84,10 @@ pub fn sublists<'a>(env: Env<'a>, list: Term<'a>) -> NifResult<Atom> {

Ok(atom::ok())
}

#[rustler::nif]
fn make_refs<'a>(env: Env<'a>) -> (bool, Reference<'a>, Reference<'a>) {
let first = env.make_ref();
let second = env.make_ref();
(first != second, first, second)
}
9 changes: 9 additions & 0 deletions rustler_tests/test/env_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,13 @@ defmodule RustlerTest.EnvTest do
assert :error == RustlerTest.send(task.pid, :msg)
assert :error == RustlerTest.send(task.pid, :msg)
end

test "make_ref" do
{different, ref1, ref2} = RustlerTest.make_refs()

assert different
assert is_reference(ref1)
assert is_reference(ref2)
assert ref1 != ref2
end
end

0 comments on commit 5dd58c5

Please sign in to comment.