-module(themis@number). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/themis/number.gleam"). -export([integer/1, decimal/1, positive_infinity/0, negative_infinity/0, not_a_number/0, compare/2, unsafe_compare/2, add/2, print/1]). -export_type([comparison_error/0, number_/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. -type comparison_error() :: na_n_value. -type number_() :: pos_inf | neg_inf | na_n | {dec, float()} | {int, integer()}. -file("src/themis/number.gleam", 21). ?DOC(" Creates a Number representing an integer value.\n"). -spec integer(integer()) -> number_(). integer(Value) -> {int, Value}. -file("src/themis/number.gleam", 26). ?DOC(" Creates a Number representing a decimal value.\n"). -spec decimal(float()) -> number_(). decimal(Value) -> {dec, Value}. -file("src/themis/number.gleam", 31). ?DOC(" Creates a Number representing positive infinity.\n"). -spec positive_infinity() -> number_(). positive_infinity() -> pos_inf. -file("src/themis/number.gleam", 36). ?DOC(" Creates a Number representing negative infinity.\n"). -spec negative_infinity() -> number_(). negative_infinity() -> neg_inf. -file("src/themis/number.gleam", 41). ?DOC(" Creates a Number representing NaN (Not a Number).\n"). -spec not_a_number() -> number_(). not_a_number() -> na_n. -file("src/themis/number.gleam", 47). ?DOC( " Compare two numbers (see gleam_stdlib/order)\n" " Will return an error if either value is NaN\n" ). -spec compare(number_(), number_()) -> {ok, gleam@order:order()} | {error, comparison_error()}. compare(Val1, Val2) -> case {Val1, Val2} of {V1, V2} when V1 =:= V2 -> {ok, eq}; {{int, V1@1}, {int, V2@1}} -> {ok, gleam@int:compare(V1@1, V2@1)}; {{dec, V1@2}, {dec, V2@2}} -> {ok, gleam@float:compare(V1@2, V2@2)}; {pos_inf, _} -> {ok, gt}; {neg_inf, _} -> {ok, lt}; {_, pos_inf} -> {ok, lt}; {_, neg_inf} -> {ok, gt}; {{dec, D}, {int, I}} -> {ok, gleam@float:compare(D, erlang:float(I))}; {{int, I@1}, {dec, D@1}} -> {ok, gleam@float:compare(erlang:float(I@1), D@1)}; {na_n, _} -> {error, na_n_value}; {_, na_n} -> {error, na_n_value} end. -file("src/themis/number.gleam", 67). ?DOC( " Compare two numbers (see gleam_stdlib/order)\n" " Will panic if either value is NaN\n" ). -spec unsafe_compare(number_(), number_()) -> gleam@order:order(). unsafe_compare(Val1, Val2) -> case compare(Val1, Val2) of {error, _} -> erlang:error(#{gleam_error => panic, message => <<"cannot compare NaN"/utf8>>, file => <>, module => <<"themis/number"/utf8>>, function => <<"unsafe_compare"/utf8>>, line => 69}); {ok, R} -> R end. -file("src/themis/number.gleam", 77). ?DOC( " Add two numbers.\n" " Any `NaN` input value will always return `NaN`.\n" " `PosInf` + `NegInf` = `NaN`\n" ). -spec add(number_(), number_()) -> number_(). add(Val1, Val2) -> case {Val1, Val2} of {na_n, _} -> na_n; {_, na_n} -> na_n; {{int, First}, {int, Second}} -> {int, First + Second}; {{dec, First@1}, {dec, Second@1}} -> {dec, gleam@float:add(First@1, Second@1)}; {{dec, Dec}, {int, Int}} -> {dec, gleam@float:add(erlang:float(Int), Dec)}; {{int, Int}, {dec, Dec}} -> {dec, gleam@float:add(erlang:float(Int), Dec)}; {pos_inf, neg_inf} -> na_n; {neg_inf, pos_inf} -> na_n; {pos_inf, _} -> pos_inf; {_, pos_inf} -> pos_inf; {neg_inf, _} -> neg_inf; {_, neg_inf} -> neg_inf end. -file("src/themis/number.gleam", 91). ?DOC(" Prometheus-scrapable representation of a number\n"). -spec print(number_()) -> binary(). print(Number) -> case Number of {dec, Val} -> gleam_stdlib:float_to_string(Val); {int, Val@1} -> erlang:integer_to_binary(Val@1); na_n -> <<"NaN"/utf8>>; neg_inf -> <<"-Inf"/utf8>>; pos_inf -> <<"+Inf"/utf8>> end.