From c5a606c1e8077af0e6f4442b2c9345bf5dfa483b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Wed, 18 Jan 2023 16:12:02 +0100 Subject: [PATCH 1/3] Create ConvertibleValue from sequence --- aleph-client/Cargo.toml | 2 +- .../src/contract/convertible_value.rs | 151 ++++++++++++++---- 2 files changed, 124 insertions(+), 29 deletions(-) diff --git a/aleph-client/Cargo.toml b/aleph-client/Cargo.toml index 37d13f8769..7ff22c25da 100644 --- a/aleph-client/Cargo.toml +++ b/aleph-client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "aleph_client" # TODO bump major version when API stablize -version = "2.8.1" +version = "2.8.2" edition = "2021" license = "Apache 2.0" diff --git a/aleph-client/src/contract/convertible_value.rs b/aleph-client/src/contract/convertible_value.rs index 18397e3d47..06d6788d74 100644 --- a/aleph-client/src/contract/convertible_value.rs +++ b/aleph-client/src/contract/convertible_value.rs @@ -40,38 +40,31 @@ impl Deref for ConvertibleValue { } } -impl TryFrom for bool { - type Error = anyhow::Error; +macro_rules! try_from_flat_value { + ($ty: ty, $variant: ident, $desc: literal) => { + impl TryFrom for $ty { + type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> Result { - match value.0 { - Value::Bool(value) => Ok(value), - _ => bail!("Expected {:?} to be a boolean", value.0), - } - } -} - -impl TryFrom for u128 { - type Error = anyhow::Error; - - fn try_from(value: ConvertibleValue) -> Result { - match value.0 { - Value::UInt(value) => Ok(value), - _ => bail!("Expected {:?} to be an integer", value.0), + fn try_from(value: ConvertibleValue) -> Result<$ty, Self::Error> { + match value.0 { + Value::$variant(value) => Ok(value.try_into()?), + _ => anyhow::bail!("Expected {:?} to be {}", value, $desc), + } + } } - } + }; } -impl TryFrom for u32 { - type Error = anyhow::Error; - - fn try_from(value: ConvertibleValue) -> Result { - match value.0 { - Value::UInt(value) => Ok(value.try_into()?), - _ => bail!("Expected {:?} to be an integer", value.0), - } - } -} +try_from_flat_value!(bool, Bool, "boolean"); +try_from_flat_value!(char, Char, "char"); +try_from_flat_value!(u16, UInt, "unsigned integer"); +try_from_flat_value!(u32, UInt, "unsigned integer"); +try_from_flat_value!(u64, UInt, "unsigned integer"); +try_from_flat_value!(u128, UInt, "unsigned integer"); +try_from_flat_value!(i16, Int, "signed integer"); +try_from_flat_value!(i32, Int, "signed integer"); +try_from_flat_value!(i64, Int, "signed integer"); +try_from_flat_value!(i128, Int, "signed integer"); impl TryFrom for AccountId { type Error = anyhow::Error; @@ -193,3 +186,105 @@ where } } } + +impl + Debug> TryFrom + for Vec +{ + type Error = anyhow::Error; + + fn try_from(value: ConvertibleValue) -> std::result::Result { + let seq = match value.0 { + Value::Seq(seq) => seq, + _ => bail!("Failed parsing `ConvertibleValue` to `Vec`. Expected `Seq(_)` but instead got: {:?}", value), + }; + + let mut result = vec![]; + for element in seq.elems() { + result.push(ConvertibleValue(element.clone()).try_into()?); + } + + Ok(result) + } +} + +#[cfg(test)] +mod tests { + use contract_transcode::Value::{Bool, Char, Int, Seq, UInt}; + + use crate::contract::ConvertibleValue; + + #[test] + fn converts_boolean() { + let cast: bool = ConvertibleValue(Bool(true)) + .try_into() + .expect("Should cast successfully"); + assert_eq!(true, cast); + } + + #[test] + fn converts_char() { + let cast: char = ConvertibleValue(Char('x')) + .try_into() + .expect("Should cast successfully"); + assert_eq!('x', cast); + } + + #[test] + fn converts_biguint() { + let long_uint = 41414141414141414141414141414141414141u128; + let cast: u128 = ConvertibleValue(UInt(long_uint)) + .try_into() + .expect("Should cast successfully"); + assert_eq!(long_uint, cast); + } + + #[test] + fn converts_uint() { + let cast: u32 = ConvertibleValue(UInt(41)) + .try_into() + .expect("Should cast successfully"); + assert_eq!(41, cast); + } + + #[test] + fn converts_bigint() { + let long_int = -41414141414141414141414141414141414141i128; + let cast: i128 = ConvertibleValue(Int(long_int)) + .try_into() + .expect("Should cast successfully"); + assert_eq!(long_int, cast); + } + + #[test] + fn converts_int() { + let cast: i32 = ConvertibleValue(Int(-41)) + .try_into() + .expect("Should cast successfully"); + assert_eq!(-41, cast); + } + + #[test] + fn converts_integer_sequence() { + let cv = ConvertibleValue(Seq(vec![UInt(4), UInt(1)].into())); + let cast: Vec = cv.try_into().expect("Should cast successfully"); + assert_eq!(vec![4u32, 1u32], cast); + } + + #[test] + fn converts_nested_sequence() { + let words = vec![ + vec!['s', 'u', 'r', 'f', 'i', 'n'], + vec![], + vec!['b', 'i', 'r', 'd'], + ]; + let encoded_words = words + .iter() + .map(|word| Seq(word.iter().cloned().map(Char).collect::>().into())) + .collect::>(); + + let cv = ConvertibleValue(Seq(encoded_words.into())); + let cast: Vec> = cv.try_into().expect("Should cast successfully"); + + assert_eq!(words, cast); + } +} From 3587e52d0e402bdd87dbc311010a6cf7e63aa2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Wed, 18 Jan 2023 16:37:07 +0100 Subject: [PATCH 2/3] Support arrays --- aleph-client/Cargo.lock | 2 +- .../src/contract/convertible_value.rs | 23 +++++++++++++++++-- bin/cliain/Cargo.lock | 2 +- e2e-tests/Cargo.lock | 2 +- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/aleph-client/Cargo.lock b/aleph-client/Cargo.lock index 396e04014d..139df3543d 100644 --- a/aleph-client/Cargo.lock +++ b/aleph-client/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.8.1" +version = "2.8.2" dependencies = [ "anyhow", "async-trait", diff --git a/aleph-client/src/contract/convertible_value.rs b/aleph-client/src/contract/convertible_value.rs index 06d6788d74..e2d97739ed 100644 --- a/aleph-client/src/contract/convertible_value.rs +++ b/aleph-client/src/contract/convertible_value.rs @@ -187,8 +187,8 @@ where } } -impl + Debug> TryFrom - for Vec +impl> TryFrom + for Vec { type Error = anyhow::Error; @@ -207,6 +207,18 @@ impl + Debug> TryFrom + Debug> + TryFrom for [Elem; N] +{ + type Error = anyhow::Error; + + fn try_from(value: ConvertibleValue) -> std::result::Result { + Vec::::try_from(value)? + .try_into() + .map_err(|e| anyhow!("Failed to convert vector to an array: {e:?}")) + } +} + #[cfg(test)] mod tests { use contract_transcode::Value::{Bool, Char, Int, Seq, UInt}; @@ -263,6 +275,13 @@ mod tests { assert_eq!(-41, cast); } + #[test] + fn converts_integer_array() { + let cv = ConvertibleValue(Seq(vec![UInt(4), UInt(1)].into())); + let cast: [u32; 2] = cv.try_into().expect("Should cast successfully"); + assert_eq!([4u32, 1u32], cast); + } + #[test] fn converts_integer_sequence() { let cv = ConvertibleValue(Seq(vec![UInt(4), UInt(1)].into())); diff --git a/bin/cliain/Cargo.lock b/bin/cliain/Cargo.lock index da53bb0948..8c90c9adcd 100644 --- a/bin/cliain/Cargo.lock +++ b/bin/cliain/Cargo.lock @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.8.1" +version = "2.8.2" dependencies = [ "anyhow", "async-trait", diff --git a/e2e-tests/Cargo.lock b/e2e-tests/Cargo.lock index 1f43006247..4584b3c142 100644 --- a/e2e-tests/Cargo.lock +++ b/e2e-tests/Cargo.lock @@ -78,7 +78,7 @@ dependencies = [ [[package]] name = "aleph_client" -version = "2.8.1" +version = "2.8.2" dependencies = [ "anyhow", "async-trait", From 4cf7ce3907f98810349e2c844cbfebe4a4f4a174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Miko=C5=82ajczyk?= Date: Thu, 19 Jan 2023 08:21:45 +0100 Subject: [PATCH 3/3] Simplify results --- aleph-client/src/contract/convertible_value.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/aleph-client/src/contract/convertible_value.rs b/aleph-client/src/contract/convertible_value.rs index e2d97739ed..fac6cda891 100644 --- a/aleph-client/src/contract/convertible_value.rs +++ b/aleph-client/src/contract/convertible_value.rs @@ -45,7 +45,7 @@ macro_rules! try_from_flat_value { impl TryFrom for $ty { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> Result<$ty, Self::Error> { + fn try_from(value: ConvertibleValue) -> anyhow::Result<$ty> { match value.0 { Value::$variant(value) => Ok(value.try_into()?), _ => anyhow::bail!("Expected {:?} to be {}", value, $desc), @@ -69,7 +69,7 @@ try_from_flat_value!(i128, Int, "signed integer"); impl TryFrom for AccountId { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> Result { + fn try_from(value: ConvertibleValue) -> Result { match value.0 { Value::Literal(value) => { AccountId::from_str(&value).map_err(|_| anyhow!("Invalid account id")) @@ -85,7 +85,7 @@ where { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> Result, Self::Error> { + fn try_from(value: ConvertibleValue) -> Result> { if let Value::Tuple(tuple) = &value.0 { match tuple.ident() { Some(x) if x == "Ok" => { @@ -115,7 +115,7 @@ where impl TryFrom for String { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> std::result::Result { + fn try_from(value: ConvertibleValue) -> Result { let seq = match value.0 { Value::Seq(seq) => seq, _ => bail!("Failed parsing `ConvertibleValue` to `String`. Expected `Seq(Value::UInt)` but instead got: {:?}", value), @@ -150,7 +150,7 @@ where { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> std::result::Result, Self::Error> { + fn try_from(value: ConvertibleValue) -> Result> { let tuple = match &value.0 { Value::Tuple(tuple) => tuple, _ => bail!("Expected {:?} to be a Some(_) or None Tuple.", &value), @@ -192,7 +192,7 @@ impl> TryFrom std::result::Result { + fn try_from(value: ConvertibleValue) -> Result { let seq = match value.0 { Value::Seq(seq) => seq, _ => bail!("Failed parsing `ConvertibleValue` to `Vec`. Expected `Seq(_)` but instead got: {:?}", value), @@ -212,7 +212,7 @@ impl + De { type Error = anyhow::Error; - fn try_from(value: ConvertibleValue) -> std::result::Result { + fn try_from(value: ConvertibleValue) -> Result { Vec::::try_from(value)? .try_into() .map_err(|e| anyhow!("Failed to convert vector to an array: {e:?}"))