Skip to content

Commit

Permalink
Merge pull request #581 from rusterlium/ps-fix-get_term_type-for-inte…
Browse files Browse the repository at this point in the history
…gers

Fix Term's "get_type()" implementation
  • Loading branch information
filmor authored Feb 13, 2024
2 parents 30a5e5a + 63ec23c commit 88c6e15
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 6 deletions.
5 changes: 3 additions & 2 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ This document is intended to simplify upgrading to newer versions by extending t
See also
[enif\_send](https://www.erlang.org/doc/man/erl_nif.html#enif_send).

3. As `Term::get_type` is now implemented using `enif_get_type`, some cases of
the `TermType` `enum` are changed, removed, or added:
3. As `Term::get_type` is now implemented using `enif_get_type` on all
non-Windows systems, some cases of the `TermType` `enum` are changed,
removed, or added (on all systems):
1. `EmptyList` is dropped, `List` is returned for both empty and non-empty
lists
2. `Exception` is dropped
Expand Down
21 changes: 19 additions & 2 deletions rustler/src/dynamic.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::ffi::c_double;

#[cfg(feature = "nif_version_2_15")]
use rustler_sys::ErlNifTermType;

Expand Down Expand Up @@ -43,7 +45,7 @@ impl From<ErlNifTermType> for TermType {
}

pub fn get_type(term: Term) -> TermType {
if cfg!(nif_version_2_15) {
if cfg!(feature = "nif_version_2_15") && !cfg!(target_family = "windows") {
term.get_erl_type().into()
} else if term.is_atom() {
TermType::Atom
Expand All @@ -56,7 +58,11 @@ pub fn get_type(term: Term) -> TermType {
} else if term.is_map() {
TermType::Map
} else if term.is_number() {
TermType::Float
if term.is_float() {
TermType::Float
} else {
TermType::Integer
}
} else if term.is_pid() {
TermType::Pid
} else if term.is_port() {
Expand Down Expand Up @@ -98,4 +104,15 @@ impl<'a> Term<'a> {
impl_check!(is_port);
impl_check!(is_ref);
impl_check!(is_tuple);

pub fn is_float(self) -> bool {
let mut val: c_double = 0.0;
unsafe {
rustler_sys::enif_get_double(self.get_env().as_c_arg(), self.as_c_arg(), &mut val) == 1
}
}

pub fn is_integer(self) -> bool {
self.is_number() && !self.is_float()
}
}
2 changes: 1 addition & 1 deletion rustler/src/term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl<'a> Term<'a> {

#[cfg(feature = "nif_version_2_15")]
pub fn get_erl_type(&self) -> rustler_sys::ErlNifTermType {
unsafe { rustler_sys::enif_term_type(self.env.as_c_arg(), &self.as_c_arg()) }
unsafe { rustler_sys::enif_term_type(self.env.as_c_arg(), self.as_c_arg()) }
}
}

Expand Down
2 changes: 1 addition & 1 deletion rustler_sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ fn build_api(b: &mut dyn ApiBuilder, opts: &GenerateOptions) {
b.func(
"ErlNifTermType",
"enif_term_type",
"env: *mut ErlNifEnv, term: *const ERL_NIF_TERM",
"env: *mut ErlNifEnv, term: ERL_NIF_TERM",
);

b.func("c_int", "enif_is_pid_undefined", "pid: *const ErlNifPid");
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 @@ -47,6 +47,7 @@ defmodule RustlerTest do
def term_cmp(_, _), do: err()
def term_internal_hash(_, _), do: err()
def term_phash2_hash(_), do: err()
def term_type(_term), do: err()

def sum_map_values(_), do: err()
def map_entries_sorted(_), 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 @@ -30,6 +30,7 @@ rustler::init!(
test_term::term_cmp,
test_term::term_internal_hash,
test_term::term_phash2_hash,
test_term::term_type,
test_map::sum_map_values,
test_map::map_entries_sorted,
test_map::map_from_arrays,
Expand Down
31 changes: 31 additions & 0 deletions rustler_tests/native/rustler_test/src/test_term.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ mod atoms {
equal,
less,
greater,
// Term types
atom,
binary,
float,
fun,
integer,
list,
map,
pid,
port,
reference,
tuple,
unknown,
}
}

Expand Down Expand Up @@ -40,3 +53,21 @@ pub fn term_internal_hash(term: Term, salt: u32) -> u32 {
pub fn term_phash2_hash(term: Term) -> u32 {
term.hash_phash2()
}

#[rustler::nif]
pub fn term_type(term: Term) -> Atom {
match term.get_type() {
rustler::TermType::Atom => atoms::atom(),
rustler::TermType::Binary => atoms::binary(),
rustler::TermType::Fun => atoms::fun(),
rustler::TermType::List => atoms::list(),
rustler::TermType::Map => atoms::map(),
rustler::TermType::Integer => atoms::integer(),
rustler::TermType::Float => atoms::float(),
rustler::TermType::Pid => atoms::pid(),
rustler::TermType::Port => atoms::port(),
rustler::TermType::Ref => atoms::reference(),
rustler::TermType::Tuple => atoms::tuple(),
rustler::TermType::Unknown => atoms::unknown(),
}
}
13 changes: 13 additions & 0 deletions rustler_tests/test/term_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,17 @@ defmodule RustlerTest.TermTest do

assert unique > 50
end

test "term type" do
assert RustlerTest.term_type(:foo) == :atom
assert RustlerTest.term_type("foo") == :binary
assert RustlerTest.term_type(42.2) == :float
assert RustlerTest.term_type(42) == :integer
assert RustlerTest.term_type(%{}) == :map
assert RustlerTest.term_type([]) == :list
assert RustlerTest.term_type({:ok, 42}) == :tuple
assert RustlerTest.term_type(self()) == :pid
assert RustlerTest.term_type(& &1) == :fun
assert RustlerTest.term_type(make_ref()) == :reference
end
end

0 comments on commit 88c6e15

Please sign in to comment.