Skip to content

Commit 88c6e15

Browse files
authored
Merge pull request #581 from rusterlium/ps-fix-get_term_type-for-integers
Fix Term's "get_type()" implementation
2 parents 30a5e5a + 63ec23c commit 88c6e15

File tree

8 files changed

+70
-6
lines changed

8 files changed

+70
-6
lines changed

UPGRADE.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ This document is intended to simplify upgrading to newer versions by extending t
1919
See also
2020
[enif\_send](https://www.erlang.org/doc/man/erl_nif.html#enif_send).
2121

22-
3. As `Term::get_type` is now implemented using `enif_get_type`, some cases of
23-
the `TermType` `enum` are changed, removed, or added:
22+
3. As `Term::get_type` is now implemented using `enif_get_type` on all
23+
non-Windows systems, some cases of the `TermType` `enum` are changed,
24+
removed, or added (on all systems):
2425
1. `EmptyList` is dropped, `List` is returned for both empty and non-empty
2526
lists
2627
2. `Exception` is dropped

rustler/src/dynamic.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ffi::c_double;
2+
13
#[cfg(feature = "nif_version_2_15")]
24
use rustler_sys::ErlNifTermType;
35

@@ -43,7 +45,7 @@ impl From<ErlNifTermType> for TermType {
4345
}
4446

4547
pub fn get_type(term: Term) -> TermType {
46-
if cfg!(nif_version_2_15) {
48+
if cfg!(feature = "nif_version_2_15") && !cfg!(target_family = "windows") {
4749
term.get_erl_type().into()
4850
} else if term.is_atom() {
4951
TermType::Atom
@@ -56,7 +58,11 @@ pub fn get_type(term: Term) -> TermType {
5658
} else if term.is_map() {
5759
TermType::Map
5860
} else if term.is_number() {
59-
TermType::Float
61+
if term.is_float() {
62+
TermType::Float
63+
} else {
64+
TermType::Integer
65+
}
6066
} else if term.is_pid() {
6167
TermType::Pid
6268
} else if term.is_port() {
@@ -98,4 +104,15 @@ impl<'a> Term<'a> {
98104
impl_check!(is_port);
99105
impl_check!(is_ref);
100106
impl_check!(is_tuple);
107+
108+
pub fn is_float(self) -> bool {
109+
let mut val: c_double = 0.0;
110+
unsafe {
111+
rustler_sys::enif_get_double(self.get_env().as_c_arg(), self.as_c_arg(), &mut val) == 1
112+
}
113+
}
114+
115+
pub fn is_integer(self) -> bool {
116+
self.is_number() && !self.is_float()
117+
}
101118
}

rustler/src/term.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ impl<'a> Term<'a> {
124124

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

rustler_sys/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ fn build_api(b: &mut dyn ApiBuilder, opts: &GenerateOptions) {
848848
b.func(
849849
"ErlNifTermType",
850850
"enif_term_type",
851-
"env: *mut ErlNifEnv, term: *const ERL_NIF_TERM",
851+
"env: *mut ErlNifEnv, term: ERL_NIF_TERM",
852852
);
853853

854854
b.func("c_int", "enif_is_pid_undefined", "pid: *const ErlNifPid");

rustler_tests/lib/rustler_test.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ defmodule RustlerTest do
4747
def term_cmp(_, _), do: err()
4848
def term_internal_hash(_, _), do: err()
4949
def term_phash2_hash(_), do: err()
50+
def term_type(_term), do: err()
5051

5152
def sum_map_values(_), do: err()
5253
def map_entries_sorted(_), do: err()

rustler_tests/native/rustler_test/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ rustler::init!(
3030
test_term::term_cmp,
3131
test_term::term_internal_hash,
3232
test_term::term_phash2_hash,
33+
test_term::term_type,
3334
test_map::sum_map_values,
3435
test_map::map_entries_sorted,
3536
test_map::map_from_arrays,

rustler_tests/native/rustler_test/src/test_term.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ mod atoms {
77
equal,
88
less,
99
greater,
10+
// Term types
11+
atom,
12+
binary,
13+
float,
14+
fun,
15+
integer,
16+
list,
17+
map,
18+
pid,
19+
port,
20+
reference,
21+
tuple,
22+
unknown,
1023
}
1124
}
1225

@@ -40,3 +53,21 @@ pub fn term_internal_hash(term: Term, salt: u32) -> u32 {
4053
pub fn term_phash2_hash(term: Term) -> u32 {
4154
term.hash_phash2()
4255
}
56+
57+
#[rustler::nif]
58+
pub fn term_type(term: Term) -> Atom {
59+
match term.get_type() {
60+
rustler::TermType::Atom => atoms::atom(),
61+
rustler::TermType::Binary => atoms::binary(),
62+
rustler::TermType::Fun => atoms::fun(),
63+
rustler::TermType::List => atoms::list(),
64+
rustler::TermType::Map => atoms::map(),
65+
rustler::TermType::Integer => atoms::integer(),
66+
rustler::TermType::Float => atoms::float(),
67+
rustler::TermType::Pid => atoms::pid(),
68+
rustler::TermType::Port => atoms::port(),
69+
rustler::TermType::Ref => atoms::reference(),
70+
rustler::TermType::Tuple => atoms::tuple(),
71+
rustler::TermType::Unknown => atoms::unknown(),
72+
}
73+
}

rustler_tests/test/term_test.exs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,17 @@ defmodule RustlerTest.TermTest do
6767

6868
assert unique > 50
6969
end
70+
71+
test "term type" do
72+
assert RustlerTest.term_type(:foo) == :atom
73+
assert RustlerTest.term_type("foo") == :binary
74+
assert RustlerTest.term_type(42.2) == :float
75+
assert RustlerTest.term_type(42) == :integer
76+
assert RustlerTest.term_type(%{}) == :map
77+
assert RustlerTest.term_type([]) == :list
78+
assert RustlerTest.term_type({:ok, 42}) == :tuple
79+
assert RustlerTest.term_type(self()) == :pid
80+
assert RustlerTest.term_type(& &1) == :fun
81+
assert RustlerTest.term_type(make_ref()) == :reference
82+
end
7083
end

0 commit comments

Comments
 (0)