From 5dd58c558258512b662c060959a419805025cf62 Mon Sep 17 00:00:00 2001 From: Benedikt Reinartz Date: Sun, 13 Oct 2024 08:54:23 +0200 Subject: [PATCH] Add reference type and `make_ref` call --- rustler/src/lib.rs | 2 +- rustler/src/types/mod.rs | 9 +++- rustler/src/types/reference.rs | 52 +++++++++++++++++++ rustler_tests/lib/rustler_test.ex | 1 + .../native/rustler_test/src/test_env.rs | 9 +++- rustler_tests/test/env_test.exs | 9 ++++ 6 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 rustler/src/types/reference.rs diff --git a/rustler/src/lib.rs b/rustler/src/lib.rs index d1335526..159e7dc7 100644 --- a/rustler/src/lib.rs +++ b/rustler/src/lib.rs @@ -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")] diff --git a/rustler/src/types/mod.rs b/rustler/src/types/mod.rs index 52c141cf..c3f11ced 100644 --- a/rustler/src/types/mod.rs +++ b/rustler/src/types/mod.rs @@ -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; @@ -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; diff --git a/rustler/src/types/reference.rs b/rustler/src/types/reference.rs new file mode 100644 index 00000000..bdce7f5c --- /dev/null +++ b/rustler/src/types/reference.rs @@ -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> for Reference<'a> { + fn into(self) -> Term<'a> { + self.0 + } +} + +impl<'a> TryFrom> for Reference<'a> { + type Error = Error; + + fn try_from(term: Term<'a>) -> Result { + if term.is_ref() { + Ok(Reference(term)) + } else { + Err(Error::BadArg) + } + } +} + +impl<'a> Decoder<'a> for Reference<'a> { + fn decode(term: Term<'a>) -> NifResult { + 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()))) } + } +} diff --git a/rustler_tests/lib/rustler_test.ex b/rustler_tests/lib/rustler_test.ex index b2c2232f..bfebade6 100644 --- a/rustler_tests/lib/rustler_test.ex +++ b/rustler_tests/lib/rustler_test.ex @@ -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() diff --git a/rustler_tests/native/rustler_test/src/test_env.rs b/rustler_tests/native/rustler_test/src/test_env.rs index 06dd63d6..99f9da4f 100644 --- a/rustler_tests/native/rustler_test/src/test_env.rs +++ b/rustler_tests/native/rustler_test/src/test_env.rs @@ -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. @@ -84,3 +84,10 @@ pub fn sublists<'a>(env: Env<'a>, list: Term<'a>) -> NifResult { 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) +} diff --git a/rustler_tests/test/env_test.exs b/rustler_tests/test/env_test.exs index 29c06acc..6e016bbd 100644 --- a/rustler_tests/test/env_test.exs +++ b/rustler_tests/test/env_test.exs @@ -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