Skip to content

Commit

Permalink
adding explicit_type_args
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianrof committed Dec 19, 2024
1 parent aa99af9 commit 63cd6b3
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 116 deletions.
231 changes: 130 additions & 101 deletions ergotree-interpreter/src/eval/sglobal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,33 +93,32 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx
"To deserialize Short with fromBigEndianBytes, exactly two bytes should be provided".to_string(),
));
}
let b0 = bytes[0] as i16;
let b1 = bytes[1] as i16;
Ok(Value::Short(((b0 & 0xFF) << 8 | (b1 & 0xFF)) as i16))
let value = bytes
.iter()
.fold(0i16, |acc, &x| (acc << 8) | (x as u8 as i16));
Ok(Value::Short(value))
}
SType::SInt => {
if bytes.len() != 4 {
return Err(EvalError::UnexpectedValue(
"To deserialize Int with fromBigEndianBytes, exactly four bytes should be provided".to_string(),
));
}
let bytes_vec: Vec<u8> = bytes.iter().map(|&x| x as u8).collect();
let int_bytes: [u8; 4] = bytes_vec.try_into().map_err(|_| {
EvalError::UnexpectedValue("Invalid byte array length for Int".to_string())
})?;
Ok(Value::Int(i32::from_be_bytes(int_bytes)))
let value = bytes
.iter()
.fold(0i32, |acc, &x| (acc << 8) | (x as u8 as i32));
Ok(Value::Int(value))
}
SType::SLong => {
if bytes.len() != 8 {
return Err(EvalError::UnexpectedValue(
"To deserialize Long with fromBigEndianBytes, exactly eight bytes should be provided".to_string(),
));
}
let bytes_vec: Vec<u8> = bytes.iter().map(|&x| x as u8).collect();
let long_bytes: [u8; 8] = bytes_vec.try_into().map_err(|_| {
EvalError::UnexpectedValue("Invalid byte array length for Long".to_string())
})?;
Ok(Value::Long(i64::from_be_bytes(long_bytes)))
let value = bytes
.iter()
.fold(0i64, |acc, &x| (acc << 8) | (x as u8 as i64));
Ok(Value::Long(value))
}
SType::SBigInt => {
if bytes.len() > 32 {
Expand All @@ -128,10 +127,11 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx
));
}
let bytes_vec: Vec<u8> = bytes.iter().map(|&x| x as u8).collect();

Check failure on line 129 in ergotree-interpreter/src/eval/sglobal.rs

View workflow job for this annotation

GitHub Actions / Build without default features

