mod decode;
pub mod types;
use scale_info::form::PortableForm;
use types::*;
pub use decode::decode_with_visitor;
pub trait Visitor: Sized {
type Value<'scale, 'info>;
type Error: From<DecodeError>;
fn unchecked_decode_as_type<'scale, 'info>(
self,
_input: &mut &'scale [u8],
_type_id: TypeId,
_types: &'info scale_info::PortableRegistry,
) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>> {
DecodeAsTypeResult::Skipped(self)
}
fn visit_unexpected<'scale, 'info>(
self,
unexpected: Unexpected,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Err(DecodeError::Unexpected(unexpected).into())
}
fn visit_bool<'scale, 'info>(
self,
_value: bool,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Bool)
}
fn visit_char<'scale, 'info>(
self,
_value: char,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Char)
}
fn visit_u8<'scale, 'info>(
self,
_value: u8,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U8)
}
fn visit_u16<'scale, 'info>(
self,
_value: u16,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U16)
}
fn visit_u32<'scale, 'info>(
self,
_value: u32,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U32)
}
fn visit_u64<'scale, 'info>(
self,
_value: u64,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U64)
}
fn visit_u128<'scale, 'info>(
self,
_value: u128,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U128)
}
fn visit_u256<'info>(
self,
_value: &'_ [u8; 32],
_type_id: TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::U256)
}
fn visit_i8<'scale, 'info>(
self,
_value: i8,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I8)
}
fn visit_i16<'scale, 'info>(
self,
_value: i16,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I16)
}
fn visit_i32<'scale, 'info>(
self,
_value: i32,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I32)
}
fn visit_i64<'scale, 'info>(
self,
_value: i64,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I64)
}
fn visit_i128<'scale, 'info>(
self,
_value: i128,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I128)
}
fn visit_i256<'info>(
self,
_value: &'_ [u8; 32],
_type_id: TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::I256)
}
fn visit_sequence<'scale, 'info>(
self,
_value: &mut Sequence<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Sequence)
}
fn visit_composite<'scale, 'info>(
self,
_value: &mut Composite<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Composite)
}
fn visit_tuple<'scale, 'info>(
self,
_value: &mut Tuple<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Tuple)
}
fn visit_str<'scale, 'info>(
self,
_value: &mut Str<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Str)
}
fn visit_variant<'scale, 'info>(
self,
_value: &mut Variant<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Variant)
}
fn visit_array<'scale, 'info>(
self,
_value: &mut Array<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Array)
}
fn visit_bitsequence<'scale, 'info>(
self,
_value: &mut BitSequence<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_unexpected(Unexpected::Bitsequence)
}
fn visit_compact_u8<'scale, 'info>(
self,
value: Compact<u8>,
type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u8(value.value(), type_id)
}
fn visit_compact_u16<'scale, 'info>(
self,
value: Compact<u16>,
type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u16(value.value(), type_id)
}
fn visit_compact_u32<'scale, 'info>(
self,
value: Compact<u32>,
type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u32(value.value(), type_id)
}
fn visit_compact_u64<'scale, 'info>(
self,
value: Compact<u64>,
type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u64(value.value(), type_id)
}
fn visit_compact_u128<'scale, 'info>(
self,
value: Compact<u128>,
type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
self.visit_u128(value.value(), type_id)
}
}
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
pub enum DecodeError {
#[error("Cannot decode bit sequence: {0}")]
BitSequenceError(#[from] BitSequenceError),
#[error("Could not decode compact encoded type into {0:?}")]
CannotDecodeCompactIntoType(scale_info::Type<PortableForm>),
#[error("Could not decode string: {0}")]
InvalidStr(#[from] std::str::Utf8Error),
#[error("{0} is expected to be a valid char, but is not")]
InvalidChar(u32),
#[error("Ran out of data during decoding")]
NotEnoughInput,
#[error("Could not find variant with index {0} in {1:?}")]
VariantNotFound(u8, scale_info::TypeDefVariant<PortableForm>),
#[error("{0}")]
CodecError(#[from] codec::Error),
#[error("Cannot find type with ID {0}")]
TypeIdNotFound(u32),
#[error("Unexpected type {0}")]
Unexpected(Unexpected),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(missing_docs)]
pub enum Unexpected {
Bool,
Char,
U8,
U16,
U32,
U64,
U128,
U256,
I8,
I16,
I32,
I64,
I128,
I256,
Sequence,
Composite,
Tuple,
Str,
Variant,
Array,
Bitsequence,
}
impl std::fmt::Display for Unexpected {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Unexpected::Bool => "bool",
Unexpected::Char => "char",
Unexpected::U8 => "u8",
Unexpected::U16 => "u16",
Unexpected::U32 => "u32",
Unexpected::U64 => "u64",
Unexpected::U128 => "u128",
Unexpected::U256 => "u256",
Unexpected::I8 => "i8",
Unexpected::I16 => "i16",
Unexpected::I32 => "i32",
Unexpected::I64 => "i64",
Unexpected::I128 => "i128",
Unexpected::I256 => "i256",
Unexpected::Sequence => "sequence",
Unexpected::Composite => "composite",
Unexpected::Tuple => "tuple",
Unexpected::Str => "str",
Unexpected::Variant => "variant",
Unexpected::Array => "array",
Unexpected::Bitsequence => "bitsequence",
};
f.write_str(s)
}
}
pub enum DecodeAsTypeResult<V, R> {
Skipped(V),
Decoded(R),
}
pub trait DecodeItemIterator<'scale, 'info> {
fn decode_item<V: Visitor>(
&mut self,
visitor: V,
) -> Option<Result<V::Value<'scale, 'info>, V::Error>>;
}
pub type BitSequenceError = scale_bits::scale::format::FromMetadataError;
#[derive(Clone, Copy, Debug, Default)]
pub struct TypeId(pub u32);
pub struct IgnoreVisitor;
impl Visitor for IgnoreVisitor {
type Value<'scale, 'info> = ();
type Error = DecodeError;
fn visit_unexpected<'scale, 'info>(
self,
_unexpected: Unexpected,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(())
}
}
#[cfg(test)]
mod test {
use crate::visitor::TypeId;
use super::*;
use codec::{self, Encode};
use scale_info::PortableRegistry;
#[derive(Debug, PartialEq)]
enum Value {
Bool(bool),
Char(char),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
U256([u8; 32]),
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
I256([u8; 32]),
CompactU8(Vec<Loc>, u8),
CompactU16(Vec<Loc>, u16),
CompactU32(Vec<Loc>, u32),
CompactU64(Vec<Loc>, u64),
CompactU128(Vec<Loc>, u128),
Sequence(Vec<Value>),
Composite(Vec<(String, Value)>),
Tuple(Vec<Value>),
Str(String),
Array(Vec<Value>),
Variant(String, Vec<(String, Value)>),
BitSequence(scale_bits::Bits),
}
#[derive(Clone, Debug, PartialEq)]
enum Loc {
Unnamed,
Named(String),
Primitive,
}
impl<'a> From<CompactLocation<'a>> for Loc {
fn from(l: CompactLocation) -> Self {
match l {
CompactLocation::UnnamedComposite(_) => Loc::Unnamed,
CompactLocation::NamedComposite(_, s) => Loc::Named(s.to_owned()),
CompactLocation::Primitive(_) => Loc::Primitive,
}
}
}
struct ValueVisitor;
impl Visitor for ValueVisitor {
type Value<'scale, 'info> = Value;
type Error = DecodeError;
fn visit_bool<'scale, 'info>(
self,
value: bool,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::Bool(value))
}
fn visit_char<'scale, 'info>(
self,
value: char,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::Char(value))
}
fn visit_u8<'scale, 'info>(
self,
value: u8,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::U8(value))
}
fn visit_u16<'scale, 'info>(
self,
value: u16,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::U16(value))
}
fn visit_u32<'scale, 'info>(
self,
value: u32,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::U32(value))
}
fn visit_u64<'scale, 'info>(
self,
value: u64,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::U64(value))
}
fn visit_u128<'scale, 'info>(
self,
value: u128,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::U128(value))
}
fn visit_u256<'info>(
self,
value: &'_ [u8; 32],
_type_id: TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
Ok(Value::U256(*value))
}
fn visit_i8<'scale, 'info>(
self,
value: i8,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::I8(value))
}
fn visit_i16<'scale, 'info>(
self,
value: i16,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::I16(value))
}
fn visit_i32<'scale, 'info>(
self,
value: i32,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::I32(value))
}
fn visit_i64<'scale, 'info>(
self,
value: i64,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::I64(value))
}
fn visit_i128<'scale, 'info>(
self,
value: i128,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::I128(value))
}
fn visit_i256<'info>(
self,
value: &'_ [u8; 32],
_type_id: TypeId,
) -> Result<Self::Value<'_, 'info>, Self::Error> {
Ok(Value::I256(*value))
}
fn visit_compact_u8<'scale, 'info>(
self,
value: Compact<u8>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let locs = value.locations().iter().map(|&l| l.into()).collect();
Ok(Value::CompactU8(locs, value.value()))
}
fn visit_compact_u16<'scale, 'info>(
self,
value: Compact<u16>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let locs = value.locations().iter().map(|&l| l.into()).collect();
Ok(Value::CompactU16(locs, value.value()))
}
fn visit_compact_u32<'scale, 'info>(
self,
value: Compact<u32>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let locs = value.locations().iter().map(|&l| l.into()).collect();
Ok(Value::CompactU32(locs, value.value()))
}
fn visit_compact_u64<'scale, 'info>(
self,
value: Compact<u64>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let locs = value.locations().iter().map(|&l| l.into()).collect();
Ok(Value::CompactU64(locs, value.value()))
}
fn visit_compact_u128<'scale, 'info>(
self,
value: Compact<u128>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let locs = value.locations().iter().map(|&l| l.into()).collect();
Ok(Value::CompactU128(locs, value.value()))
}
fn visit_sequence<'scale, 'info>(
self,
value: &mut Sequence<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = vec![];
while let Some(val) = value.decode_item(ValueVisitor) {
let val = val?;
vals.push(val);
}
Ok(Value::Sequence(vals))
}
fn visit_composite<'scale, 'info>(
self,
value: &mut Composite<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = vec![];
for item in value.by_ref() {
let item = item?;
let val = item.decode_with_visitor(ValueVisitor)?;
let name = item.name().unwrap_or("").to_owned();
vals.push((name, val));
}
Ok(Value::Composite(vals))
}
fn visit_tuple<'scale, 'info>(
self,
value: &mut Tuple<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = vec![];
while let Some(val) = value.decode_item(ValueVisitor) {
let val = val?;
vals.push(val);
}
Ok(Value::Tuple(vals))
}
fn visit_str<'scale, 'info>(
self,
value: &mut Str<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
Ok(Value::Str(value.as_str()?.to_owned()))
}
fn visit_variant<'scale, 'info>(
self,
value: &mut Variant<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = vec![];
let fields = value.fields();
for item in fields.by_ref() {
let item = item?;
let val = item.decode_with_visitor(ValueVisitor)?;
let name = item.name().unwrap_or("").to_owned();
vals.push((name, val));
}
Ok(Value::Variant(value.name().to_owned(), vals))
}
fn visit_array<'scale, 'info>(
self,
value: &mut Array<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = vec![];
while let Some(val) = value.decode_item(ValueVisitor) {
let val = val?;
vals.push(val);
}
Ok(Value::Array(vals))
}
fn visit_bitsequence<'scale, 'info>(
self,
value: &mut BitSequence<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let bools: Result<scale_bits::Bits, _> = value.decode()?.collect();
Ok(Value::BitSequence(bools?))
}
}
fn make_type<T: scale_info::TypeInfo + 'static>() -> (u32, 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_explicit_info<Ty: scale_info::TypeInfo + 'static, T: Encode>(
val: T,
expected: Value,
) {
let encoded = val.encode();
let (id, types) = make_type::<Ty>();
let bytes = &mut &*encoded;
let val = decode_with_visitor(bytes, id, &types, ValueVisitor)
.expect("decoding should not error");
assert_eq!(bytes.len(), 0, "Decoding should consume all bytes");
assert_eq!(val, expected);
}
fn encode_decode_check<T: Encode + scale_info::TypeInfo + 'static>(val: T, expected: Value) {
encode_decode_check_explicit_info::<T, T>(val, expected);
}
#[test]
fn encode_decode_primitives() {
encode_decode_check(123u8, Value::U8(123));
encode_decode_check(123u16, Value::U16(123));
encode_decode_check(123u32, Value::U32(123));
encode_decode_check(123u64, Value::U64(123));
encode_decode_check(123u128, Value::U128(123));
encode_decode_check(codec::Compact(123u8), Value::CompactU8(vec![Loc::Primitive], 123));
encode_decode_check(codec::Compact(123u16), Value::CompactU16(vec![Loc::Primitive], 123));
encode_decode_check(codec::Compact(123u32), Value::CompactU32(vec![Loc::Primitive], 123));
encode_decode_check(codec::Compact(123u64), Value::CompactU64(vec![Loc::Primitive], 123));
encode_decode_check(codec::Compact(123u128), Value::CompactU128(vec![Loc::Primitive], 123));
encode_decode_check(true, Value::Bool(true));
encode_decode_check(false, Value::Bool(false));
encode_decode_check_explicit_info::<char, _>('c' as u32, Value::Char('c'));
encode_decode_check("Hello there", Value::Str("Hello there".to_owned()));
encode_decode_check("Hello there".to_string(), Value::Str("Hello there".to_owned()));
}
#[test]
fn decode_compact_named_wrapper_struct() {
#[derive(Encode, scale_info::TypeInfo)]
struct MyWrapper {
inner: u32,
}
impl From<codec::Compact<MyWrapper>> for MyWrapper {
fn from(val: codec::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(
codec::Compact(MyWrapper { inner: 123 }),
Value::CompactU32(vec![Loc::Named("inner".to_owned()), Loc::Primitive], 123),
);
}
#[test]
fn decode_compact_unnamed_wrapper_struct() {
#[derive(Encode, scale_info::TypeInfo)]
struct MyWrapper(u32);
impl From<codec::Compact<MyWrapper>> for MyWrapper {
fn from(val: codec::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(
codec::Compact(MyWrapper(123)),
Value::CompactU32(vec![Loc::Unnamed, Loc::Primitive], 123),
);
}
#[test]
fn decode_sequence_array_tuple_types() {
encode_decode_check(
vec![1i32, 2, 3],
Value::Sequence(vec![Value::I32(1), Value::I32(2), Value::I32(3)]),
);
encode_decode_check(
[1i32, 2, 3], Value::Array(vec![Value::I32(1), Value::I32(2), Value::I32(3)]),
);
encode_decode_check(
(1i32, true, 123456u128),
Value::Tuple(vec![Value::I32(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::Variant("Foo".to_owned(), vec![(String::new(), Value::Bool(true))]),
);
encode_decode_check(
MyEnum::Bar { hi: "hello".to_string(), other: 123 },
Value::Variant(
"Bar".to_owned(),
vec![
("hi".to_string(), Value::Str("hello".to_string())),
("other".to_string(), Value::U128(123)),
],
),
);
}
#[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::Composite(vec![
(String::new(), Value::Bool(true)),
(String::new(), Value::Str("James".to_string())),
(String::new(), Value::Sequence(vec![Value::U8(1), Value::U8(2), Value::U8(3)])),
]),
);
encode_decode_check(
Named { is_valid: true, name: "James".into(), bytes: vec![1, 2, 3] },
Value::Composite(vec![
("is_valid".to_string(), Value::Bool(true)),
("name".to_string(), Value::Str("James".to_string())),
(
"bytes".to_string(),
Value::Sequence(vec![Value::U8(1), Value::U8(2), Value::U8(3)]),
),
]),
);
}
#[test]
fn decode_arrays() {
encode_decode_check(
[1u8, 2, 3],
Value::Array(vec![Value::U8(1), Value::U8(2), Value::U8(3)]),
)
}
#[test]
fn decode_bit_sequence() {
use bitvec::{
bitvec,
order::{Lsb0, Msb0},
};
use scale_bits::bits;
encode_decode_check(bits![0, 1, 1, 0, 1, 0], Value::BitSequence(bits![0, 1, 1, 0, 1, 0]));
encode_decode_check(
bitvec![u8, Lsb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u16, Lsb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u32, Lsb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u64, Lsb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u8, Msb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u16, Msb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u32, Msb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
encode_decode_check(
bitvec![u64, Msb0; 0, 1, 1, 0, 1, 0],
Value::BitSequence(bits![0, 1, 1, 0, 1, 0]),
);
}
#[test]
fn zero_copy_string_decoding() {
let input = ("hello", "world");
let input_encoded = input.encode();
struct ZeroCopyStrVisitor;
impl Visitor for ZeroCopyStrVisitor {
type Value<'scale, 'info> = &'scale str;
type Error = DecodeError;
fn visit_str<'scale, 'info>(
self,
value: &mut Str<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
value.as_str()
}
}
struct ZeroCopyPairVisitor;
impl Visitor for ZeroCopyPairVisitor {
type Value<'scale, 'info> = (&'scale str, &'scale str);
type Error = DecodeError;
fn visit_tuple<'scale, 'info>(
self,
value: &mut Tuple<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let fst = value.decode_item(ZeroCopyStrVisitor).unwrap()?;
let snd = value.decode_item(ZeroCopyStrVisitor).unwrap()?;
Ok((fst, snd))
}
}
let (ty_id, types) = make_type::<(&str, &str)>();
let decoded =
decode_with_visitor(&mut &*input_encoded, ty_id, &types, ZeroCopyPairVisitor).unwrap();
assert_eq!(decoded, ("hello", "world"));
}
#[test]
fn zero_copy_using_info_and_scale_lifetimes() {
use std::collections::BTreeMap;
#[derive(codec::Encode, scale_info::TypeInfo)]
struct Foo {
hello: String,
world: String,
}
let input_encoded = Foo { hello: "hi".to_string(), world: "planet".to_string() }.encode();
struct ZeroCopyStrVisitor;
impl Visitor for ZeroCopyStrVisitor {
type Value<'scale, 'info> = &'scale str;
type Error = DecodeError;
fn visit_str<'scale, 'info>(
self,
value: &mut Str<'scale>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
value.as_str()
}
}
struct ZeroCopyMapVisitor;
impl Visitor for ZeroCopyMapVisitor {
type Value<'scale, 'info> = std::collections::BTreeMap<&'info str, &'scale str>;
type Error = DecodeError;
fn visit_composite<'scale, 'info>(
self,
value: &mut Composite<'scale, 'info>,
_type_id: TypeId,
) -> Result<Self::Value<'scale, 'info>, Self::Error> {
let mut vals = std::collections::BTreeMap::<&'info str, &'scale str>::new();
for item in value {
let item = item?;
let Some(key) = item.name() else { continue };
let val = item.decode_with_visitor(ZeroCopyStrVisitor)?;
vals.insert(key, val);
}
Ok(vals)
}
}
let (ty_id, types) = make_type::<Foo>();
let decoded =
decode_with_visitor(&mut &*input_encoded, ty_id, &types, ZeroCopyMapVisitor).unwrap();
assert_eq!(decoded, BTreeMap::from_iter([("hello", "hi"), ("world", "planet")]));
}
#[test]
fn bailout_works() {
let input = ("hello", "world");
let (ty_id, types) = make_type::<(&str, &str)>();
let input_encoded = input.encode();
struct BailOutVisitor;
impl Visitor for BailOutVisitor {
type Value<'scale, 'info> = (&'scale [u8], u32);
type Error = DecodeError;
fn unchecked_decode_as_type<'scale, 'info>(
self,
input: &mut &'scale [u8],
type_id: TypeId,
_types: &'info scale_info::PortableRegistry,
) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>>
{
DecodeAsTypeResult::Decoded(Ok((*input, type_id.0)))
}
}
let decoded =
decode_with_visitor(&mut &*input_encoded, ty_id, &types, BailOutVisitor).unwrap();
assert_eq!(decoded, (&*input_encoded, ty_id));
struct CodecDecodeVisitor<T>(std::marker::PhantomData<T>);
impl<T: codec::Decode> Visitor for CodecDecodeVisitor<T> {
type Value<'scale, 'info> = T;
type Error = DecodeError;
fn unchecked_decode_as_type<'scale, 'info>(
self,
input: &mut &'scale [u8],
_type_id: TypeId,
_types: &'info scale_info::PortableRegistry,
) -> DecodeAsTypeResult<Self, Result<Self::Value<'scale, 'info>, Self::Error>>
{
DecodeAsTypeResult::Decoded(T::decode(input).map_err(|e| e.into()))
}
}
let decoded: (String, String) = decode_with_visitor(
&mut &*input_encoded,
ty_id,
&types,
CodecDecodeVisitor(std::marker::PhantomData),
)
.unwrap();
assert_eq!(decoded, ("hello".to_string(), "world".to_string()));
}
}