From 63cd6b394c832b34efccee7d6bcface246c19d92 Mon Sep 17 00:00:00 2001 From: sebastianrof Date: Thu, 19 Dec 2024 13:19:17 -0500 Subject: [PATCH] adding explicit_type_args --- ergotree-interpreter/src/eval/sglobal.rs | 231 +++++++++++++---------- ergotree-ir/src/types/sglobal.rs | 8 +- ergotree-ir/src/types/stype_param.rs | 11 -- 3 files changed, 134 insertions(+), 116 deletions(-) diff --git a/ergotree-interpreter/src/eval/sglobal.rs b/ergotree-interpreter/src/eval/sglobal.rs index b9d0bd7ea..6b48ffd07 100644 --- a/ergotree-interpreter/src/eval/sglobal.rs +++ b/ergotree-interpreter/src/eval/sglobal.rs @@ -93,9 +93,10 @@ 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 { @@ -103,11 +104,10 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx "To deserialize Int with fromBigEndianBytes, exactly four bytes should be provided".to_string(), )); } - let bytes_vec: Vec = 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 { @@ -115,11 +115,10 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx "To deserialize Long with fromBigEndianBytes, exactly eight bytes should be provided".to_string(), )); } - let bytes_vec: Vec = 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 { @@ -128,10 +127,11 @@ pub(crate) static SGLOBAL_FROM_BIGENDIAN_BYTES_EVAL_FN: EvalFn = |mc, _env, _ctx )); } let bytes_vec: Vec = bytes.iter().map(|&x| x as u8).collect(); - 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() { @@ -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; @@ -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::(); - assert_eq!(eval_out::(&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::(), + v_short in any::(), + v_int in any::(), + v_long in any::() + ) { + { + 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::(); - assert_eq!(eval_out::(&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::(&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::(); - assert_eq!(eval_out::(&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::(&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::(); - assert_ne!(eval_out::(&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::(&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::(); - let expected_bigint = num_bigint::BigInt::from(1); - assert_eq!( - eval_out::(&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::(&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::()) { + 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::(&expr), BigInt256::from(v_long)); + } } } diff --git a/ergotree-ir/src/types/sglobal.rs b/ergotree-ir/src/types/sglobal.rs index dc6ffcb3f..e4ef726e8 100644 --- a/ergotree-ir/src/types/sglobal.rs +++ b/ergotree-ir/src/types/sglobal.rs @@ -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; @@ -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! { @@ -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(),); diff --git a/ergotree-ir/src/types/stype_param.rs b/ergotree-ir/src/types/stype_param.rs index cd24ea4e1..ae760caf1 100644 --- a/ergotree-ir/src/types/stype_param.rs +++ b/ergotree-ir/src/types/stype_param.rs @@ -100,14 +100,3 @@ pub struct STypeParam { upper_bound: Option, lower_bound: Option, } - -impl STypeParam { - /// paramT - pub fn param_t() -> Self { - Self { - ident: STypeVar::t(), - upper_bound: None, - lower_bound: None, - } - } -}