#scale #decoding #parity

no-std scale-decode

在运行时将 SCALE 编码的字节解码为任意类型

12 次重大发布

0.13.1 2024年6月7日
0.12.0 2024年4月29日
0.11.1 2024年2月16日
0.10.0 2023年11月10日
0.3.0 2022年7月28日

#14 in #parity

Download history 7456/week @ 2024-05-04 9370/week @ 2024-05-11 15502/week @ 2024-05-18 31472/week @ 2024-05-25 30780/week @ 2024-06-01 23580/week @ 2024-06-08 25872/week @ 2024-06-15 32241/week @ 2024-06-22 27645/week @ 2024-06-29 25648/week @ 2024-07-06 36508/week @ 2024-07-13 37567/week @ 2024-07-20 33609/week @ 2024-07-27 37675/week @ 2024-08-03 47593/week @ 2024-08-10 34006/week @ 2024-08-17

159,326 每月下载量
106 个 crate (10 directly) 中使用

Apache-2.0

180KB
3K SLoC

scale-decode

此 crate 通过使用 TypeResolver(其中一个为 scale_info::PortableRegistry)简化了将 SCALE 编码的字节解码为自定义数据结构的操作。通过使用此类型信息来指导解码(而不是仅仅根据目标类型的形状尝试解码字节),可以更灵活地解码数据并将其映射到某些目标类型。

用于解码类型的主要特质是 Visitor 特质(以下为示例)。通过实现此特质,您可以描述如何将 SCALE 解码的值映射到您选择的某些自定义类型(无论是动态形状的类型还是您想要解码到的一些静态类型)。标准库中许多现有的 Rust 类型都有 Visitor 特质的实现。

还存在一个 IntoVisitor 特质,它被许多现有的 rust 类型实现,并将给定类型映射到能够解码到该类型的某个访问者实现。

最后,一个包装特质 DecodeAsType,为所有具有 IntoVisitor 实现的类型自动实现,并且其访问者错误可以被转换为标准 crate::Error

对于自定义的结构体和枚举,可以使用 DecodeAsType derive 宏来自动生成 DecodeAsType 实现。

以下是一个实现 Visitor 以将字节解码为自定义 Value 类型的示例

use std::marker::PhantomData;
use scale_decode::TypeResolver;
use scale_decode::visitor::{
    self,
    types::{Array, BitSequence, Composite, Sequence, Str, Tuple, Variant},
    TypeIdFor,
};

// A custom type we'd like to decode into:
#[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]),
    Sequence(Vec<Value>),
    Composite(Vec<(String, Value)>),
    Tuple(Vec<Value>),
    Str(String),
    Array(Vec<Value>),
    Variant(String, Vec<(String, Value)>),
    BitSequence(scale_bits::Bits),
}

// Implement the `Visitor` trait to define how to go from SCALE
// values into this type. Here, we are choosing to be generic over
// how types are resolved, which is a good default choice when creating
// a visitor unless you rely on a specific type resolver/ID type.
struct ValueVisitor<R>(PhantomData<R>);

impl<R> ValueVisitor<R> {
    fn new() -> Self {
        Self(PhantomData)
    }
}

impl<R: TypeResolver> visitor::Visitor for ValueVisitor<R> {
    type Value<'scale, 'resolver> = Value;
    type Error = visitor::DecodeError;
    type TypeResolver = R;

