Add decoders
This commit is contained in:
parent
75a020f08c
commit
d7ecddda63
6 changed files with 102 additions and 4 deletions
|
@ -1,3 +1,9 @@
|
|||
2.1.0
|
||||
-----
|
||||
|
||||
+ Added a gleam/dynamic Decoder.
|
||||
+ Added a string decoder.
|
||||
|
||||
2.0.0
|
||||
-----
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name = "bigi"
|
||||
version = "2.0.0"
|
||||
version = "2.1.0"
|
||||
|
||||
# Fill out these fields if you intend to generate HTML documentation or publish
|
||||
# your project to the Hex package manager.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import gleam/order
|
||||
import gleam/dynamic
|
||||
|
||||
/// A big integer.
|
||||
pub type BigInt
|
||||
|
@ -9,11 +10,27 @@ pub type BigInt
|
|||
pub fn zero() -> BigInt
|
||||
|
||||
/// Create a big integer from a regular integer.
|
||||
///
|
||||
/// Note that in the JavaScript target, if your integer is bigger than the
|
||||
/// [maximum safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER)
|
||||
/// or smaller than the
|
||||
/// [minimum safe integer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER),
|
||||
/// you may lose precision when operating on it, including when converting it
|
||||
/// into a big integer (as the JavaScript Number type has already reduced the
|
||||
/// precision of the value).
|
||||
@external(erlang, "bigi_ffi", "from")
|
||||
@external(javascript, "./bigi_ffi.mjs", "from")
|
||||
pub fn from_int(int: Int) -> BigInt
|
||||
|
||||
/// Convert the big integer to a regular integer.
|
||||
/// Convert a string into a big integer.
|
||||
///
|
||||
/// If the string does not represent a big integer in base 10, an error is
|
||||
/// returned. Trailing non-digit content is not allowed.
|
||||
@external(erlang, "bigi_ffi", "from_string")
|
||||
@external(javascript, "./bigi_ffi.mjs", "from_string")
|
||||
pub fn from_string(str: String) -> Result(BigInt, Nil)
|
||||
|
||||
/// Convert a big integer to a regular integer.
|
||||
///
|
||||
/// In Erlang, this cannot fail, as all Erlang integers are big integers. In the
|
||||
/// JavaScript target, this will fail if the integer is bigger than the
|
||||
|
@ -123,6 +140,11 @@ pub fn digits(bigint: BigInt) {
|
|||
get_digit(bigint, [], divisor)
|
||||
}
|
||||
|
||||
/// Decode a `gleam/dynamic` value into a big integer, if possible.
|
||||
@external(erlang, "bigi_ffi", "decode")
|
||||
@external(javascript, "./bigi_ffi.mjs", "decode")
|
||||
pub fn decode(dyn: dynamic.Dynamic) -> Result(BigInt, dynamic.DecodeErrors)
|
||||
|
||||
fn get_digit(bigint: BigInt, digits: List(Int), divisor: BigInt) {
|
||||
case compare(bigint, divisor) {
|
||||
order.Gt -> {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
-export([
|
||||
from/1,
|
||||
from_string/1,
|
||||
to/1,
|
||||
zero/0,
|
||||
compare/2,
|
||||
|
@ -14,11 +15,18 @@
|
|||
remainder_no_zero/2,
|
||||
modulo/2,
|
||||
modulo_no_zero/2,
|
||||
power/2
|
||||
power/2,
|
||||
decode/1
|
||||
]).
|
||||
|
||||
from(Int) -> Int.
|
||||
|
||||
from_string(Str) ->
|
||||
case string:to_integer(Str) of
|
||||
{_, Rest} when Rest /= <<"">> -> {error, nil};
|
||||
{Int, _} -> {ok, Int}
|
||||
end.
|
||||
|
||||
to(BigInt) -> {ok, BigInt}.
|
||||
|
||||
zero() -> 0.
|
||||
|
@ -65,3 +73,18 @@ do_power(A, N) ->
|
|||
0 -> 1;
|
||||
1 -> A
|
||||
end).
|
||||
|
||||
decode(Dyn) when is_integer(Dyn) -> {ok, Dyn};
|
||||
decode(Dyn) -> {error, {decode_error, <<"bigint">>, get_type(Dyn), []}}.
|
||||
|
||||
get_type(Val) when is_atom(Val) -> <<"atom">>;
|
||||
get_type(Val) when is_function(Val) -> <<"function">>;
|
||||
get_type(Val) when is_pid(Val) -> <<"pid">>;
|
||||
get_type(Val) when is_binary(Val) -> <<"binary">>;
|
||||
get_type(Val) when is_list(Val) -> <<"list">>;
|
||||
get_type(Val) when is_map(Val) -> <<"map">>;
|
||||
get_type(Val) when is_reference(Val) -> <<"reference">>;
|
||||
get_type(Val) when is_float(Val) -> <<"float">>;
|
||||
get_type(Val) when is_tuple(Val) -> <<"tuple">>;
|
||||
get_type(Val) when is_port(Val) -> <<"port">>;
|
||||
get_type(Val) when is_bitstring(Val) -> <<"bitstring">>.
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
import { Ok, Error } from "./gleam.mjs";
|
||||
import { Ok, Error, toList } from "./gleam.mjs";
|
||||
import { Lt, Eq, Gt } from "../gleam_stdlib/gleam/order.mjs";
|
||||
import { DecodeError } from "../gleam_stdlib/gleam/dynamic.mjs";
|
||||
|
||||
export function from(int) {
|
||||
return BigInt(int);
|
||||
}
|
||||
|
||||
export function from_string(string) {
|
||||
try {
|
||||
return new Ok(BigInt(string));
|
||||
} catch {
|
||||
return new Error(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export function to(bigint) {
|
||||
if (bigint > Number.MAX_SAFE_INTEGER || bigint < Number.MIN_SAFE_INTEGER) {
|
||||
return new Error(undefined);
|
||||
|
@ -106,3 +115,12 @@ export function power(a, b) {
|
|||
|
||||
return new Ok(a ** b);
|
||||
}
|
||||
|
||||
export function decode(dyn) {
|
||||
const dynType = typeof dyn;
|
||||
if (dynType === "bigint") {
|
||||
return new Ok(dyn);
|
||||
} else {
|
||||
return new Error(toList([new DecodeError("bigint", dynType, toList([]))]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import gleam/order
|
||||
import gleam/dynamic
|
||||
import gleeunit
|
||||
import gleeunit/should
|
||||
import bigi
|
||||
|
@ -145,6 +146,34 @@ pub fn negative_exponent_test() {
|
|||
should.be_error(bigint)
|
||||
}
|
||||
|
||||
pub fn dynamic_decoder_test() {
|
||||
let bigint = bigi.from_int(1234)
|
||||
let dyn = dynamic.from(bigint)
|
||||
should.equal(bigi.decode(dyn), Ok(bigint))
|
||||
}
|
||||
|
||||
pub fn dynamic_decoder_fail_test() {
|
||||
let not_bigint = "foo"
|
||||
let dyn = dynamic.from(not_bigint)
|
||||
should.be_error(bigi.decode(dyn))
|
||||
}
|
||||
|
||||
pub fn from_string_test() {
|
||||
let str =
|
||||
"214589024895249582498594209582039480239609385130598310670139580139855"
|
||||
let parsed = bigi.from_string(str)
|
||||
should.be_ok(parsed)
|
||||
let assert Ok(parsed_data) = parsed
|
||||
should.equal(bigi.to_string(parsed_data), str)
|
||||
}
|
||||
|
||||
pub fn from_bad_string_test() {
|
||||
let str =
|
||||
"214589024895249582498594209582039480239-//-609385130598310670139580139855"
|
||||
let parsed = bigi.from_string(str)
|
||||
should.be_error(parsed)
|
||||
}
|
||||
|
||||
pub fn power_test() {
|
||||
let assert Ok(bigint) = bigi.power(bigi.from_int(2), bigi.from_int(65_535))
|
||||
|
||||
|
|
Loading…
Reference in a new issue