#codec #scale #tetsy #attributes #compact #deserialize #data

tetsy-scale-codec-derive

Tetsy SCALE Codec的序列化和反序列化宏

显示包…

4 个稳定版本

2.0.1 2021年2月20日
2.0.0 2021年2月18日
1.2.0 2021年3月10日
1.0.2 2021年2月20日

#53#tetsy

Download history 187/week @ 2024-03-11 232/week @ 2024-03-18 457/week @ 2024-03-25 406/week @ 2024-04-01 164/week @ 2024-04-08 321/week @ 2024-04-15 230/week @ 2024-04-22 213/week @ 2024-04-29 245/week @ 2024-05-06 213/week @ 2024-05-13 178/week @ 2024-05-20 206/week @ 2024-05-27 185/week @ 2024-06-03 180/week @ 2024-06-10 177/week @ 2024-06-17 307/week @ 2024-06-24

851 每月下载量
用于 175 个包中(通过 tetsy-scale-codec

Apache-2.0

41KB
991

Tetsy SCALE Codec

Rust 实现了 Tetsy Tetcore 框架中使用的 SCALE(简单串联聚合小端)数据格式。

SCALE 是一种轻量级格式,允许编码(和解析),这使得它非常适合资源受限的执行环境,如区块链运行时和低功耗、低内存设备。

需要注意的是,编码上下文(对类型和数据结构外观的了解)需要在编码和解码端单独知道。编码数据不包含此上下文信息。

要更好地了解不同类型的编码方式,请参阅 Tetcore 文档网站上的低级数据格式概述页面

实现

该编解码器使用以下特性实现:

编码

Encode 特性用于将数据编码为 SCALE 格式。 Encode 特性包含以下函数

  • size_hint(&self) -> usize:获取编码数据所需的容量(以字节为单位)。这是为了避免对编码所需的内存进行重复分配。这可以是一个估计值,不需要是一个确切的数字。如果大小未知,甚至没有良好的最大值,则可以从特性实现中省略此函数。这是一个需要廉价操作的操作,不应涉及迭代等。
  • encode_to<T: Output>(&self, dest: &mut T): 将值编码并附加到目标缓冲区。
  • encode(&self) -> Vec<u8>: 将类型数据编码并返回一个切片。
  • using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R: 将类型数据编码并在编码值上执行闭包。返回执行闭包的结果。

注意:实现应覆盖值类型的 using_encoded 和分配类型的 encode_to。尽可能实现所有类型的 size_hint。包装类型应覆盖所有方法。

解码

Decode 特性用于将编码数据反序列化/解码到相应类型。

  • fn decode<I: Input>(value: &mut I) -> Result<Self, Error>: 尝试将值从 SCALE 格式解码到调用该函数的类型。如果解码失败,则返回 Err

CompactAs

CompactAs 特性用于将自定义类型/结构体包装为紧凑类型,使其更加节省空间/内存。紧凑编码的描述 在这里

  • encode_as(&self) -> &Self::As: 将类型(self)编码为紧凑类型。类型 As 在相同的特性中定义,其实现应该是紧凑编码的。
  • decode_from(_: Self::As) -> Result<Self, Error>: 将类型(self)从紧凑编码类型解码。

HasCompact

如果实现了HasCompact特性,则表示相应的类型是一种紧凑编码类型。

EncodeLike

对于每种类型,都需要手动实现EncodeLike特性。当使用 derive 时,它会自动为您完成。基本上,这个特性给了您将多个类型传递到函数的机会,这些类型都编码成相同的表示。

使用示例

以下是一些演示 codec 使用的示例。

简单类型


use tetsy_scale_codec::{Encode, Decode};

#[derive(Debug, PartialEq, Encode, Decode)]
enum EnumType {
	#[codec(index = 15)]
	A,
	B(u32, u64),
	C {
		a: u32,
		b: u64,
	},
}

let a = EnumType::A;
let b = EnumType::B(1, 2);
let c = EnumType::C { a: 1, b: 2 };

a.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x0f");
});

b.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0");
});

c.using_encoded(|ref slice| {
    assert_eq!(slice, &b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0");
});

let mut da: &[u8] = b"\x0f";
assert_eq!(EnumType::decode(&mut da).ok(), Some(a));

let mut db: &[u8] = b"\x01\x01\0\0\0\x02\0\0\0\0\0\0\0";
assert_eq!(EnumType::decode(&mut db).ok(), Some(b));

let mut dc: &[u8] = b"\x02\x01\0\0\0\x02\0\0\0\0\0\0\0";
assert_eq!(EnumType::decode(&mut dc).ok(), Some(c));

let mut dz: &[u8] = &[0];
assert_eq!(EnumType::decode(&mut dz).ok(), None);

带有 HasCompact 的紧凑类型


use tetsy_scale_codec::{Encode, Decode, Compact, HasCompact};

#[derive(Debug, PartialEq, Encode, Decode)]
struct Test1CompactHasCompact<T: HasCompact> {
    #[codec(compact)]
    bar: T,
}

#[derive(Debug, PartialEq, Encode, Decode)]
struct Test1HasCompact<T: HasCompact> {
    #[codec(encoded_as = "<T as HasCompact>::Type")]
    bar: T,
}

let test_val: (u64, usize) = (0u64, 1usize);

let encoded = Test1HasCompact { bar: test_val.0 }.encode();
assert_eq!(encoded.len(), test_val.1);
assert_eq!(<Test1CompactHasCompact<u64>>::decode(&mut &encoded[..]).unwrap().bar, test_val.0);

带有 CompactAs 的类型


use serde_derive::{Serialize, Deserialize};
use tetsy_scale_codec::{Encode, Decode, Compact, HasCompact, CompactAs, Error};

#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(PartialEq, Eq, Clone)]
struct StructHasCompact(u32);

impl CompactAs for StructHasCompact {
    type As = u32;

    fn encode_as(&self) -> &Self::As {
        &12
    }

    fn decode_from(_: Self::As) -> Result<Self, Error> {
        Ok(StructHasCompact(12))
    }
}

impl From<Compact<StructHasCompact>> for StructHasCompact {
    fn from(_: Compact<StructHasCompact>) -> Self {
        StructHasCompact(12)
    }
}

#[derive(Debug, PartialEq, Encode, Decode)]
enum TestGenericHasCompact<T> {
    A {
        #[codec(compact)] a: T
    },
}

let a = TestGenericHasCompact::A::<StructHasCompact> {
    a: StructHasCompact(12325678),
};

let encoded = a.encode();
assert_eq!(encoded.len(), 2);

derive 属性

derive 实现支持以下属性

  • codec(dumb_trait_bound):此属性需要放在应该实现其中一个特性的类型上方。这将使确定要添加的特性边界的算法仅使用类型的类型参数。这在算法包括私有类型在公共接口中的情况下可能很有用。通过使用此属性,您应该不会再次收到此错误/警告。
  • codec(skip):需要放在字段或变体上方,使其在编码/解码时被跳过。
  • codec(compact):需要放在字段上方,并使字段使用紧凑编码。(类型需要支持紧凑编码。)
  • codec(encoded_as = "OtherType"):需要放在字段上方,并使字段使用 OtherType 进行编码。
  • codec(index = 0):需要放在枚举变体上方,以便在编码时使用给定的索引。默认情况下,索引是从 0 开始计数的,以第一个变体为起点。

许可证:Apache-2.0


lib.rs:

为复杂数据结构生成序列化和反序列化 codec,以进行简单的打包。

依赖关系

~2MB
~42K SLoC