5 версий
0.2.2 | 8 мар 2022 |
---|---|
0.2.1 | 7 мар 2022 |
0.2.0 | 4 мар 2022 |
0.1.1 | 3 мар 2022 |
0.1.0 | 1 мар 2022 |
#10 в #daml
Используется в daml
3MB
11K SLoC
Дамл Деривейт
Этот crate предоставляет proc макро для генерации Rust типов из daml
.
Этот crate не следует использовать напрямую, вместо этого вы должны зависеть от crate daml
и включить функцию derive
[dependencies]
daml = { version = "0.2.2", features = [ "derive" ] }
Лицензия
daml-derive
распространяется по условиям Лицензии Apache (Версия 2.0).
Если вы явно не указали иное, любая намеренная вкладка, представленная вам для включения в указанное время, как определено в Лицензии Apache-2.0, должна быть лицензирована дually, как выше, без дополнительных условий или условий.
Подробнее см. в LICENSE.
Авторское право 2022
lib.rs
:
Proc макро для генерации Rust типов и преобразований из типов и архивов Daml.
Обзор
Предоставляются два механизма для представления типов Daml в Rust
- Кастомные атрибуты, которые можно применить к структурам Rust, генерирующим конвертеры типов Daml.
- Генератор proc макро кода, который принимает файл
dar
Daml в качестве ввода и генерирует Rust типы с кастомными атрибутами.
Кастомные атрибуты
Этот раздел объясняет, как использовать предоставленные кастомные атрибуты для аннотирования Rust типов для генерации кода преобразований данных API Daml ledger, необходимого для использования их с Daml ledger.
Маппинг структур Daml к Rust
Структуры Daml моделируются с помощью различных конструкций языка Rust в сочетании с procedural macros кастомных атрибутов, как показано в следующей таблице
Концепция Daml | Конструкция Rust | Кастомный атрибут |
---|---|---|
Шаблон Daml | struct |
[macro@DamlTemplate ] |
Выбор шаблона Daml | impl блок |
[macro@DamlChoices ] |
Данные Daml (Запись) | struct |
[macro@DamlData ] |
Данные Daml (Вариант) | enum |
[macro@DamlVariant ] |
Эnum Daml | enum |
[宏@DamlEnum ] |
将Daml数据类型映射到Rust
以下表格列出了Daml内置原始类型和Rust类型别名之间的映射关系
Daml类型 | Rust类型别名 | 具体的Rust类型 | 注意 |
---|---|---|---|
Int |
DamlInt64 |
i64 |
|
Numeric |
DamlNumeric |
bigdecimal::BigDecimal |
注意:BigDecimal包将被替换 |
Text |
DamlText |
String |
|
Bool |
DamlBool |
bool |
|
Party |
DamlParty |
String |
|
Date |
DamlDate |
chrono::Date |
|
Time |
DamlTime |
chrono::DateTime |
|
() |
DamlUnit |
() |
|
ContractId a |
DamlContractId |
String |
注意:此映射可能发生变化 |
List a 或 [a] |
DamlList<T> |
Vec<T> |
type T 必须是另一个Rust类型别名 |
TextMap a |
DamlTextMap<T> |
HashMap<String, T> |
type T 必须是另一个Rust类型别名 |
Optional a |
DamlOptional<T> |
Option<T> |
type T 必须是另一个Rust类型别名 |
注意,这里仅为了方便显示具体的Rust类型,在所有情况下,都必须使用Rust类型别名来表示Daml结构,以便确定Daml类型。
泛型类型
泛型类型(List<T>
、TextMap<T>
和 Optional<T>
)可以自由嵌套到任意深度,并且可以在所有预期类型的上下文中使用,例如模板和数据字段以及选择参数。
例如,以下是一些有效的类型示例
let int: DamlInt64;
let party: DamlParty;
let opt_numeric: DamlOptional<DamlNumeric10>;
let list_of_int: DamlList<DamlInt64>;
let list_of_opt_int: DamlList<DamlOptional<DamlInt64>>;
let list_of_opt_map_party: DamlList<DamlOptional<DamlTextMap<DamlParty>>>;
let opt_list_data: DamlOptional<DamlList<MyData>>;
递归数据类型
Daml数据(记录和变体)可能是递归的。例如
data Foo = Foo
with
bar : Optional Text
foo : Foo
因此,宏@DamlData
和 宏@DamlVariant
类型可以递归定义。然而,在Rust中建模此类结构需要通过间接引用来持有任何递归定义的项目,通常通过堆分配智能指针,如 Box<T>
,以确保结构体或枚举的非无限大小(请参阅此处获取详细信息)。
因此,上述示例可以表示如下
#[DamlData]
pub struct Foo {
bar: DamlOptional<DamlText>,
foo: Box<Foo>,
}
注意,Box<T>
是目前唯一支持的间接引用形式,它可以在使用 T
的任何地方使用。
序言
上述所有Rust类型别名都定义在 prelude
模块中,可以通过使用 daml::prelude::*
来包含。
模块
使用此crate提供的自定义属性注解的Rust 结构体
和 枚举
类型不必须嵌套在映射Daml 模块
层级的Rust 模块
中。所有标准Rust名称解析和可见性规则都适用,因此建议尽可能镜像Daml层级结构,以避免命名空间冲突。
例如,在 Fuji.MyModule.MySubModule
Daml 模块中定义的 MyData
数据类型可能声明如下
mod fuji {
mod my_module {
mod my_sub_module {
use daml::prelude::*;
#[DamlData]
pub struct MyData {}
}
}
}
示例
给定以下在某个包的 Fuji.PingPong
模块中声明的 Daml 模板
template Ping
with
sender: Party
receiver: Party
count: Int
where
signatory sender
observer receiver
controller receiver can
ResetCount : ()
with
new_count: Int
do
create Pong with sender; receiver; count = new_count
return ()
可以使用 [宏@DamlTemplate
] 和 [宏@DamlChoices
] 自定义属性在 Rust 中表示
use daml::prelude::*;
#[DamlTemplate(package_id = r"...package id hash omitted...", module_name = "Fuji.PingPong")]
pub struct Ping {
pub sender: DamlParty,
pub receiver: DamlParty,
pub count: DamlInt64,
}
#[DamlChoices]
impl Ping {
#[ResetCount]
fn reset_count(&self, new_count: DamlInt64) {}
}
然后可以创建一个新的 Ping
let ping = Ping::new("Alice", "Bob", 0);
要在 Daml 账本上创建 Ping
模板的实例,需要构造一个针对我们的 ping
数据的特定 DamlCreateCommand
。这可以按如下方式完成
let create_ping_command = ping.create_command();
生成的 DamlCreateCommand
可以通过 DamlCommandService
或 DamlCommandSubmissionService
正常提交到 Daml 账本。
一旦在 Daml 账本上创建了合约实例并收到相应的 DamlCreatedEvent
,就可以将其转换为 Rust 类型,如下所示
let ping_contract: PingContract = created_event.try_into()?;
}
请注意,Daml 账本返回的 DamlCreatedEvent
转换为 PingContract
而不是普通的 Ping
。PingContract
类型是一个 结构体
,并提供访问 Ping
数据和合约 ID 的方法 data() -> Ping
和 id() -> &PingContractId
assert_eq!("Alice", ping_contract.data().sender);
assert_eq!("Bob", ping_contract.data().receiver);
assert_eq!(0, ping_contract.data().count);
assert_eq!("#0:0", ping_contract.id().contract_id);
注意: 合约 ID 可能会在将来重构为使用一个单独的类型。
PingContract
类型为 Daml 模板中定义的每个 choice
提供了一个方法,包括该 choice 可能具有的任何参数。要在 Daml 账本上执行一个 choice,需要一个针对我们的合约的特定 DamlExerciseCommand
。这可以按如下方式构建
let exercise_command = ping_contract.id().reset_count_command(5);
}
生成的 DamlExerciseCommand
可以通过 DamlCommandService
或 DamlCommandSubmissionService
正常提交到 Daml 账本。
请注意,choice 方法名称 必须 与 Daml choice 的名称(snake_case 格式)匹配,并且带有 _command
后缀,choice 参数 必须 在 Daml 和 Rust 表示之间匹配。
有关详细信息和使用示例,请参阅 [宏@DamlTemplate
]、[宏@DamlChoices
] 和 [宏@DamlData
] 的文档。
错误
当将 DamlError
(仅运行时)从 DamlValue
转换为注解类型失败时,将返回底层 try_into()
。
恐慌
如果检测到注解的 struct
、enum
或 impl
块中的错误,将引发恐慌(仅编译时)。
依赖关系
~7–10MB
~177K SLoC