use super::TypeId;
use crate::prelude::*;
use crate::value_type::{Composite, Primitive, Value, ValueDef, Variant};
use scale_decode::FieldIter;
use scale_info::{form::PortableForm, Path, PortableRegistry};
pub use scale_decode::visitor::DecodeError;
pub fn decode_value_as_type(
data: &mut &[u8],
ty_id: TypeId,
types: &PortableRegistry,
) -> Result<Value<TypeId>, DecodeError> {
scale_decode::visitor::decode_with_visitor(data, ty_id, types, DecodeValueVisitor)
}
macro_rules! to_unnamed_composite {
($value:ident, $type_id:ident) => {{
let mut vals = Vec::with_capacity($value.remaining());
while let Some(val) = $value.decode_item(DecodeValueVisitor) {
let val = val?;
vals.push(val);
}
Ok(Value { value: ValueDef::Composite(Composite::Unnamed(vals)), context: $type_id.0 })
}};
}
impl scale_decode::DecodeAsFields for Composite<TypeId> {
fn decode_as_fields<'info>(
input: &mut &[u8],
fields: &mut dyn FieldIter<'info>,
types: &'info PortableRegistry,
) -> Result<Self, scale_decode::Error> {
static EMPTY_PATH: &Path<PortableForm> = &Path { segments: Vec::new() };
let mut composite =
scale_decode::visitor::types::Composite::new(input, EMPTY_PATH, fields, types, false);
let val = visit_composite(&mut composite);
composite.skip_decoding()?;
*input = composite.bytes_from_undecoded();
val.map_err(From::from)
}
}
pub struct DecodeValueVisitor;
impl scale_decode::IntoVisitor for Value<TypeId> {
type Visitor = scale_decode::visitor::VisitorWithCrateError<DecodeValueVisitor>;
fn into_visitor() -> Self::Visitor {
scale_decode::visitor::VisitorWithCrateError(DecodeValueVisitor)
}
}
impl scale_decode::visitor::Visitor for DecodeValueVisitor {
type Value<'scale, 'info> = Value<TypeId>;
type Error = DecodeError;
fn visit_bool<'scale, 'info>(
self,
value: bool,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::bool(value).map_context(|_| type_id.0))
}
fn visit_char<'scale, 'info>(
self,
value: char,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::char(value).map_context(|_| type_id.0))
}
fn visit_u8<'scale, 'info>(
self,
value: u8,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u128(value as u128, type_id)
}
fn visit_u16<'scale, 'info>(
self,
value: u16,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u128(value as u128, type_id)
}
fn visit_u32<'scale, 'info>(
self,
value: u32,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u128(value as u128, type_id)
}
fn visit_u64<'scale, 'info>(
self,
value: u64,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u128(value as u128, type_id)
}
fn visit_u128<'scale, 'info>(
self,
value: u128,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::u128(value).map_context(|_| type_id.0))
}
fn visit_u256<'info>(
self,
value: &'_ [u8; 32],
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
Ok(Value { value: ValueDef::Primitive(Primitive::U256(*value)), context: type_id.0 })
}
fn visit_i8<'scale, 'info>(
self,
value: i8,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_i128(value as i128, type_id)
}
fn visit_i16<'scale, 'info>(
self,
value: i16,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_i128(value as i128, type_id)
}
fn visit_i32<'scale, 'info>(
self,
value: i32,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_i128(value as i128, type_id)
}
fn visit_i64<'scale, 'info>(
self,
value: i64,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_i128(value as i128, type_id)
}
fn visit_i128<'scale, 'info>(
self,
value: i128,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::i128(value).map_context(|_| type_id.0))
}
fn visit_i256<'info>(
self,
value: &'_ [u8; 32],
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
Ok(Value { value: ValueDef::Primitive(Primitive::U256(*value)), context: type_id.0 })
}
fn visit_sequence<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Sequence<'scale, 'info>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
to_unnamed_composite!(value, type_id)
}
fn visit_tuple<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Tuple<'scale, 'info>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
to_unnamed_composite!(value, type_id)
}
fn visit_array<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Array<'scale, 'info>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
to_unnamed_composite!(value, type_id)
}
fn visit_bitsequence<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::BitSequence<'scale>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let bits: Result<_, _> = value.decode()?.collect();
Ok(Value { value: ValueDef::BitSequence(bits?), context: type_id.0 })
}
fn visit_str<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Str<'scale>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::string(value.as_str()?).map_context(|_| type_id.0))
}
fn visit_variant<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Variant<'scale, 'info>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let values = visit_composite(value.fields())?;
Ok(Value {
value: ValueDef::Variant(Variant { name: value.name().to_owned(), values }),
context: type_id.0,
})
}
fn visit_composite<'scale, 'info>(
self,
value: &mut scale_decode::visitor::types::Composite<'scale, 'info>,
type_id: scale_decode::visitor::TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value { value: ValueDef::Composite(visit_composite(value)?), context: type_id.0 })
}
}
fn visit_composite(
value: &mut scale_decode::visitor::types::Composite<'_, '_>,
) -> Result<Composite<TypeId>, DecodeError> {
let len = value.remaining();
let named = len > 0 && !value.has_unnamed_fields();
if named {
let mut vals = Vec::with_capacity(len);
let mut name = value.peek_name();
while let Some(v) = value.decode_item(DecodeValueVisitor) {
let v = v?;
vals.push((name.expect("all fields should be named; we have checked").to_owned(), v));
name = value.peek_name();
}
Ok(Composite::Named(vals))
} else {
let mut vals = Vec::with_capacity(len);
while let Some(v) = value.decode_item(DecodeValueVisitor) {
let v = v?;
vals.push(v);
}
Ok(Composite::Unnamed(vals))
}
}
#[cfg(test)]
mod test {
use crate::value;
use super::*;
use codec::{Compact, Encode};
fn make_type<T: scale_info::TypeInfo + 'static>() -> (TypeId, PortableRegistry) {
let m = scale_info::MetaType::new::<T>();
let mut types = scale_info::Registry::new();
let id = types.register_type(&m);
let portable_registry: PortableRegistry = types.into();
(id.id, portable_registry)
}
fn encode_decode_check<T: Encode + scale_info::TypeInfo + 'static>(val: T, exp: Value<()>) {
encode_decode_check_explicit_info::<T, _>(val, exp)
}
fn encode_decode_check_explicit_info<Ty: scale_info::TypeInfo + 'static, T: Encode>(
val: T,
ex: Value<()>,
) {
let encoded = val.encode();
let encoded = &mut &*encoded;
let (id, portable_registry) = make_type::<Ty>();
let val = decode_value_as_type(encoded, id, &portable_registry).expect("decoding failed");
assert_eq!(val.remove_context(), ex, "decoded value does not look like what we expected");
assert_eq!(encoded.len(), 0, "decoding did not consume all of the encoded bytes");
}
#[test]
fn decode_primitives() {
encode_decode_check(true, Value::bool(true));
encode_decode_check(false, Value::bool(false));
encode_decode_check_explicit_info::<char, _>('a' as u32, Value::char('a'));
encode_decode_check("hello", Value::string("hello"));
encode_decode_check(
"hello".to_string(), Value::string("hello"),
);
encode_decode_check(123u8, Value::u128(123));
encode_decode_check(123u16, Value::u128(123));
encode_decode_check(123u32, Value::u128(123));
encode_decode_check(123u64, Value::u128(123));
encode_decode_check(123u128, Value::u128(123));
encode_decode_check(123i8, Value::i128(123));
encode_decode_check(123i16, Value::i128(123));
encode_decode_check(123i32, Value::i128(123));
encode_decode_check(123i64, Value::i128(123));
encode_decode_check(123i128, Value::i128(123));
}
#[test]
fn decode_compact_primitives() {
encode_decode_check(Compact(123u8), Value::u128(123));
encode_decode_check(Compact(123u16), Value::u128(123));
encode_decode_check(Compact(123u32), Value::u128(123));
encode_decode_check(Compact(123u64), Value::u128(123));
encode_decode_check(Compact(123u128), Value::u128(123));
}
#[test]
fn decode_compact_named_wrapper_struct() {
#[derive(Encode, scale_info::TypeInfo)]
struct MyWrapper {
inner: u32,
}
impl From<Compact<MyWrapper>> for MyWrapper {
fn from(val: Compact<MyWrapper>) -> MyWrapper {
val.0
}
}
impl codec::CompactAs for MyWrapper {
type As = u32;
fn encode_as(&self) -> &Self::As {
&self.inner
}
fn decode_from(inner: Self::As) -> Result<Self, codec::Error> {
Ok(MyWrapper { inner })
}
}
encode_decode_check(
Compact(MyWrapper { inner: 123 }),
Value::named_composite(vec![("inner", Value::u128(123))]),
);
}
#[test]
fn decode_compact_unnamed_wrapper_struct() {
#[derive(Encode, scale_info::TypeInfo)]
struct MyWrapper(u32);
impl From<Compact<MyWrapper>> for MyWrapper {
fn from(val: Compact<MyWrapper>) -> MyWrapper {
val.0
}
}
impl codec::CompactAs for MyWrapper {
type As = u32;
fn encode_as(&self) -> &Self::As {
&self.0
}
fn decode_from(inner: Self::As) -> Result<Self, codec::Error> {
Ok(MyWrapper(inner))
}
}
encode_decode_check(
Compact(MyWrapper(123)),
Value::unnamed_composite(vec![Value::u128(123)]),
);
}
#[test]
fn decode_sequence_array_tuple_types() {
encode_decode_check(vec![1i32, 2, 3], value!((1, 2, 3)));
encode_decode_check(
[1i32, 2, 3], Value::unnamed_composite(vec![Value::i128(1), Value::i128(2), Value::i128(3)]),
);
encode_decode_check(
(1i32, true, 123456u128),
Value::unnamed_composite(vec![Value::i128(1), Value::bool(true), Value::u128(123456)]),
);
}
#[test]
fn decode_variant_types() {
#[derive(Encode, scale_info::TypeInfo)]
enum MyEnum {
Foo(bool),
Bar { hi: String, other: u128 },
}
encode_decode_check(
MyEnum::Foo(true),
Value::unnamed_variant("Foo", vec![Value::bool(true)]),
);
encode_decode_check(
MyEnum::Bar { hi: "hello".to_string(), other: 123 },
value!(Bar { hi: "hello", other: 123u32 }),
);
}
#[test]
fn decode_composite_types() {
#[derive(Encode, scale_info::TypeInfo)]
struct Unnamed(bool, String, Vec<u8>);
#[derive(Encode, scale_info::TypeInfo)]
struct Named {
is_valid: bool,
name: String,
bytes: Vec<u8>,
}
encode_decode_check(
Unnamed(true, "James".into(), vec![1, 2, 3]),
value!((true, "James", (1u8, 2u8, 3u8))),
);
encode_decode_check(
Named { is_valid: true, name: "James".into(), bytes: vec![1, 2, 3] },
value!({is_valid: true, name: "James", bytes: (1u8, 2u8, 3u8)}),
);
}
#[test]
fn decoding_zero_length_composites_always_unnamed() {
#[derive(Encode, scale_info::TypeInfo)]
struct Named {}
#[derive(Encode, scale_info::TypeInfo)]
struct Unnamed();
encode_decode_check(Unnamed(), Value::unnamed_composite(vec![]));
encode_decode_check(Named {}, Value::unnamed_composite(vec![]));
}
#[test]
fn decode_bit_sequence() {
use scale_bits::bits;
encode_decode_check(bits![0, 1, 1, 0, 1, 0], Value::bit_sequence(bits![0, 1, 1, 0, 1, 0]));
}
#[test]
fn decode_composite_fields() {
use codec::Encode;
use scale_decode::DecodeAsFields;
#[derive(Encode, scale_decode::DecodeAsType, scale_info::TypeInfo)]
struct Foo {
a: String,
b: bool,
c: u16,
}
let (id, types) = make_type::<Foo>();
let scale_info::TypeDef::Composite(c) = &types.resolve(id).unwrap().type_def else {
panic!("Couldn't get fields");
};
let mut fields =
c.fields.iter().map(|f| scale_decode::Field::new(f.ty.id, f.name.as_deref()));
let foo = Foo { a: "Hello".to_owned(), b: true, c: 123 };
let foo_bytes = foo.encode();
let foo_bytes_cursor = &mut &*foo_bytes;
let out = Composite::decode_as_fields(foo_bytes_cursor, &mut fields, &types)
.expect("can decode as fields")
.map_context(|_| ());
assert_eq!(
out,
Composite::named([
("a", Value::string("Hello")),
("b", Value::bool(true)),
("c", Value::u128(123))
])
);
assert_eq!(foo_bytes_cursor.len(), 0, "all bytes should have been consumed");
}
}