Skip to content
This repository has been archived by the owner on Jun 10, 2024. It is now read-only.

encode_unsigned_1 #676

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions native_implemented/otp/src/erlang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
58 changes: 58 additions & 0 deletions native_implemented/otp/src/erlang/encode_unsigned_1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#[cfg(all(not(target_arch = "wasm32"), test))]
mod test;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're moving away from unit tests and preferring writing integration tests in Erlang now under native_implemented/otp/tests/internal/lib

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, does that also mean that we're moving away from proptest as well?

How do I run these integration tests in local dev?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, for now. I think I figured out how to wire up and run the erlang integration tests.


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 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<Term> {
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<u8> = 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) => {
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<u8> = 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(TryIntoIntegerError::Type)
.context(term_is_not_integer("encoded_unsigned", term))
.map_err(From::from),
}
}
66 changes: 66 additions & 0 deletions native_implemented/otp/src/erlang/encode_unsigned_1/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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 proptest::strategy::Just;

// 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]))
)
});
}

#[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!(
|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(())
},
);
}