27 个版本 (稳定版)
2.11.3 | 2024 年 5 月 8 日 |
---|---|
2.11.1 | 2024 年 3 月 25 日 |
2.10.0 | 2023 年 10 月 20 日 |
2.9.0 | 2023 年 7 月 3 日 |
0.2.0 | 2020 年 6 月 17 日 |
#4 in #encodable
509,468 次每月下载
在 1,148 个 crate 中使用 (通过 scale-info)
44KB
786 行
scale-info ·
一个用于描述 Rust 类型的库,旨在提供有关 SCALE 可编码类型结构的详细信息。
这些定义提供了第三方工具(例如 UI 客户端)有关如何解码类型的信息,而无需考虑语言。
其核心是 TypeInfo
特性
pub trait TypeInfo {
type Identity: ?Sized + 'static;
fn type_info() -> Type;
}
实现此特性的类型将构建并返回一个 Type
结构
pub struct Type<T: Form = MetaForm> {
/// The unique path to the type. Can be empty for built-in types
path: Path<T>,
/// The generic type parameters of the type in use. Empty for non generic types
type_params: Vec<T::Type>,
/// The actual type definition
type_def: TypeDef<T>,
}
类型被定义为以下变体之一
pub enum TypeDef<T: Form = MetaForm> {
/// A composite type (e.g. a struct or a tuple)
Composite(TypeDefComposite<T>),
/// A variant type (e.g. an enum)
Variant(TypeDefVariant<T>),
/// A sequence type with runtime known length.
Sequence(TypeDefSequence<T>),
/// An array type with compile-time known length.
Array(TypeDefArray<T>),
/// A tuple type.
Tuple(TypeDefTuple<T>),
/// A Rust primitive type.
Primitive(TypeDefPrimitive),
}
内置类型定义
以下“内置”类型具有预定义的 TypeInfo
定义
-
基本类型:
bool
、char
、str
、u8
、u16
、u32
、u64
、u128
、i8
、i16
、i32
、i64
、i128
。 -
序列: 元素类型为
T
的可变大小序列,其中T
实现了TypeInfo
。例如:[T]
、&[T]
、&mut [T]
、Vec<T>
-
数组: 任何实现了
TypeInfo
的T
的固定大小[T: $n]
,其中$n
是预定义大小之一。 -
元组: 由最多 10 个字段组成,这些字段的类型实现了
TypeInfo
。
用户定义类型
用户定义类型有两种:Composite
和 Variant
。
两者都使用其定义中的 Path
和 Field
类型。
字段
表示用户定义类型的基本构建块是 Field
结构体,它定义了字段的 Type
以及其可选名称。用户定义类型的构建器强制执行以下不变性:所有字段都有一个名称(例如结构体)或所有字段都是未命名的(例如元组)。
路径
类型的路径是一系列标识符的唯一序列。Rust 类型通常从命名空间和标识符构建路径,例如 foo::bar::Baz
转换为路径 ["foo", "bar", "Baz"]
。
复合类型
复合数据类型 由一组 Fields
组成。
结构体 由一组 命名 字段表示,在构建过程中强制执行
struct Foo<T> {
bar: T,
data: u64,
}
impl<T> TypeInfo for Foo<T>
where
T: TypeInfo + 'static,
{
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.type_params(vec![MetaType::new::<T>()])
.composite(Fields::named()
.field(|f| f.ty::<T>().name("bar").type_name("T"))
.field(|f| f.ty::<u64>().name("data").type_name("u64"))
)
}
}
元组 由一组 未命名 字段表示,在构建过程中强制执行
struct Foo(u32, bool);
impl TypeInfo for Foo {
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.composite(Fields::unnamed()
.field(|f| f.ty::<u32>().type_name("u32"))
.field(|f| f.ty::<bool>().type_name("bool"))
)
}
}
变体
变体类型 即枚举或带标签的联合,由一组变体组成。变体可以具有未命名字段、命名字段或没有任何字段
enum Foo<T>{
A(T),
B { f: u32 },
C,
}
impl<T> TypeInfo for Foo<T>
where
T: TypeInfo + 'static,
{
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.type_params(vec![MetaType::new::<T>()])
.variant(
Variants::new()
.variant("A", |v| v.fields(Fields::unnamed().field(|f| f.ty::<T>())))
.variant("B", |v| v.fields(Fields::named().field(|f| f.ty::<u32>().name("f").type_name("u32"))))
.variant_unit("C")
)
}
}
如果没有变体包含字段,则可以显式设置区分符,由构建器在构建过程中强制执行
enum Foo {
A,
B,
C = 33,
}
impl TypeInfo for Foo {
type Identity = Self;
fn type_info() -> Type {
Type::builder()
.path(Path::new("Foo", module_path!()))
.variant(
Variants::new()
.variant("A", |v| v.index(1))
.variant("B", |v| v.index(2))
.variant("C", |v| v.index(33))
)
}
}
注册表
类型信息在所谓的类型注册表(Registry
)中提供。类型定义在此处注册,并关联唯一的 ID,外部可以引用这些 ID,以提供一种轻量级的方式来降低开销,而不是使用类型标识符。
所有具体的 TypeInfo
结构体有两种形式
- 一种元数据形式(
MetaType
),作为与其他形式之间的桥梁 - 一种适合序列化的可移植形式。
还必须实现 IntoPortable
特性,以便使用类型注册表的实例准备类型定义进行序列化。
转换后,所有类型定义都存储在类型注册表中。请注意,类型注册表应作为元数据结构的一部分进行序列化,其中注册的类型被用于允许消费者解析类型。
编码
类型注册表可以编码为
- JSON(启用“serde”功能)。
- SCALE 本身(使用
parity-scale-codec
)。
功能
以下可选的 cargo
功能可用:
- serde 包含了对类型注册表进行 json 序列化/反序列化的支持。请参见示例 这里。
- derive 重新导出
scale-info-derive
包。
已知问题
当为一个具有泛型紧凑字段的类型推导 TypeInfo
时,例如:
#[derive(Encode, TypeInfo)]
struct Foo<S> { #[codec(compact)] a: S }
当不使用正确的界限使用此泛型类型时,您可能会遇到以下错误:
error[E0275]: overflow evaluating the requirement `_::_parity_scale_codec::Compact<_>: Decode`
有关更多信息,请参阅 https://github.com/paritytech/scale-info/issues/65。
资源
- 有关描述
ink!
智能合约元数据的用法。 - 原始设计草案(已过时)
依赖关系
~2.5MB
~59K SLoC