From a51baaa206bbbb084a7b9568e1f391fc4722762e Mon Sep 17 00:00:00 2001 From: Andrew Mayorov Date: Thu, 8 Jun 2023 14:42:20 +0300 Subject: [PATCH] refactor(pluglib): move conversion utils to `emqx_utils_conv` --- .../src/emqx_bridge_influxdb_connector.erl | 4 +- .../src/emqx_bridge_kafka_impl_consumer.erl | 2 +- .../src/emqx_bridge_kafka_impl_producer.erl | 2 +- .../src/emqx_bridge_pulsar_impl_producer.erl | 2 +- .../src/emqx_bridge_sqlserver_connector.erl | 2 +- apps/emqx_oracle/src/emqx_oracle.erl | 10 +- .../src/emqx_plugin_libs_rule.erl | 41 +----- .../test/emqx_plugin_libs_rule_SUITE.erl | 23 +--- apps/emqx_rule_engine/src/emqx_rule_funcs.erl | 40 +++--- apps/emqx_rule_engine/src/emqx_rule_maps.erl | 2 +- .../test/emqx_rule_funcs_SUITE.erl | 6 +- apps/emqx_utils/src/emqx_placeholder.erl | 4 +- apps/emqx_utils/src/emqx_utils_conv.erl | 125 ++++++++++++++++++ .../emqx_utils/test/emqx_utils_conv_tests.erl | 44 ++++++ 14 files changed, 215 insertions(+), 92 deletions(-) create mode 100644 apps/emqx_utils/src/emqx_utils_conv.erl create mode 100644 apps/emqx_utils/test/emqx_utils_conv_tests.erl diff --git a/apps/emqx_bridge_influxdb/src/emqx_bridge_influxdb_connector.erl b/apps/emqx_bridge_influxdb/src/emqx_bridge_influxdb_connector.erl index 71ab85c58..adf61918a 100644 --- a/apps/emqx_bridge_influxdb/src/emqx_bridge_influxdb_connector.erl +++ b/apps/emqx_bridge_influxdb/src/emqx_bridge_influxdb_connector.erl @@ -637,7 +637,7 @@ value_type(Val) -> Val. key_filter(undefined) -> undefined; -key_filter(Value) -> emqx_plugin_libs_rule:bin(Value). +key_filter(Value) -> emqx_utils_conv:bin(Value). data_filter(undefined) -> undefined; data_filter(Int) when is_integer(Int) -> Int; @@ -645,7 +645,7 @@ data_filter(Number) when is_number(Number) -> Number; data_filter(Bool) when is_boolean(Bool) -> Bool; data_filter(Data) -> bin(Data). -bin(Data) -> emqx_plugin_libs_rule:bin(Data). +bin(Data) -> emqx_utils_conv:bin(Data). %% helper funcs log_error_points(InstId, Errs) -> diff --git a/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_consumer.erl b/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_consumer.erl index 9d03d53f9..a95e67b8d 100644 --- a/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_consumer.erl +++ b/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_consumer.erl @@ -556,7 +556,7 @@ render(FullMessage, PayloadTemplate) -> (undefined) -> <<>>; (X) -> - emqx_plugin_libs_rule:bin(X) + emqx_utils_conv:bin(X) end }, emqx_placeholder:proc_tmpl(PayloadTemplate, FullMessage, Opts). diff --git a/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_producer.erl b/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_producer.erl index cb8427cc5..2d48c788b 100644 --- a/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_producer.erl +++ b/apps/emqx_bridge_kafka/src/emqx_bridge_kafka_impl_producer.erl @@ -255,7 +255,7 @@ render(Template, Message) -> Opts = #{ var_trans => fun (undefined) -> <<"">>; - (X) -> emqx_plugin_libs_rule:bin(X) + (X) -> emqx_utils_conv:bin(X) end, return => full_binary }, diff --git a/apps/emqx_bridge_pulsar/src/emqx_bridge_pulsar_impl_producer.erl b/apps/emqx_bridge_pulsar/src/emqx_bridge_pulsar_impl_producer.erl index 0b5885c16..133b98710 100644 --- a/apps/emqx_bridge_pulsar/src/emqx_bridge_pulsar_impl_producer.erl +++ b/apps/emqx_bridge_pulsar/src/emqx_bridge_pulsar_impl_producer.erl @@ -435,7 +435,7 @@ render(Message, Template) -> Opts = #{ var_trans => fun (undefined) -> <<"">>; - (X) -> emqx_plugin_libs_rule:bin(X) + (X) -> emqx_utils_conv:bin(X) end, return => full_binary }, diff --git a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl index edd8770f5..cb0c0e16e 100644 --- a/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl +++ b/apps/emqx_bridge_sqlserver/src/emqx_bridge_sqlserver_connector.erl @@ -44,7 +44,7 @@ %% Internal exports used to execute code with ecpool worker -export([do_get_status/1, worker_do_insert/3]). --import(emqx_plugin_libs_rule, [str/1]). +-import(emqx_utils_conv, [str/1]). -import(hoconsc, [mk/2, enum/1, ref/2]). -define(ACTION_SEND_MESSAGE, send_message). diff --git a/apps/emqx_oracle/src/emqx_oracle.erl b/apps/emqx_oracle/src/emqx_oracle.erl index 5d80c0d56..d6fd51847 100644 --- a/apps/emqx_oracle/src/emqx_oracle.erl +++ b/apps/emqx_oracle/src/emqx_oracle.erl @@ -93,14 +93,14 @@ on_start( ServiceName = case maps:get(service_name, Config, undefined) of undefined -> undefined; - ServiceName0 -> emqx_plugin_libs_rule:str(ServiceName0) + ServiceName0 -> emqx_utils_conv:str(ServiceName0) end, Options = [ {host, Host}, {port, Port}, - {user, emqx_plugin_libs_rule:str(User)}, + {user, emqx_utils_conv:str(User)}, {password, jamdb_secret:wrap(maps:get(password, Config, ""))}, - {sid, emqx_plugin_libs_rule:str(Sid)}, + {sid, emqx_utils_conv:str(Sid)}, {service_name, ServiceName}, {pool_size, maps:get(<<"pool_size">>, Config, ?DEFAULT_POOL_SIZE)}, {timeout, ?OPT_TIMEOUT}, @@ -268,14 +268,14 @@ connect(Opts) -> jamdb_oracle:start_link(Opts). sql_query_to_str(SqlQuery) -> - emqx_plugin_libs_rule:str(SqlQuery). + emqx_utils_conv:str(SqlQuery). sql_params_to_str(Params) when is_list(Params) -> lists:map( fun (false) -> "0"; (true) -> "1"; - (Value) -> emqx_plugin_libs_rule:str(Value) + (Value) -> emqx_utils_conv:str(Value) end, Params ). diff --git a/apps/emqx_plugin_libs/src/emqx_plugin_libs_rule.erl b/apps/emqx_plugin_libs/src/emqx_plugin_libs_rule.erl index fd792310b..aa9e38316 100644 --- a/apps/emqx_plugin_libs/src/emqx_plugin_libs_rule.erl +++ b/apps/emqx_plugin_libs/src/emqx_plugin_libs_rule.erl @@ -27,8 +27,6 @@ %% type converting -export([ - str/1, - bin/1, bool/1, int/1, float/1, @@ -36,7 +34,6 @@ map/1, utf8_bin/1, utf8_str/1, - number_to_binary/1, atom_key/1, unsafe_atom_key/1 ]). @@ -172,39 +169,15 @@ tcp_connectivity(Host, Port, Timeout) -> {error, Reason} end. -str(Bin) when is_binary(Bin) -> binary_to_list(Bin); -str(Num) when is_number(Num) -> number_to_list(Num); -str(Atom) when is_atom(Atom) -> atom_to_list(Atom); -str(Map) when is_map(Map) -> binary_to_list(emqx_utils_json:encode(Map)); -str(List) when is_list(List) -> - case io_lib:printable_list(List) of - true -> List; - false -> binary_to_list(emqx_utils_json:encode(List)) - end; -str(Data) -> - error({invalid_str, Data}). - utf8_bin(Str) when is_binary(Str); is_list(Str) -> unicode:characters_to_binary(Str); utf8_bin(Str) -> - unicode:characters_to_binary(bin(Str)). + unicode:characters_to_binary(emqx_utils_conv:bin(Str)). utf8_str(Str) when is_binary(Str); is_list(Str) -> unicode:characters_to_list(Str); utf8_str(Str) -> - unicode:characters_to_list(str(Str)). - -bin(Bin) when is_binary(Bin) -> Bin; -bin(Num) when is_number(Num) -> number_to_binary(Num); -bin(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8); -bin(Map) when is_map(Map) -> emqx_utils_json:encode(Map); -bin(List) when is_list(List) -> - case io_lib:printable_list(List) of - true -> list_to_binary(List); - false -> emqx_utils_json:encode(List) - end; -bin(Data) -> - error({invalid_bin, Data}). + unicode:characters_to_list(emqx_utils_conv:str(Str)). int(List) when is_list(List) -> try @@ -274,13 +247,3 @@ bool(Bool) when false; bool(Bool) -> error({invalid_boolean, Bool}). - -number_to_binary(Int) when is_integer(Int) -> - integer_to_binary(Int); -number_to_binary(Float) when is_float(Float) -> - float_to_binary(Float, [{decimals, 10}, compact]). - -number_to_list(Int) when is_integer(Int) -> - integer_to_list(Int); -number_to_list(Float) when is_float(Float) -> - float_to_list(Float, [{decimals, 10}, compact]). diff --git a/apps/emqx_plugin_libs/test/emqx_plugin_libs_rule_SUITE.erl b/apps/emqx_plugin_libs/test/emqx_plugin_libs_rule_SUITE.erl index bf509f362..bb1ba838b 100644 --- a/apps/emqx_plugin_libs/test/emqx_plugin_libs_rule_SUITE.erl +++ b/apps/emqx_plugin_libs/test/emqx_plugin_libs_rule_SUITE.erl @@ -28,11 +28,11 @@ all() -> emqx_common_test_helpers:all(?MODULE). t_http_connectivity(_) -> {ok, Socket} = gen_tcp:listen(?PORT, []), ok = emqx_plugin_libs_rule:http_connectivity( - "http://127.0.0.1:" ++ emqx_plugin_libs_rule:str(?PORT), 1000 + "http://127.0.0.1:" ++ integer_to_list(?PORT), 1000 ), gen_tcp:close(Socket), {error, _} = emqx_plugin_libs_rule:http_connectivity( - "http://127.0.0.1:" ++ emqx_plugin_libs_rule:str(?PORT), 1000 + "http://127.0.0.1:" ++ integer_to_list(?PORT), 1000 ). t_tcp_connectivity(_) -> @@ -41,25 +41,6 @@ t_tcp_connectivity(_) -> gen_tcp:close(Socket), {error, _} = emqx_plugin_libs_rule:tcp_connectivity("127.0.0.1", ?PORT, 1000). -t_str(_) -> - ?assertEqual("abc", emqx_plugin_libs_rule:str("abc")), - ?assertEqual("abc", emqx_plugin_libs_rule:str(abc)), - ?assertEqual("{\"a\":1}", emqx_plugin_libs_rule:str(#{a => 1})), - ?assertEqual("1", emqx_plugin_libs_rule:str(1)), - ?assertEqual("2.0", emqx_plugin_libs_rule:str(2.0)), - ?assertEqual("true", emqx_plugin_libs_rule:str(true)), - ?assertError(_, emqx_plugin_libs_rule:str({a, v})). - -t_bin(_) -> - ?assertEqual(<<"abc">>, emqx_plugin_libs_rule:bin("abc")), - ?assertEqual(<<"abc">>, emqx_plugin_libs_rule:bin(abc)), - ?assertEqual(<<"{\"a\":1}">>, emqx_plugin_libs_rule:bin(#{a => 1})), - ?assertEqual(<<"[{\"a\":1}]">>, emqx_plugin_libs_rule:bin([#{a => 1}])), - ?assertEqual(<<"1">>, emqx_plugin_libs_rule:bin(1)), - ?assertEqual(<<"2.0">>, emqx_plugin_libs_rule:bin(2.0)), - ?assertEqual(<<"true">>, emqx_plugin_libs_rule:bin(true)), - ?assertError(_, emqx_plugin_libs_rule:bin({a, v})). - t_atom_key(_) -> _ = erlang, _ = port, diff --git a/apps/emqx_rule_engine/src/emqx_rule_funcs.erl b/apps/emqx_rule_engine/src/emqx_rule_funcs.erl index a94aa0c8a..de9bf0485 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_funcs.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_funcs.erl @@ -17,7 +17,6 @@ -module(emqx_rule_funcs). -include("rule_engine.hrl"). --include_lib("emqx/include/emqx.hrl"). -include_lib("emqx/include/logger.hrl"). -elvis([{elvis_style, god_modules, disable}]). @@ -266,8 +265,6 @@ ]} ). --define(is_var(X), is_binary(X)). - %% @doc "msgid()" Func msgid() -> fun @@ -631,29 +628,42 @@ do_get_subbits(Bits, Sz, Len, <<"bits">>, <<"signed">>, <<"little">>) -> %%------------------------------------------------------------------------------ str(Data) -> - emqx_plugin_libs_rule:bin(Data). + emqx_utils_conv:bin(Data). +str_utf8(Data) when is_binary(Data); is_list(Data) -> + unicode:characters_to_binary(Data); str_utf8(Data) -> - emqx_plugin_libs_rule:utf8_bin(Data). + unicode:characters_to_binary(str(Data)). bool(Data) -> - emqx_plugin_libs_rule:bool(Data). + emqx_utils_conv:bool(Data). int(Data) -> - emqx_plugin_libs_rule:int(Data). + emqx_utils_conv:int(Data). float(Data) -> - emqx_plugin_libs_rule:float(Data). + emqx_utils_conv:float(Data). float(Data, Decimals) when Decimals > 0 -> - Data1 = ?MODULE:float(Data), + Data1 = emqx_utils_conv:float(Data), list_to_float(float_to_list(Data1, [{decimals, Decimals}])). float2str(Float, Precision) -> - emqx_plugin_libs_rule:float2str(Float, Precision). + float_to_binary(Float, [{decimals, Precision}, compact]). +map(Bin) when is_binary(Bin) -> + case emqx_utils_json:decode(Bin) of + Map = #{} -> + Map; + _ -> + error(badarg, [Bin]) + end; +map(List) when is_list(List) -> + maps:from_list(List); +map(Map = #{}) -> + Map; map(Data) -> - emqx_plugin_libs_rule:map(Data). + error(badarg, [Data]). bin2hexstr(Bin) when is_binary(Bin) -> emqx_utils:bin_to_hexstr(Bin, upper). @@ -895,7 +905,7 @@ mget(Key, Map, Default) -> Val; error when is_atom(Key) -> %% the map may have an equivalent binary-form key - BinKey = emqx_plugin_libs_rule:bin(Key), + BinKey = emqx_utils_conv:bin(Key), case maps:find(BinKey, Map) of {ok, Val} -> Val; error -> Default @@ -922,7 +932,7 @@ mput(Key, Val, Map) -> maps:put(Key, Val, Map); error when is_atom(Key) -> %% the map may have an equivalent binary-form key - BinKey = emqx_plugin_libs_rule:bin(Key), + BinKey = emqx_utils_conv:bin(Key), case maps:find(BinKey, Map) of {ok, _} -> maps:put(BinKey, Val, Map); error -> maps:put(Key, Val, Map) @@ -1053,7 +1063,7 @@ unix_ts_to_rfc3339(Epoch) -> unix_ts_to_rfc3339(Epoch, <<"second">>). unix_ts_to_rfc3339(Epoch, Unit) when is_integer(Epoch) -> - emqx_plugin_libs_rule:bin( + emqx_utils_conv:bin( calendar:system_time_to_rfc3339( Epoch, [{unit, time_unit(Unit)}] ) @@ -1090,7 +1100,7 @@ format_date(TimeUnit, Offset, FormatString) -> format_date(TimeUnit, Offset, FormatString, TimeEpoch) -> Unit = time_unit(TimeUnit), - emqx_plugin_libs_rule:bin( + emqx_utils_conv:bin( lists:concat( emqx_calendar:format(TimeEpoch, Unit, Offset, FormatString) ) diff --git a/apps/emqx_rule_engine/src/emqx_rule_maps.erl b/apps/emqx_rule_engine/src/emqx_rule_maps.erl index 3dfffca46..baf83ff6f 100644 --- a/apps/emqx_rule_engine/src/emqx_rule_maps.erl +++ b/apps/emqx_rule_engine/src/emqx_rule_maps.erl @@ -97,7 +97,7 @@ general_find({key, Key}, Map, _OrgData, Handler) when is_map(Map) -> Handler({found, {{key, Key}, Val}}); error when is_atom(Key) -> %% the map may have an equivalent binary-form key - BinKey = emqx_plugin_libs_rule:bin(Key), + BinKey = atom_to_binary(Key), case maps:find(BinKey, Map) of {ok, Val} -> Handler({equivalent, {{key, BinKey}, Val}}); error -> Handler(not_found) diff --git a/apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl b/apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl index 12110b206..6e67f6cd1 100644 --- a/apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl +++ b/apps/emqx_rule_engine/test/emqx_rule_funcs_SUITE.erl @@ -126,7 +126,7 @@ t_int(_) -> ?assertEqual(1, emqx_rule_funcs:int(1.0001)), ?assertEqual(1, emqx_rule_funcs:int(true)), ?assertEqual(0, emqx_rule_funcs:int(false)), - ?assertError({invalid_number, {a, v}}, emqx_rule_funcs:int({a, v})), + ?assertError(badarg, emqx_rule_funcs:int({a, v})), ?assertError(_, emqx_rule_funcs:int("a")). t_float(_) -> @@ -137,7 +137,7 @@ t_float(_) -> ?assertEqual(1.9, emqx_rule_funcs:float(1.9)), ?assertEqual(1.0001, emqx_rule_funcs:float(1.0001)), ?assertEqual(1.0000000001, emqx_rule_funcs:float(1.0000000001)), - ?assertError({invalid_number, {a, v}}, emqx_rule_funcs:float({a, v})), + ?assertError(badarg, emqx_rule_funcs:float({a, v})), ?assertError(_, emqx_rule_funcs:float("a")). t_map(_) -> @@ -158,7 +158,7 @@ t_bool(_) -> ?assertEqual(true, emqx_rule_funcs:bool(<<"true">>)), ?assertEqual(false, emqx_rule_funcs:bool(false)), ?assertEqual(false, emqx_rule_funcs:bool(<<"false">>)), - ?assertError({invalid_boolean, _}, emqx_rule_funcs:bool(3)). + ?assertError(badarg, emqx_rule_funcs:bool(3)). t_proc_dict_put_get_del(_) -> ?assertEqual(undefined, emqx_rule_funcs:proc_dict_get(<<"abc">>)), diff --git a/apps/emqx_utils/src/emqx_placeholder.erl b/apps/emqx_utils/src/emqx_placeholder.erl index babac8a84..861548f93 100644 --- a/apps/emqx_utils/src/emqx_placeholder.erl +++ b/apps/emqx_utils/src/emqx_placeholder.erl @@ -112,7 +112,7 @@ proc_tmpl(Tokens, Data) -> -spec proc_tmpl(tmpl_token(), map(), proc_tmpl_opts()) -> binary() | list(). proc_tmpl(Tokens, Data, Opts = #{return := full_binary}) -> - Trans = maps:get(var_trans, Opts, fun emqx_plugin_libs_rule:bin/1), + Trans = maps:get(var_trans, Opts, fun emqx_utils_conv:bin/1), list_to_binary( proc_tmpl(Tokens, Data, #{return => rawlist, var_trans => Trans}) ); @@ -243,7 +243,7 @@ sql_data(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8); sql_data(Map) when is_map(Map) -> emqx_utils_json:encode(Map). -spec bin(term()) -> binary(). -bin(Val) -> emqx_plugin_libs_rule:bin(Val). +bin(Val) -> emqx_utils_conv:bin(Val). -spec quote_sql(_Value) -> iolist(). quote_sql(Str) -> diff --git a/apps/emqx_utils/src/emqx_utils_conv.erl b/apps/emqx_utils/src/emqx_utils_conv.erl new file mode 100644 index 000000000..9879d3a9d --- /dev/null +++ b/apps/emqx_utils/src/emqx_utils_conv.erl @@ -0,0 +1,125 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2017-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_utils_conv). + +-export([bin/1]). +-export([str/1]). +-export([bool/1]). +-export([int/1]). +-export([float/1]). + +-compile({no_auto_import, [float/1]}). + +-type scalar() :: binary() | number() | atom() | string(). + +-spec bin(Term) -> binary() when + Term :: scalar() | #{scalar() => Term} | [Term]. +bin(Bin) when is_binary(Bin) -> Bin; +bin(Num) when is_number(Num) -> number_to_binary(Num); +bin(Atom) when is_atom(Atom) -> atom_to_binary(Atom, utf8); +bin(Map) when is_map(Map) -> emqx_utils_json:encode(Map); +bin(List) when is_list(List) -> + case io_lib:printable_list(List) of + true -> list_to_binary(List); + false -> emqx_utils_json:encode(List) + end; +bin(Data) -> + error({invalid_bin, Data}). + +-spec str(Term) -> string() when + Term :: scalar() | #{scalar() => Term} | [Term]. +str(Bin) when is_binary(Bin) -> binary_to_list(Bin); +str(Num) when is_number(Num) -> number_to_list(Num); +str(Atom) when is_atom(Atom) -> atom_to_list(Atom); +str(Map) when is_map(Map) -> binary_to_list(emqx_utils_json:encode(Map)); +str(List) when is_list(List) -> + case io_lib:printable_list(List) of + true -> List; + false -> binary_to_list(emqx_utils_json:encode(List)) + end; +str(Data) -> + error({invalid_str, Data}). + +-spec number_to_binary(number()) -> binary(). +number_to_binary(Int) when is_integer(Int) -> + integer_to_binary(Int); +number_to_binary(Float) when is_float(Float) -> + float_to_binary(Float, [{decimals, 10}, compact]). + +-spec number_to_list(number()) -> string(). +number_to_list(Int) when is_integer(Int) -> + integer_to_list(Int); +number_to_list(Float) when is_float(Float) -> + float_to_list(Float, [{decimals, 10}, compact]). + +-spec bool(Term) -> boolean() when + Term :: boolean() | binary() | 0..1. +bool(true) -> true; +bool(<<"true">>) -> true; +bool(N) when N == 1 -> true; +bool(false) -> false; +bool(<<"false">>) -> false; +bool(N) when N == 0 -> false; +bool(Data) -> error(badarg, [Data]). + +-spec int(Term) -> integer() when + Term :: binary() | string() | number() | boolean(). +int(List) when is_list(List) -> + try + list_to_integer(List) + catch + error:badarg -> + int(list_to_float(List)) + end; +int(Bin) when is_binary(Bin) -> + try + binary_to_integer(Bin) + catch + error:badarg -> + int(binary_to_float(Bin)) + end; +int(Int) when is_integer(Int) -> + Int; +int(Float) when is_float(Float) -> + erlang:floor(Float); +int(true) -> + 1; +int(false) -> + 0; +int(Data) -> + error(badarg, [Data]). + +-spec float(Term) -> float() when + Term :: binary() | string() | number(). +float(List) when is_list(List) -> + try + list_to_float(List) + catch + error:badarg -> + float(list_to_integer(List)) + end; +float(Bin) when is_binary(Bin) -> + try + binary_to_float(Bin) + catch + error:badarg -> + float(binary_to_integer(Bin)) + end; +float(Num) when is_number(Num) -> + erlang:float(Num); +float(Data) -> + error(badarg, [Data]). diff --git a/apps/emqx_utils/test/emqx_utils_conv_tests.erl b/apps/emqx_utils/test/emqx_utils_conv_tests.erl new file mode 100644 index 000000000..b60467264 --- /dev/null +++ b/apps/emqx_utils/test/emqx_utils_conv_tests.erl @@ -0,0 +1,44 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_utils_conv_tests). + +-import(emqx_utils_conv, [bin/1, str/1]). + +-include_lib("eunit/include/eunit.hrl"). + +bin_test_() -> + [ + ?_assertEqual(<<"abc">>, bin("abc")), + ?_assertEqual(<<"abc">>, bin(abc)), + ?_assertEqual(<<"{\"a\":1}">>, bin(#{a => 1})), + ?_assertEqual(<<"[{\"a\":1}]">>, bin([#{a => 1}])), + ?_assertEqual(<<"1">>, bin(1)), + ?_assertEqual(<<"2.0">>, bin(2.0)), + ?_assertEqual(<<"true">>, bin(true)), + ?_assertError(_, bin({a, v})) + ]. + +str_test_() -> + [ + ?_assertEqual("abc", str("abc")), + ?_assertEqual("abc", str(abc)), + ?_assertEqual("{\"a\":1}", str(#{a => 1})), + ?_assertEqual("1", str(1)), + ?_assertEqual("2.0", str(2.0)), + ?_assertEqual("true", str(true)), + ?_assertError(_, str({a, v})) + ].