Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aleph-client: Cast ConvertibleValue to a sequence #875

Merged
merged 4 commits into from
Jan 19, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion aleph-client/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion aleph-client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"

Expand Down
170 changes: 142 additions & 28 deletions aleph-client/src/contract/convertible_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,38 +40,31 @@ impl Deref for ConvertibleValue {
}
}

impl TryFrom<ConvertibleValue> for bool {
type Error = anyhow::Error;

fn try_from(value: ConvertibleValue) -> Result<bool, Self::Error> {
match value.0 {
Value::Bool(value) => Ok(value),
_ => bail!("Expected {:?} to be a boolean", value.0),
}
}
}

impl TryFrom<ConvertibleValue> for u128 {
type Error = anyhow::Error;
macro_rules! try_from_flat_value {
($ty: ty, $variant: ident, $desc: literal) => {
impl TryFrom<ConvertibleValue> for $ty {
type Error = anyhow::Error;

fn try_from(value: ConvertibleValue) -> Result<u128, Self::Error> {
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),
}
}
}
}
};
}
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved

impl TryFrom<ConvertibleValue> for u32 {
type Error = anyhow::Error;

fn try_from(value: ConvertibleValue) -> Result<u32, Self::Error> {
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<ConvertibleValue> for AccountId {
type Error = anyhow::Error;
Expand Down Expand Up @@ -193,3 +186,124 @@ where
}
}
}

impl<Elem: TryFrom<ConvertibleValue, Error = anyhow::Error>> TryFrom<ConvertibleValue>
for Vec<Elem>
{
type Error = anyhow::Error;

fn try_from(value: ConvertibleValue) -> std::result::Result<Self, Self::Error> {
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
let seq = match value.0 {
Value::Seq(seq) => seq,
_ => bail!("Failed parsing `ConvertibleValue` to `Vec<T>`. Expected `Seq(_)` but instead got: {:?}", value),
};

let mut result = vec![];
for element in seq.elems() {
result.push(ConvertibleValue(element.clone()).try_into()?);
}
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved

Ok(result)
}
}

impl<const N: usize, Elem: TryFrom<ConvertibleValue, Error = anyhow::Error> + Debug>
TryFrom<ConvertibleValue> for [Elem; N]
{
type Error = anyhow::Error;

fn try_from(value: ConvertibleValue) -> std::result::Result<Self, Self::Error> {
Vec::<Elem>::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};

use crate::contract::ConvertibleValue;

#[test]
fn converts_boolean() {
let cast: bool = ConvertibleValue(Bool(true))
.try_into()
.expect("Should cast successfully");
assert_eq!(true, cast);
pmikolajczyk41 marked this conversation as resolved.
Show resolved Hide resolved
}

#[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_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()));
let cast: Vec<u32> = 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::<Vec<_>>().into()))
.collect::<Vec<_>>();

let cv = ConvertibleValue(Seq(encoded_words.into()));
let cast: Vec<Vec<char>> = cv.try_into().expect("Should cast successfully");

assert_eq!(words, cast);
}
}
2 changes: 1 addition & 1 deletion bin/cliain/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion e2e-tests/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.