    fn visit_bool<'scale, 'resolver>(
        self,
        value: bool,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::Bool(value))
    }
    fn visit_char<'scale, 'resolver>(
        self,
        value: char,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::Char(value))
    }
    fn visit_u8<'scale, 'resolver>(
        self,
        value: u8,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U8(value))
    }
    fn visit_u16<'scale, 'resolver>(
        self,
        value: u16,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U16(value))
    }
    fn visit_u32<'scale, 'resolver>(
        self,
        value: u32,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U32(value))
    }
    fn visit_u64<'scale, 'resolver>(
        self,
        value: u64,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U64(value))
    }
    fn visit_u128<'scale, 'resolver>(
        self,
        value: u128,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U128(value))
    }
    fn visit_u256<'scale, 'resolver>(
        self,
        value: &'scale [u8; 32],
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::U256(*value))
    }
    fn visit_i8<'scale, 'resolver>(
        self,
        value: i8,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I8(value))
    }
    fn visit_i16<'scale, 'resolver>(
        self,
        value: i16,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I16(value))
    }
    fn visit_i32<'scale, 'resolver>(
        self,
        value: i32,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I32(value))
    }
    fn visit_i64<'scale, 'resolver>(
        self,
        value: i64,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I64(value))
    }
    fn visit_i128<'scale, 'resolver>(
        self,
        value: i128,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I128(value))
    }
    fn visit_i256<'scale, 'resolver>(
        self,
        value: &'scale [u8; 32],
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::I256(*value))
    }
    fn visit_sequence<'scale, 'resolver>(
        self,
        value: &mut Sequence<'scale, 'resolver, Self::TypeResolver>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        let mut vals = vec![];
        while let Some(val) = value.decode_item(ValueVisitor::new()) {
            let val = val?;
            vals.push(val);
        }
        Ok(Value::Sequence(vals))
    }
    fn visit_composite<'scale, 'resolver>(
        self,
        value: &mut Composite<'scale, 'resolver, Self::TypeResolver>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        let mut vals = vec![];
        for item in value.by_ref() {
            let item = item?;
            let val = item.decode_with_visitor(ValueVisitor::new())?;
            let name = item.name().unwrap_or("").to_owned();
            vals.push((name, val));
        }
        Ok(Value::Composite(vals))
    }
    fn visit_tuple<'scale, 'resolver>(
        self,
        value: &mut Tuple<'scale, 'resolver, Self::TypeResolver>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        let mut vals = vec![];
        while let Some(val) = value.decode_item(ValueVisitor::new()) {
            let val = val?;
            vals.push(val);
        }
        Ok(Value::Tuple(vals))
    }
    fn visit_str<'scale, 'resolver>(
        self,
        value: &mut Str<'scale>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        Ok(Value::Str(value.as_str()?.to_owned()))
    }
    fn visit_variant<'scale, 'resolver>(
        self,
        value: &mut Variant<'scale, 'resolver, Self::TypeResolver>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, 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::new())?;
            let name = item.name().unwrap_or("").to_owned();
            vals.push((name, val));
        }
        Ok(Value::Variant(value.name().to_owned(), vals))
    }
    fn visit_array<'scale, 'resolver>(
        self,
        value: &mut Array<'scale, 'resolver, Self::TypeResolver>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        let mut vals = vec![];
        while let Some(val) = value.decode_item(ValueVisitor::new()) {
            let val = val?;
            vals.push(val);
        }
        Ok(Value::Array(vals))
    }
    fn visit_bitsequence<'scale, 'resolver>(
        self,
        value: &mut BitSequence<'scale>,
        _type_id: &TypeIdFor<Self>,
    ) -> Result<Self::Value<'scale, 'resolver>, Self::Error> {
        let bools: Result<scale_bits::Bits, _> = value.decode()?.collect();
        Ok(Value::BitSequence(bools?))
    }
}

然后可以将其传递给解码函数,如下所示

let value: Value = scale_decode::visitor::decode_with_visitor(scale_bytes, &type_id, &types, ValueVisitor::new())?;

其中 scale_bytes 是要解码的字节,type_id 是存储在 types 注册表中的类型,您希望将其解码成字节,而 types 是一个包含有关使用中各种类型信息的 scale_type_resolver::TypeResolver(其具体实现为 scale_info::PortableRegistry)。

如果我们随后编写一个类似于下面的 IntoVisitor 实现

impl scale_decode::IntoVisitor for Value {
    type AnyVisitor<R: TypeResolver> = ValueVisitor<R>;
    fn into_visitor<R: TypeResolver>() -> Self::AnyVisitor<R> {
        ValueVisitor::new()
    }
}

然后我们也可以通过自动的 DecodeAsType 实现如下解码

use scale_decode::DecodeAsType;

let value = Value::decode_as_type(scale_bytes, type_id, types)?;

有了 IntoVisitor 实现,您还可以受益于以相同的方式解码类似 Vec<Value>(Value, bool)Arc<Value> 等内容。

依赖关系

~3.5MB
~75K SLoC