cannot find type `Vec` in this scope
let big_int = num_bigint::BigInt::from_bytes_be(num_bigint::Sign::Plus, &bytes_vec);
Ok(Value::BigInt(BigInt256::try_from(big_int).map_err(
|e| EvalError::UnexpectedValue(format!("Failed to convert to BigInt256: {:?}", e)),
)?))
Ok(Value::BigInt(
BigInt256::from_be_slice(&bytes_vec).ok_or_else(|| {
EvalError::UnexpectedValue("Failed to convert to BigInt256".to_string())
})?,
))
}
SType::SUnit => {
if !bytes.is_empty() {
Expand All @@ -158,7 +158,7 @@ mod tests {
use ergotree_ir::mir::method_call::MethodCall;
use ergotree_ir::mir::property_call::PropertyCall;

use crate::eval::tests::eval_out;
use crate::eval::tests::{eval_out, eval_out_wo_ctx};
use ergotree_ir::chain::context::Context;
use ergotree_ir::types::sglobal;
use ergotree_ir::types::stype::SType;
Expand Down Expand Up @@ -197,97 +197,126 @@ mod tests {
);
}

#[test]
fn eval_from_bigendian_bytes() {
let type_args = std::iter::once((STypeVar::t(), SType::SInt)).collect();
use proptest::prelude::*;

let bytes = vec![0_i8, 0, 0, 1];
let expr: Expr = MethodCall::new(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD
.clone()
.with_concrete_types(&type_args),
vec![bytes.into()],
)
.unwrap()
.into();
let ctx = force_any_val::<Context>();
assert_eq!(eval_out::<i32>(&expr, &ctx), 1);
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(64))]

#[test]
fn eval_from_bigendian_bytes_short() {
let type_args = std::iter::once((STypeVar::t(), SType::SShort)).collect();
#[test]
fn test_bigendian_bytes_roundtrip(
v_byte in any::<i8>(),
v_short in any::<i16>(),
v_int in any::<i32>(),
v_long in any::<i64>()
) {
{
let bytes = vec![v_byte];

let bytes = vec![0_i8, 1];
let expr: Expr = MethodCall::new(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD
.clone()
.with_concrete_types(&type_args),
vec![bytes.into()],
)
.unwrap()
.into();
let ctx = force_any_val::<Context>();
assert_eq!(eval_out::<i16>(&expr, &ctx), 1);
}
let type_args = std::iter::once((STypeVar::t(), SType::SByte)).collect();
let expr: Expr = MethodCall::with_type_args(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
vec![bytes.into()],
type_args,
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<i8>(&expr), v_byte);
}

#[test]
fn eval_from_bigendian_bytes_long() {
let type_args = std::iter::once((STypeVar::t(), SType::SLong)).collect();
{
let bytes = vec![(v_short >> 8) as i8, v_short as i8];

let bytes = vec![0_i8, 0, 0, 0, 0, 0, 0, 1];
let expr: Expr = MethodCall::new(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD
.clone()
.with_concrete_types(&type_args),
vec![bytes.into()],
)
.unwrap()
.into();
let ctx = force_any_val::<Context>();
assert_eq!(eval_out::<i64>(&expr, &ctx), 1);
}
let type_args = std::iter::once((STypeVar::t(), SType::SShort)).collect();
let expr: Expr = MethodCall::with_type_args(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
vec![bytes.into()],
type_args,
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<i16>(&expr), v_short);
}

#[test]
fn eval_from_bigendian_bytes_wrong_answer() {
let type_args = std::iter::once((STypeVar::t(), SType::SInt)).collect();
{
let bytes = vec![
(v_int >> 24) as i8,
(v_int >> 16) as i8,
(v_int >> 8) as i8,
v_int as i8
];

let bytes = vec![0_i8, 0, 0, 1];
let expr: Expr = MethodCall::new(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD
.clone()
.with_concrete_types(&type_args),
vec![bytes.into()],
)
.unwrap()
.into();
let ctx = force_any_val::<Context>();
assert_ne!(eval_out::<i32>(&expr, &ctx), 2);
}
let type_args = std::iter::once((STypeVar::t(), SType::SInt)).collect();
let expr: Expr = MethodCall::with_type_args(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
vec![bytes.into()],
type_args,
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<i32>(&expr), v_int);
}

#[test]
fn eval_from_bigendian_bytes_bigint() {
let type_args = std::iter::once((STypeVar::t(), SType::SBigInt)).collect();
{
let bytes = vec![
(v_long >> 56) as i8,
(v_long >> 48) as i8,
(v_long >> 40) as i8,
(v_long >> 32) as i8,
(v_long >> 24) as i8,
(v_long >> 16) as i8,
(v_long >> 8) as i8,
v_long as i8
];

let bytes = vec![0_i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
let expr: Expr = MethodCall::new(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD
.clone()
.with_concrete_types(&type_args),
vec![bytes.into()],
)
.unwrap()
.into();
let ctx = force_any_val::<Context>();
let expected_bigint = num_bigint::BigInt::from(1);
assert_eq!(
eval_out::<BigInt256>(&expr, &ctx),
BigInt256::try_from(expected_bigint).unwrap()
);
let type_args = std::iter::once((STypeVar::t(), SType::SLong)).collect();
let expr: Expr = MethodCall::with_type_args(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
vec![bytes.clone().into()],
type_args,
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<i64>(&expr), v_long);

let original_long = ((bytes[0] as i64) << 56) |
(((bytes[1] as i64) & 0xFF) << 48) |
(((bytes[2] as i64) & 0xFF) << 40) |
(((bytes[3] as i64) & 0xFF) << 32) |
(((bytes[4] as i64) & 0xFF) << 24) |
(((bytes[5] as i64) & 0xFF) << 16) |
(((bytes[6] as i64) & 0xFF) << 8) |
((bytes[7] as i64) & 0xFF);
assert_eq!(original_long, v_long);
}
}

#[test]
fn test_bigint_roundtrip(v_long in any::<i64>()) {
let bytes = vec![
(v_long >> 56) as i8,
(v_long >> 48) as i8,
(v_long >> 40) as i8,
(v_long >> 32) as i8,
(v_long >> 24) as i8,
(v_long >> 16) as i8,
(v_long >> 8) as i8,
v_long as i8
];

let type_args = std::iter::once((STypeVar::t(), SType::SBigInt)).collect();
let expr: Expr = MethodCall::with_type_args(
Expr::Global,
sglobal::FROM_BIGENDIAN_BYTES_METHOD.clone().with_concrete_types(&type_args),
vec![bytes.into()],
type_args,
)
.unwrap()
.into();
assert_eq!(eval_out_wo_ctx::<BigInt256>(&expr), BigInt256::from(v_long));
}
}
}
8 changes: 4 additions & 4 deletions ergotree-ir/src/types/sglobal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::smethod::SMethodDesc;
use super::stype::SType;
use crate::types::smethod::SMethod;
use crate::types::stype_companion::STypeCompanion;
use crate::types::stype_param::{STypeParam, STypeVar};
use crate::types::stype_param::STypeVar;
use alloc::vec;
use alloc::vec::Vec;
use lazy_static::lazy_static;
Expand All @@ -26,7 +26,7 @@ pub const FROM_BIGENDIAN_BYTES_METHOD_ID: MethodId = MethodId(5);
lazy_static! {
/// Global method descriptors
pub(crate) static ref METHOD_DESC: Vec<&'static SMethodDesc> =
vec![&GROUP_GENERATOR_METHOD_DESC, &XOR_METHOD_DESC,];
vec![&GROUP_GENERATOR_METHOD_DESC, &XOR_METHOD_DESC, &FROM_BIGENDIAN_BYTES_METHOD_DESC];
}

lazy_static! {
Expand Down Expand Up @@ -72,9 +72,9 @@ lazy_static! {
tpe: SFunc {
t_dom: vec![SType::SGlobal, SType::SColl(SType::SByte.into())],
t_range:SType::STypeVar(STypeVar::t()).into(),
tpe_params: vec![STypeParam::param_t()],
tpe_params: vec![],
},
explicit_type_args: vec![]
explicit_type_args: vec![STypeVar::t()]
};
/// GLOBAL.fromBigEndianBytes
pub static ref FROM_BIGENDIAN_BYTES_METHOD: SMethod = SMethod::new(STypeCompanion::Global, FROM_BIGENDIAN_BYTES_METHOD_DESC.clone(),);
Expand Down
11 changes: 0 additions & 11 deletions ergotree-ir/src/types/stype_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,3 @@ pub struct STypeParam {
upper_bound: Option<SType>,
lower_bound: Option<SType>,
}

impl STypeParam {
/// paramT
pub fn param_t() -> Self {
Self {
ident: STypeVar::t(),
upper_bound: None,
lower_bound: None,
}
}
}

0 comments on commit 63cd6b3

Please sign in to comment.