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 макро кода, который принимает файл
darDaml в качестве ввода и генерирует 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