Skip to content

Commit

Permalink
Replace rug::Integer with num_bigint::BigInt
Browse files Browse the repository at this point in the history
rug::Integer is dependent on gmp-mpfr-sys v1.1.10, which doesn't work
for wasm-unknown-unknown.
  • Loading branch information
KronicDeth committed Apr 17, 2019
1 parent af5453b commit cbdcb8e
Show file tree
Hide file tree
Showing 11 changed files with 363 additions and 262 deletions.
13 changes: 12 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lumen_runtime/Cargo.toml
Expand Up @@ -19,7 +19,8 @@ lazy_static = "1.2"
libc = "0.2"
liblumen_arena = { path = "../liblumen_arena" }
log = "0.4"
rug = "1.3"
num-bigint = "0.2.2"
num-traits = "0.2.6"
signal-hook = "0.1"
xdg = "2.1"

Expand Down
18 changes: 10 additions & 8 deletions lumen_runtime/src/binary.rs
@@ -1,6 +1,9 @@
use std::convert::TryInto;
use std::mem::transmute;

use num_bigint::BigInt;
use num_traits::Zero;

use crate::atom::Existence;
use crate::list::{Cons, ToList};
use crate::process::{IntoProcess, Process};
Expand Down Expand Up @@ -212,12 +215,15 @@ where
fn next_small_big_integer(&mut self, mut process: &mut Process) -> Option<Term> {
self.next().and_then(|count| {
self.next().and_then(|sign| {
let mut rug_integer = rug::Integer::new();
let mut big_int: BigInt = Zero::zero();
let mut truncated = false;

for _ in 0..count {
match self.next() {
Some(byte) => rug_integer = (rug_integer << 8) | (byte as u32),
Some(byte) => {
let byte_big_int: BigInt = byte.into();
big_int = (big_int << 8) | (byte_big_int)
}
None => {
truncated = true;
break;
Expand All @@ -228,13 +234,9 @@ where
if truncated {
None
} else {
let signed_rug_integer = if sign == 0 {
rug_integer
} else {
-1 * rug_integer
};
let signed_big_int = if sign == 0 { big_int } else { -1 * big_int };

Some(signed_rug_integer.into_process(&mut process))
Some(signed_big_int.into_process(&mut process))
}
})
})
Expand Down
6 changes: 4 additions & 2 deletions lumen_runtime/src/binary/heap.rs
Expand Up @@ -381,6 +381,8 @@ mod tests {
mod iter {
use super::*;

use std::convert::TryInto;

#[test]
fn without_elements() {
let mut process: Process = Default::default();
Expand All @@ -390,7 +392,7 @@ mod tests {
assert_eq!(binary.iter().count(), 0);

let size_integer: Integer = binary.size();
let size_usize: usize = size_integer.into();
let size_usize: usize = size_integer.try_into().unwrap();

assert_eq!(binary.iter().count(), size_usize);
}
Expand All @@ -407,7 +409,7 @@ mod tests {
assert_eq!(binary.iter().count(), 1);

let size_integer: Integer = binary.size();
let size_usize: usize = size_integer.into();
let size_usize: usize = size_integer.try_into().unwrap();

assert_eq!(binary.iter().count(), size_usize);
}
Expand Down
57 changes: 32 additions & 25 deletions lumen_runtime/src/integer.rs
@@ -1,13 +1,19 @@
use std::cmp::Ordering;
use std::convert::{TryFrom, TryInto};

use num_bigint::BigInt;

use crate::process::{DebugInProcess, OrderInProcess, Process};
use crate::term::BadArgument;

pub mod big;
pub mod small;

use crate::integer::big::big_int_to_usize;

pub enum Integer {
Small(small::Integer),
Big(rug::Integer),
Big(BigInt),
}

impl DebugInProcess for Integer {
Expand Down Expand Up @@ -36,7 +42,7 @@ impl From<isize> for Integer {
if small::MIN <= i && i <= small::MAX {
Integer::Small(small::Integer(i))
} else {
Integer::Big(rug::Integer::from(i))
Integer::Big(i.into())
}
}
}
Expand All @@ -52,7 +58,7 @@ impl From<usize> for Integer {
if (u as isize) <= small::MAX {
Integer::Small(small::Integer(u as isize))
} else {
Integer::Big(rug::Integer::from(u))
Integer::Big(u.into())
}
}
}
Expand All @@ -69,32 +75,33 @@ impl OrderInProcess for Integer {
}
}

impl From<Integer> for usize {
fn from(integer: Integer) -> usize {
match integer {
Integer::Small(small::Integer(untagged)) => {
if 0 <= untagged {
untagged as usize
} else {
panic!(
"Small integer ({:?}) is less than 0 and cannot be converted to usize",
untagged
)
}
}
Integer::Big(rug_integer) => rug_integer.to_usize().unwrap_or_else(|| {
panic!("Big integer {:?} cannot be converted to usize", rug_integer)
}),
impl From<BigInt> for Integer {
fn from(big_int: BigInt) -> Integer {
let small_min_big_int: BigInt = small::MIN.into();
let small_max_big_int: BigInt = small::MAX.into();

if (small_min_big_int <= big_int) & (big_int <= small_max_big_int) {
let small_isize = big_int
.to_signed_bytes_be()
.iter()
.fold(0_isize, |acc, byte| (acc << 8) | (*byte as isize));

Integer::Small(small::Integer(small_isize))
} else {
Integer::Big(big_int)
}
}
}

impl From<rug::Integer> for Integer {
fn from(rug_integer: rug::Integer) -> Integer {
if (small::MIN <= rug_integer) & (rug_integer <= small::MAX) {
Integer::Small(small::Integer(rug_integer.to_isize().unwrap()))
} else {
Integer::Big(rug_integer)
impl TryFrom<Integer> for usize {
type Error = BadArgument;

fn try_from(integer: Integer) -> Result<usize, BadArgument> {
match integer {
Integer::Small(small::Integer(untagged)) => {
untagged.try_into().map_err(|_| BadArgument)
}
Integer::Big(big_int) => big_int_to_usize(&big_int),
}
}
}
41 changes: 38 additions & 3 deletions lumen_runtime/src/integer/big.rs
@@ -1,13 +1,17 @@
use crate::term::{Tag, Term};
use std::convert::TryFrom;

use num_bigint::{BigInt, Sign::*};

use crate::term::{BadArgument, Tag, Term};

pub struct Integer {
#[allow(dead_code)]
header: Term,
pub inner: rug::Integer,
pub inner: BigInt,
}

impl Integer {
pub fn new(inner: rug::Integer) -> Self {
pub fn new(inner: BigInt) -> Self {
Integer {
header: Term {
tagged: Tag::BigInteger as usize,
Expand All @@ -16,3 +20,34 @@ impl Integer {
}
}
}

impl TryFrom<Integer> for usize {
type Error = BadArgument;

fn try_from(integer: Integer) -> Result<usize, BadArgument> {
big_int_to_usize(&integer.inner)
}
}

impl TryFrom<&Integer> for usize {
type Error = BadArgument;

fn try_from(integer_ref: &Integer) -> Result<usize, BadArgument> {
big_int_to_usize(&integer_ref.inner)
}
}

pub fn big_int_to_usize(big_int: &BigInt) -> Result<usize, BadArgument> {
match big_int.sign() {
Plus => {
let (_, bytes) = big_int.to_bytes_be();
let integer_usize = bytes
.iter()
.fold(0_usize, |acc, byte| (acc << 8) | (*byte as usize));

Ok(integer_usize)
}
NoSign => Ok(0),
Minus => Err(BadArgument),
}
}

0 comments on commit cbdcb8e

Please sign in to comment.