From d28fed951ff4b30bcc4474c5e876abdc547e643b Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 07:42:22 -0800 Subject: [PATCH 01/16] Initial impl and test of encode_unsigned_1 --- native_implemented/otp/src/erlang.rs | 1 + .../otp/src/erlang/encode_unsigned_1.rs | 47 +++++++++++++++++++ .../otp/src/erlang/encode_unsigned_1/test.rs | 32 +++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 native_implemented/otp/src/erlang/encode_unsigned_1.rs create mode 100644 native_implemented/otp/src/erlang/encode_unsigned_1/test.rs diff --git a/native_implemented/otp/src/erlang.rs b/native_implemented/otp/src/erlang.rs index 352421b10..8793ebadc 100644 --- a/native_implemented/otp/src/erlang.rs +++ b/native_implemented/otp/src/erlang.rs @@ -49,6 +49,7 @@ pub mod display_1; pub mod div_2; pub mod divide_2; pub mod element_2; +pub mod encode_unsigned_1; pub mod erase_0; pub mod erase_1; pub mod error_1; diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs new file mode 100644 index 000000000..2cf8a7a7b --- /dev/null +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -0,0 +1,47 @@ +#[cfg(all(not(target_arch = "wasm32"), test))] +mod test; + +use liblumen_alloc::erts::exception; +use liblumen_alloc::erts::process::Process; +use liblumen_alloc::erts::term::prelude::*; +use crate::runtime::context::term_is_not_integer; +use anyhow::*; + +/// Returns the smallest possible representation in a binary digit representation for the given big endian unsigned integer. +#[native_implemented::function(erlang:encode_unsigned/1)] +pub fn result(process: &Process, term: Term) -> exception::Result { + match term.decode().unwrap() { + TypedTerm::SmallInteger(small_integer) => { + let mut bytes: Vec = small_integer + .to_le_bytes() + .iter() + .filter_map(|&b| match b { + 0 => None, + b => Some(b) + }) + .collect(); + + bytes.reverse(); + + Ok(process.binary_from_bytes(&bytes)) + }, + TypedTerm::BigInteger(big_integer) => { + let bytes: Vec = big_integer + .to_signed_bytes_be() + .iter() + .filter_map(|&b| match b { + 0 => None, + b => Some(b) + }) + .collect(); + + Ok(process.binary_from_bytes(&bytes)) + }, + _ => Err(TypeError) + .context(term_is_not_integer( + "encoded_unsigned", + term + )) + .map_err(From::from), + } +} diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs new file mode 100644 index 000000000..82be24f90 --- /dev/null +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -0,0 +1,32 @@ +use crate::erlang::encode_unsigned_1::result; +use crate::test::with_process; +use liblumen_alloc::erts::term::prelude::*; +use num_bigint::BigInt; + +// 1> binary:encode_unsigned(11111111). +// <<169,138,199>> +#[test] +fn otp_doctest() { + with_process(|process| { + assert_eq!( + result(process, process.integer(11111111)), + Ok(process.binary_from_bytes(&[169,138,199])) + ) + }); +} + +#[test] +fn smallest_big_int() { + let largest_small_int_as_big_int: BigInt = SmallInteger::MAX_VALUE.into(); + let smallest_big_int: BigInt = largest_small_int_as_big_int + 1; + + // 1> binary:encode_unsigned(70368744177664). + // <<64,0,0,0,0,0>> + + with_process(|process| { + assert_eq!( + result(process, process.integer(smallest_big_int)), + Ok(process.binary_from_bytes(&[64])) + ) + }); +} \ No newline at end of file From ed869b0fe7902abed7921750be7743b2217e6ee3 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 08:21:37 -0800 Subject: [PATCH 02/16] update handling for non-integer arg and negative proptest --- .../otp/src/erlang/encode_unsigned_1.rs | 2 +- .../otp/src/erlang/encode_unsigned_1/test.rs | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 2cf8a7a7b..6d698f1ef 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -37,7 +37,7 @@ pub fn result(process: &Process, term: Term) -> exception::Result { Ok(process.binary_from_bytes(&bytes)) }, - _ => Err(TypeError) + _ => Err(TryIntoIntegerError::Type) .context(term_is_not_integer( "encoded_unsigned", term diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs index 82be24f90..7f28031d8 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -2,6 +2,8 @@ use crate::erlang::encode_unsigned_1::result; use crate::test::with_process; use liblumen_alloc::erts::term::prelude::*; use num_bigint::BigInt; +use crate::test::*; +use proptest::strategy::Just; // 1> binary:encode_unsigned(11111111). // <<169,138,199>> @@ -29,4 +31,23 @@ fn smallest_big_int() { Ok(process.binary_from_bytes(&[64])) ) }); +} + +#[test] +fn not_integer() { + run!( + |arc_process| { + ( + Just(arc_process.clone()), + strategy::term::is_not_integer(arc_process.clone()) + ) + }, + |(arc_process, non_int)| { + prop_assert_badarg!( + result(&arc_process, non_int), + "invalid integer conversion" + ); + Ok(()) + }, + ); } \ No newline at end of file From b42e063e2188b8c41dcf23c1535c8225a6607870 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 08:44:52 -0800 Subject: [PATCH 03/16] handle negative integers as bardarg and add proptests --- .../otp/src/erlang/encode_unsigned_1.rs | 21 ++++++++++++++++++- .../otp/src/erlang/encode_unsigned_1/test.rs | 19 +++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 6d698f1ef..96a50771f 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -4,14 +4,24 @@ mod test; use liblumen_alloc::erts::exception; use liblumen_alloc::erts::process::Process; use liblumen_alloc::erts::term::prelude::*; -use crate::runtime::context::term_is_not_integer; +use crate::runtime::context::{term_is_not_integer, term_is_not_non_negative_integer}; use anyhow::*; +use num_bigint::Sign; /// Returns the smallest possible representation in a binary digit representation for the given big endian unsigned integer. #[native_implemented::function(erlang:encode_unsigned/1)] pub fn result(process: &Process, term: Term) -> exception::Result { match term.decode().unwrap() { TypedTerm::SmallInteger(small_integer) => { + let signed: isize = small_integer.into(); + if signed < 0 { + return Err(TryIntoIntegerError::Type) + .context(term_is_not_non_negative_integer( + "encoded_unsigned", + term + )) + .map_err(From::from); + } let mut bytes: Vec = small_integer .to_le_bytes() .iter() @@ -26,6 +36,15 @@ pub fn result(process: &Process, term: Term) -> exception::Result { Ok(process.binary_from_bytes(&bytes)) }, TypedTerm::BigInteger(big_integer) => { + if Sign::Minus == big_integer.sign() { + return Err(TryIntoIntegerError::Type) + .context(term_is_not_non_negative_integer( + "encoded_unsigned", + term + )) + .map_err(From::from); + } + let bytes: Vec = big_integer .to_signed_bytes_be() .iter() diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs index 7f28031d8..4b3663735 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -33,6 +33,25 @@ fn smallest_big_int() { }); } +#[test] +fn negative_integer() { + run!( + |arc_process| { + ( + Just(arc_process.clone()), + strategy::term::integer::negative(arc_process.clone()) + ) + }, + |(arc_process, non_int)| { + prop_assert_badarg!( + result(&arc_process, non_int), + "invalid integer conversion" + ); + Ok(()) + }, + ); +} + #[test] fn not_integer() { run!( From d70d7aa72a7929b5da7194190bfc204fad61b46d Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 08:46:59 -0800 Subject: [PATCH 04/16] auto-formatting --- .../otp/src/erlang/encode_unsigned_1.rs | 30 +++++++------------ .../otp/src/erlang/encode_unsigned_1/test.rs | 20 +++++-------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 96a50771f..a9ae60a23 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -1,14 +1,15 @@ #[cfg(all(not(target_arch = "wasm32"), test))] mod test; +use crate::runtime::context::{term_is_not_integer, term_is_not_non_negative_integer}; +use anyhow::*; use liblumen_alloc::erts::exception; use liblumen_alloc::erts::process::Process; use liblumen_alloc::erts::term::prelude::*; -use crate::runtime::context::{term_is_not_integer, term_is_not_non_negative_integer}; -use anyhow::*; use num_bigint::Sign; -/// Returns the smallest possible representation in a binary digit representation for the given big endian unsigned integer. +/// Returns the smallest possible representation in a binary digit representation for the given big +/// endian unsigned integer. #[native_implemented::function(erlang:encode_unsigned/1)] pub fn result(process: &Process, term: Term) -> exception::Result { match term.decode().unwrap() { @@ -16,10 +17,7 @@ pub fn result(process: &Process, term: Term) -> exception::Result { let signed: isize = small_integer.into(); if signed < 0 { return Err(TryIntoIntegerError::Type) - .context(term_is_not_non_negative_integer( - "encoded_unsigned", - term - )) + .context(term_is_not_non_negative_integer("encoded_unsigned", term)) .map_err(From::from); } let mut bytes: Vec = small_integer @@ -27,21 +25,18 @@ pub fn result(process: &Process, term: Term) -> exception::Result { .iter() .filter_map(|&b| match b { 0 => None, - b => Some(b) + b => Some(b), }) .collect(); bytes.reverse(); Ok(process.binary_from_bytes(&bytes)) - }, + } TypedTerm::BigInteger(big_integer) => { if Sign::Minus == big_integer.sign() { return Err(TryIntoIntegerError::Type) - .context(term_is_not_non_negative_integer( - "encoded_unsigned", - term - )) + .context(term_is_not_non_negative_integer("encoded_unsigned", term)) .map_err(From::from); } @@ -50,17 +45,14 @@ pub fn result(process: &Process, term: Term) -> exception::Result { .iter() .filter_map(|&b| match b { 0 => None, - b => Some(b) + b => Some(b), }) .collect(); Ok(process.binary_from_bytes(&bytes)) - }, + } _ => Err(TryIntoIntegerError::Type) - .context(term_is_not_integer( - "encoded_unsigned", - term - )) + .context(term_is_not_integer("encoded_unsigned", term)) .map_err(From::from), } } diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs index 4b3663735..1663eb09d 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -1,8 +1,8 @@ use crate::erlang::encode_unsigned_1::result; use crate::test::with_process; +use crate::test::*; use liblumen_alloc::erts::term::prelude::*; use num_bigint::BigInt; -use crate::test::*; use proptest::strategy::Just; // 1> binary:encode_unsigned(11111111). @@ -12,7 +12,7 @@ fn otp_doctest() { with_process(|process| { assert_eq!( result(process, process.integer(11111111)), - Ok(process.binary_from_bytes(&[169,138,199])) + Ok(process.binary_from_bytes(&[169, 138, 199])) ) }); } @@ -39,14 +39,11 @@ fn negative_integer() { |arc_process| { ( Just(arc_process.clone()), - strategy::term::integer::negative(arc_process.clone()) + strategy::term::integer::negative(arc_process.clone()), ) }, |(arc_process, non_int)| { - prop_assert_badarg!( - result(&arc_process, non_int), - "invalid integer conversion" - ); + prop_assert_badarg!(result(&arc_process, non_int), "invalid integer conversion"); Ok(()) }, ); @@ -58,15 +55,12 @@ fn not_integer() { |arc_process| { ( Just(arc_process.clone()), - strategy::term::is_not_integer(arc_process.clone()) + strategy::term::is_not_integer(arc_process.clone()), ) }, |(arc_process, non_int)| { - prop_assert_badarg!( - result(&arc_process, non_int), - "invalid integer conversion" - ); + prop_assert_badarg!(result(&arc_process, non_int), "invalid integer conversion"); Ok(()) }, ); -} \ No newline at end of file +} From 665cde96051d1a2227afeb3d51bcb9fcbf424485 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 09:29:11 -0800 Subject: [PATCH 05/16] Fix handling of leading/trailing zeros --- .../otp/src/erlang/encode_unsigned_1.rs | 28 +++-------- .../otp/src/erlang/encode_unsigned_1/test.rs | 47 ++++++++++++++++++- 2 files changed, 53 insertions(+), 22 deletions(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index a9ae60a23..38d8d0e04 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -20,18 +20,10 @@ pub fn result(process: &Process, term: Term) -> exception::Result { .context(term_is_not_non_negative_integer("encoded_unsigned", term)) .map_err(From::from); } - let mut bytes: Vec = small_integer - .to_le_bytes() - .iter() - .filter_map(|&b| match b { - 0 => None, - b => Some(b), - }) - .collect(); - + let mut bytes: Vec = small_integer.to_le_bytes(); bytes.reverse(); - - Ok(process.binary_from_bytes(&bytes)) + let first_nonzero_index = bytes.iter().position(|&b| b != 0).unwrap_or(0); + Ok(process.binary_from_bytes(&bytes[first_nonzero_index..])) } TypedTerm::BigInteger(big_integer) => { if Sign::Minus == big_integer.sign() { @@ -40,16 +32,10 @@ pub fn result(process: &Process, term: Term) -> exception::Result { .map_err(From::from); } - let bytes: Vec = big_integer - .to_signed_bytes_be() - .iter() - .filter_map(|&b| match b { - 0 => None, - b => Some(b), - }) - .collect(); - - Ok(process.binary_from_bytes(&bytes)) + let bytes: Vec = big_integer.to_signed_bytes_be(); + let first_nonzero_index_from_left = bytes.iter().position(|&b| b != 0).unwrap_or(0); + let first_nonzero_index_from_right = bytes.iter().rposition(|&b| b != 0).unwrap_or(0); + Ok(process.binary_from_bytes(&bytes[first_nonzero_index_from_left..(first_nonzero_index_from_right + 1)])) } _ => Err(TryIntoIntegerError::Type) .context(term_is_not_integer("encoded_unsigned", term)) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs index 1663eb09d..a9b65fde8 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -2,7 +2,7 @@ use crate::erlang::encode_unsigned_1::result; use crate::test::with_process; use crate::test::*; use liblumen_alloc::erts::term::prelude::*; -use num_bigint::BigInt; +use num_bigint::{BigInt, ToBigInt}; use proptest::strategy::Just; // 1> binary:encode_unsigned(11111111). @@ -33,6 +33,51 @@ fn smallest_big_int() { }); } +#[test] +fn big_int_with_middle_zeros() { + let largest_small_int_as_big_int: BigInt = SmallInteger::MAX_VALUE.into(); + let big_int_with_middle_zeros: BigInt = largest_small_int_as_big_int + 2; + + // 1> binary:encode_unsigned(70368744177665). + // <<64,0,0,0,0,1>> + with_process(|process| { + assert_eq!( + result(process, process.integer(big_int_with_middle_zeros)), + Ok(process.binary_from_bytes(&[64, 0, 0, 0, 0, 1])) + ) + }); +} + +#[test] +fn small_int_with_middle_zeros() { + // 1> binary:encode_unsigned(11075783). + // <<169,0,199>> + let largest_small_int_as_big_int: BigInt = SmallInteger::MAX_VALUE.into(); + assert!(11075783.to_bigint().unwrap() < largest_small_int_as_big_int); + + with_process(|process| { + assert_eq!( + result(process, process.integer(11075783)), + Ok(process.binary_from_bytes(&[169, 0, 199])) + ) + }); +} + +#[test] +fn small_int_with_trailing_zeros() { + // 1> binary:encode_unsigned(16777216). + // <<1,0,0,0>> + let largest_small_int_as_big_int: BigInt = SmallInteger::MAX_VALUE.into(); + assert!(16777216.to_bigint().unwrap() < largest_small_int_as_big_int); + + with_process(|process| { + assert_eq!( + result(process, process.integer(16777216)), + Ok(process.binary_from_bytes(&[1, 0, 0, 0])) + ) + }); +} + #[test] fn negative_integer() { run!( From 4b8dfdebf172bacc18950d14089b313f11858c31 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 09:30:01 -0800 Subject: [PATCH 06/16] auto-formatting --- native_implemented/otp/src/erlang/encode_unsigned_1.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 38d8d0e04..9431f93a5 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -35,7 +35,9 @@ pub fn result(process: &Process, term: Term) -> exception::Result { let bytes: Vec = big_integer.to_signed_bytes_be(); let first_nonzero_index_from_left = bytes.iter().position(|&b| b != 0).unwrap_or(0); let first_nonzero_index_from_right = bytes.iter().rposition(|&b| b != 0).unwrap_or(0); - Ok(process.binary_from_bytes(&bytes[first_nonzero_index_from_left..(first_nonzero_index_from_right + 1)])) + Ok(process.binary_from_bytes( + &bytes[first_nonzero_index_from_left..(first_nonzero_index_from_right + 1)], + )) } _ => Err(TryIntoIntegerError::Type) .context(term_is_not_integer("encoded_unsigned", term)) From 1b1abdb086697d3c103fcd3e80b838e6340e7ff9 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 09:39:03 -0800 Subject: [PATCH 07/16] Fix bug with BigInt with trailing zeros --- native_implemented/otp/src/erlang/encode_unsigned_1.rs | 7 ++----- .../otp/src/erlang/encode_unsigned_1/test.rs | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 9431f93a5..4c9608c45 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -33,11 +33,8 @@ pub fn result(process: &Process, term: Term) -> exception::Result { } let bytes: Vec = big_integer.to_signed_bytes_be(); - let first_nonzero_index_from_left = bytes.iter().position(|&b| b != 0).unwrap_or(0); - let first_nonzero_index_from_right = bytes.iter().rposition(|&b| b != 0).unwrap_or(0); - Ok(process.binary_from_bytes( - &bytes[first_nonzero_index_from_left..(first_nonzero_index_from_right + 1)], - )) + let first_nonzero_index = bytes.iter().position(|&b| b != 0).unwrap_or(0); + Ok(process.binary_from_bytes(&bytes[first_nonzero_index..])) } _ => Err(TryIntoIntegerError::Type) .context(term_is_not_integer("encoded_unsigned", term)) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs index a9b65fde8..072c3fe71 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs @@ -28,7 +28,7 @@ fn smallest_big_int() { with_process(|process| { assert_eq!( result(process, process.integer(smallest_big_int)), - Ok(process.binary_from_bytes(&[64])) + Ok(process.binary_from_bytes(&[64, 0, 0, 0, 0, 0])) ) }); } From 3576682eb8f84d6f83a3ab00ee1b9ac273eee6dd Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 09:43:37 -0800 Subject: [PATCH 08/16] small refactor --- .../otp/src/erlang/encode_unsigned_1.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/erlang/encode_unsigned_1.rs index 4c9608c45..5177c0bf5 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/erlang/encode_unsigned_1.rs @@ -22,8 +22,7 @@ pub fn result(process: &Process, term: Term) -> exception::Result { } let mut bytes: Vec = small_integer.to_le_bytes(); bytes.reverse(); - let first_nonzero_index = bytes.iter().position(|&b| b != 0).unwrap_or(0); - Ok(process.binary_from_bytes(&bytes[first_nonzero_index..])) + Ok(process.binary_from_bytes(without_leading_zeros(&bytes))) } TypedTerm::BigInteger(big_integer) => { if Sign::Minus == big_integer.sign() { @@ -33,11 +32,16 @@ pub fn result(process: &Process, term: Term) -> exception::Result { } let bytes: Vec = big_integer.to_signed_bytes_be(); - let first_nonzero_index = bytes.iter().position(|&b| b != 0).unwrap_or(0); - Ok(process.binary_from_bytes(&bytes[first_nonzero_index..])) + Ok(process.binary_from_bytes(without_leading_zeros(&bytes))) } _ => Err(TryIntoIntegerError::Type) .context(term_is_not_integer("encoded_unsigned", term)) .map_err(From::from), } } + +#[inline] +fn without_leading_zeros(bytes: &Vec) -> &[u8] { + let first_nonzero_index = bytes.iter().position(|&b| b != 0).unwrap_or(0); + &bytes[first_nonzero_index..] +} From 184951d81621a7004b5190b99bdcf5ecee02e87b Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 10:47:35 -0800 Subject: [PATCH 09/16] add doctest as integration test --- native_implemented/otp/tests/internal/lib/erlang.rs | 2 ++ .../otp/tests/internal/lib/erlang/encode_unsigned_1.rs | 1 + .../internal/lib/erlang/encode_unsigned_1/doctest/init.erl | 6 ++++++ 3 files changed, 9 insertions(+) create mode 100644 native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs create mode 100644 native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl diff --git a/native_implemented/otp/tests/internal/lib/erlang.rs b/native_implemented/otp/tests/internal/lib/erlang.rs index 8d889fc0e..03f8b9a2d 100644 --- a/native_implemented/otp/tests/internal/lib/erlang.rs +++ b/native_implemented/otp/tests/internal/lib/erlang.rs @@ -68,6 +68,8 @@ pub mod div_2; pub mod divide_2; #[path = "erlang/element_2.rs"] pub mod element_2; +#[path = "erlang/encode_unsigned_1.rs"] +pub mod encode_unsigned_1; #[path = "erlang/erase_0.rs"] pub mod erase_0; #[path = "erlang/erase_1.rs"] diff --git a/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs b/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs new file mode 100644 index 000000000..654449c50 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs @@ -0,0 +1 @@ +test_stdout!(doctest, "<<169,138,199>>\n"); diff --git a/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl b/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl new file mode 100644 index 000000000..4fde2f420 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(erlang:encode_unsigned(11111111)). From ebff6bc311bf93b0e85ddf8dba7cf9fe1f6b23da Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 11:13:02 -0800 Subject: [PATCH 10/16] move to module binary --- native_implemented/otp/src/binary.rs | 9 +++++++++ .../otp/src/{erlang => binary}/encode_unsigned_1.rs | 2 +- .../otp/src/{erlang => binary}/encode_unsigned_1/test.rs | 2 +- native_implemented/otp/src/erlang.rs | 1 - 4 files changed, 11 insertions(+), 3 deletions(-) rename native_implemented/otp/src/{erlang => binary}/encode_unsigned_1.rs (96%) rename native_implemented/otp/src/{erlang => binary}/encode_unsigned_1/test.rs (98%) diff --git a/native_implemented/otp/src/binary.rs b/native_implemented/otp/src/binary.rs index fdfcfbb1b..b4288e15b 100644 --- a/native_implemented/otp/src/binary.rs +++ b/native_implemented/otp/src/binary.rs @@ -1,4 +1,5 @@ pub mod to_term; +pub mod encode_unsigned_1; use std::backtrace::Backtrace; use std::convert::TryInto; @@ -11,6 +12,14 @@ use liblumen_alloc::erts::exception::{self, ArcError, Exception, InternalExcepti use liblumen_alloc::erts::term::prelude::*; use liblumen_alloc::Process; +pub fn module() -> Atom { + Atom::from_str("binary") +} + +pub fn module_id() -> usize { + module().id() +} + pub struct PartRange { pub byte_offset: usize, pub byte_len: usize, diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1.rs b/native_implemented/otp/src/binary/encode_unsigned_1.rs similarity index 96% rename from native_implemented/otp/src/erlang/encode_unsigned_1.rs rename to native_implemented/otp/src/binary/encode_unsigned_1.rs index 5177c0bf5..4082da7c6 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1.rs +++ b/native_implemented/otp/src/binary/encode_unsigned_1.rs @@ -10,7 +10,7 @@ use num_bigint::Sign; /// Returns the smallest possible representation in a binary digit representation for the given big /// endian unsigned integer. -#[native_implemented::function(erlang:encode_unsigned/1)] +#[native_implemented::function(binary:encode_unsigned/1)] pub fn result(process: &Process, term: Term) -> exception::Result { match term.decode().unwrap() { TypedTerm::SmallInteger(small_integer) => { diff --git a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs b/native_implemented/otp/src/binary/encode_unsigned_1/test.rs similarity index 98% rename from native_implemented/otp/src/erlang/encode_unsigned_1/test.rs rename to native_implemented/otp/src/binary/encode_unsigned_1/test.rs index 072c3fe71..86484b8f4 100644 --- a/native_implemented/otp/src/erlang/encode_unsigned_1/test.rs +++ b/native_implemented/otp/src/binary/encode_unsigned_1/test.rs @@ -1,4 +1,4 @@ -use crate::erlang::encode_unsigned_1::result; +use crate::binary::encode_unsigned_1::result; use crate::test::with_process; use crate::test::*; use liblumen_alloc::erts::term::prelude::*; diff --git a/native_implemented/otp/src/erlang.rs b/native_implemented/otp/src/erlang.rs index 8793ebadc..352421b10 100644 --- a/native_implemented/otp/src/erlang.rs +++ b/native_implemented/otp/src/erlang.rs @@ -49,7 +49,6 @@ pub mod display_1; pub mod div_2; pub mod divide_2; pub mod element_2; -pub mod encode_unsigned_1; pub mod erase_0; pub mod erase_1; pub mod error_1; From 32e04336f3d916686c5e595c5e45d99040a45672 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 11:20:44 -0800 Subject: [PATCH 11/16] move integration test to binary module --- native_implemented/otp/tests/internal/lib/binary.rs | 2 ++ .../tests/internal/lib/{erlang => binary}/encode_unsigned_1.rs | 0 .../lib/{erlang => binary}/encode_unsigned_1/doctest/init.erl | 2 +- native_implemented/otp/tests/internal/lib/erlang.rs | 2 -- 4 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 native_implemented/otp/tests/internal/lib/binary.rs rename native_implemented/otp/tests/internal/lib/{erlang => binary}/encode_unsigned_1.rs (100%) rename native_implemented/otp/tests/internal/lib/{erlang => binary}/encode_unsigned_1/doctest/init.erl (63%) diff --git a/native_implemented/otp/tests/internal/lib/binary.rs b/native_implemented/otp/tests/internal/lib/binary.rs new file mode 100644 index 000000000..74000ed79 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary.rs @@ -0,0 +1,2 @@ +#[path = "binary/encode_unsigned_1.rs"] +pub mod encode_unsigned_1; \ No newline at end of file diff --git a/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs similarity index 100% rename from native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1.rs rename to native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs diff --git a/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/doctest/init.erl similarity index 63% rename from native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl rename to native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/doctest/init.erl index 4fde2f420..3117c05b3 100644 --- a/native_implemented/otp/tests/internal/lib/erlang/encode_unsigned_1/doctest/init.erl +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/doctest/init.erl @@ -3,4 +3,4 @@ -import(erlang, [display/1]). start() -> - display(erlang:encode_unsigned(11111111)). + display(binary:encode_unsigned(11111111)). diff --git a/native_implemented/otp/tests/internal/lib/erlang.rs b/native_implemented/otp/tests/internal/lib/erlang.rs index 03f8b9a2d..8d889fc0e 100644 --- a/native_implemented/otp/tests/internal/lib/erlang.rs +++ b/native_implemented/otp/tests/internal/lib/erlang.rs @@ -68,8 +68,6 @@ pub mod div_2; pub mod divide_2; #[path = "erlang/element_2.rs"] pub mod element_2; -#[path = "erlang/encode_unsigned_1.rs"] -pub mod encode_unsigned_1; #[path = "erlang/erase_0.rs"] pub mod erase_0; #[path = "erlang/erase_1.rs"] From b807dcc2e066096b7e79dd7c0b885877de6aac32 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 11:29:55 -0800 Subject: [PATCH 12/16] hook in the binary integration test module --- native_implemented/otp/tests/internal/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/native_implemented/otp/tests/internal/lib.rs b/native_implemented/otp/tests/internal/lib.rs index 8ada4ba80..e54e05371 100644 --- a/native_implemented/otp/tests/internal/lib.rs +++ b/native_implemented/otp/tests/internal/lib.rs @@ -1,3 +1,5 @@ +#[path = "lib/binary.rs"] +pub mod binary; #[path = "lib/erlang.rs"] pub mod erlang; #[path = "lib/maps.rs"] From b31bdf07b3c4deb2638afa31d7dbdd351669bc2e Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 11:30:34 -0800 Subject: [PATCH 13/16] auto-formatting --- native_implemented/otp/src/binary.rs | 2 +- native_implemented/otp/tests/internal/lib/binary.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/native_implemented/otp/src/binary.rs b/native_implemented/otp/src/binary.rs index b4288e15b..c2e9cb3f7 100644 --- a/native_implemented/otp/src/binary.rs +++ b/native_implemented/otp/src/binary.rs @@ -1,5 +1,5 @@ -pub mod to_term; pub mod encode_unsigned_1; +pub mod to_term; use std::backtrace::Backtrace; use std::convert::TryInto; diff --git a/native_implemented/otp/tests/internal/lib/binary.rs b/native_implemented/otp/tests/internal/lib/binary.rs index 74000ed79..d26048ae3 100644 --- a/native_implemented/otp/tests/internal/lib/binary.rs +++ b/native_implemented/otp/tests/internal/lib/binary.rs @@ -1,2 +1,2 @@ #[path = "binary/encode_unsigned_1.rs"] -pub mod encode_unsigned_1; \ No newline at end of file +pub mod encode_unsigned_1; From edab51eff2a330bed7ec1c736ed7bb4908a8fb46 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 11:57:39 -0800 Subject: [PATCH 14/16] migrate integration test with_smallest_big_int --- .../otp/tests/internal/lib/binary/encode_unsigned_1.rs | 1 + .../binary/encode_unsigned_1/with_smallest_big_int/init.erl | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_smallest_big_int/init.erl diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs index 654449c50..3320210dd 100644 --- a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs @@ -1 +1,2 @@ test_stdout!(doctest, "<<169,138,199>>\n"); +test_stdout!(with_smallest_big_int, "<<64,0,0,0,0,0>>\n"); diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_smallest_big_int/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_smallest_big_int/init.erl new file mode 100644 index 000000000..d7d9349e4 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_smallest_big_int/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(binary:encode_unsigned(70368744177664)). From 112820f08118a0d357b3a6afd774762498307eb4 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 13:20:56 -0800 Subject: [PATCH 15/16] migrate more integration tests --- .../tests/internal/lib/binary/encode_unsigned_1.rs | 2 ++ .../with_negative_integer/init.erl | 11 +++++++++++ .../encode_unsigned_1/with_non_integer/init.erl | 14 ++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_negative_integer/init.erl create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_non_integer/init.erl diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs index 3320210dd..60cf74172 100644 --- a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs @@ -1,2 +1,4 @@ test_stdout!(doctest, "<<169,138,199>>\n"); test_stdout!(with_smallest_big_int, "<<64,0,0,0,0,0>>\n"); +test_stdout!(with_non_integer, "{caught, error, badarg}\n{caught, error, badarg}\n{caught, error, badarg}\n"); +test_stdout!(with_negative_integer, "{caught, error, badarg}\n{caught, error, badarg}\n"); diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_negative_integer/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_negative_integer/init.erl new file mode 100644 index 000000000..36e5b1e1c --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_negative_integer/init.erl @@ -0,0 +1,11 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + test:caught(fun () -> + display(binary:encode_unsigned(-1)) + end), + test:caught(fun () -> + display(binary:encode_unsigned(-70368744177664)) + end). \ No newline at end of file diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_non_integer/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_non_integer/init.erl new file mode 100644 index 000000000..f060d0e56 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/with_non_integer/init.erl @@ -0,0 +1,14 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + test:caught(fun () -> + display(binary:encode_unsigned(nil)) + end), + test:caught(fun () -> + display(binary:encode_unsigned(foo)) + end), + test:caught(fun () -> + display(binary:encode_unsigned("foo")) + end). \ No newline at end of file From 25d0dd4aa80da69154caf088a3642e4fcdfd6bb9 Mon Sep 17 00:00:00 2001 From: Mike Wilkerson Date: Mon, 2 Nov 2020 14:22:40 -0800 Subject: [PATCH 16/16] implement remaining tests as integration tests --- .../internal/lib/binary/encode_unsigned_1.rs | 26 +++++++++++++++++-- .../init.erl | 6 +++++ .../init.erl | 6 +++++ .../init.erl | 6 +++++ .../init.erl | 6 +++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_significant_trailing_zeros/init.erl create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_zeros_in_the_middle/init.erl create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_significant_trailing_zeros/init.erl create mode 100644 native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_zeros_in_the_middle/init.erl diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs index 60cf74172..6b7538965 100644 --- a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1.rs @@ -1,4 +1,26 @@ test_stdout!(doctest, "<<169,138,199>>\n"); test_stdout!(with_smallest_big_int, "<<64,0,0,0,0,0>>\n"); -test_stdout!(with_non_integer, "{caught, error, badarg}\n{caught, error, badarg}\n{caught, error, badarg}\n"); -test_stdout!(with_negative_integer, "{caught, error, badarg}\n{caught, error, badarg}\n"); +test_stdout!( + with_non_integer, + "{caught, error, badarg}\n{caught, error, badarg}\n{caught, error, badarg}\n" +); +test_stdout!( + with_negative_integer, + "{caught, error, badarg}\n{caught, error, badarg}\n" +); +test_stdout!( + when_big_int_encoded_bytes_have_significant_trailing_zeros, + "<<64,0,0,0,0,0>>\n" +); +test_stdout!( + when_small_int_encoded_bytes_have_significant_trailing_zeros, + "<<1,0,0,0>>\n" +); +test_stdout!( + when_small_int_encoded_bytes_have_zeros_in_the_middle, + "<<169,0,199>>\n" +); +test_stdout!( + when_big_int_encoded_bytes_have_zeros_in_the_middle, + "<<64,0,0,0,0,1>>\n" +); diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_significant_trailing_zeros/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_significant_trailing_zeros/init.erl new file mode 100644 index 000000000..0b4f10f34 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_significant_trailing_zeros/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(binary:encode_unsigned(70368744177665)). diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_zeros_in_the_middle/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_zeros_in_the_middle/init.erl new file mode 100644 index 000000000..0b4f10f34 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_big_int_encoded_bytes_have_zeros_in_the_middle/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(binary:encode_unsigned(70368744177665)). diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_significant_trailing_zeros/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_significant_trailing_zeros/init.erl new file mode 100644 index 000000000..65d6a8035 --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_significant_trailing_zeros/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(binary:encode_unsigned(16777216)). diff --git a/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_zeros_in_the_middle/init.erl b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_zeros_in_the_middle/init.erl new file mode 100644 index 000000000..26a486d6e --- /dev/null +++ b/native_implemented/otp/tests/internal/lib/binary/encode_unsigned_1/when_small_int_encoded_bytes_have_zeros_in_the_middle/init.erl @@ -0,0 +1,6 @@ +-module(init). +-export([start/0]). +-import(erlang, [display/1]). + +start() -> + display(binary:encode_unsigned(11075783)).