1个不稳定版本
0.1.0 | 2022年4月15日 |
---|
#1254 in 过程宏
86KB
1.5K SLoC
serde_dhall_typegen
这是一个宏,可以从Dhall类型自动生成Rust结构体和枚举。然后可以使用serde_dhall
crate将这些类型的Dhall值反序列化到Rust中。
目前可定制性有限,生成的Rust代码可能会频繁更改,因此仅建议在Dhall模式频繁更改时使用此crate进行原型设计。
用法
在以下mod
中创建与Dhall类型兼容的Rust类型,这些类型包含在指定的文件夹中。可以在此mod
块中包含手写的impl
。默认情况下,生成的类型名称与定义它们的Dhall文件的Pascal大小写相同(例如,my_type.dhall
-> MyType
),但可以通过Dhall元数据覆盖(见Dhall元数据)。默认情况下,这些文件中包含的任何子联合或记录将分配一个任意的名称(这可能会在编译之间更改)。
示例 my_dhall_stuff.rs
#[serde_dhall_typegen::dhall_types("./dhall/schema/")]
mod dhall { }
参数
- 到.dhall文件目录的字符串字面路径
- 形式为
name = literal
的可选参数impl = bool
- 是否为所有类型生成函数?相当于设置named_impl
和anonymous_impl
named_impl = bool
- 是否为命名类型生成函数?相当于设置named_enum_impl
和named_struct_impl
anonymous_impl = bool
- 是否为匿名类型生成函数?相当于设置anonymous_enum_impl
和anonymous_struct_impl
named_enum_impl = bool
- 是否为匿名枚举生成变体访问函数?默认为false
named_struct_impl = bool
- 是否为匿名结构体生成成员访问函数?默认为false
anonymous_enum_impl = bool
- 是否为匿名枚举生成成员访问函数?默认为true
anonymous_struct_impl = bool
- 是否为匿名结构体生成成员访问函数?默认为false
Dhall 输入
指定目录中的每个 .dhall 文件都将被评估,并必须返回一个记录、一个联合、一个 模式,或一个接受单个 Type
参数并返回前述类型之一的函数。
泛型类型
dhall_types
支持,当提供包含类型为 Type -> Type
的函数的 Dhall 文件时,生成具有单个类型参数的类型。类型参数将命名为 T
。与非泛型类型一样,如果可能,成员类型将被解释为泛型类型的实例。例如:
my_generic.dhall
\(T: Type) -> {
field: T
}
my_type.dhall
let MyGeneric = ./my_generic.dhall
{
a: MyGeneric Natural,
b: { field: Text },
}
... 变为...
pub struct MyGeneric<T> {
pub field: T,
}
pub struct MyType {
a: MyGeneric<u64>,
b: MyGeneric<String>,
}
生成的函数
默认情况下,匿名枚举为每个变体生成函数。如果变体 MyVariant
有关联类型 T
,枚举将具有以下函数
fn my_variant(&self) -> Option<&T>
fn my_variant_mut(&mut self) -> Option<&mut T>
fn into_my_variant(self) -> Result<T, Self>
如果变体没有关联类型,它将具有以下函数
fn is_my_variant(&self) -> bool
如果启用了结构体函数,类型为 T
的字段 my_field
将具有以下函数
fn my_field(&self) -> &T
fn my_field_mut(&mut self) -> &mut T
Dhall 元数据
由于 Dhall 和 Rust 的类型系统存在根本性的差异,因此在 Dhall 中可能需要进行一些非功能性的更改,以生成您打算使用的 Rust 类型。Dhall 的类型是 结构化 的,因此两个文件中具有相同结构的两个类型在 Dhall 看来是相同的类型。然而,当生成 Rust 类型时,这被认为是错误,因为它在确定给定 Dhall 类型应使用哪个 Rust 类型时会产生歧义。
为了避免这个问题,您可以为您的相同 Dhall 类型分配 'name 元数据',以便在评估期间区分它们。这不会影响您在其他上下文中的 Dhall 类型 - 结果的 Dhall 类型仅在设置特定环境变量时才会修改。
第一种方法可用于记录或联合,并且在类型之前
file_a.dhall
env:rust_type ? (\(T: Type)->\(T: Type)->T) <MyEnumA>
< A | B >
file_b.dhall
env:rust_type ? (\(T: Type)->\(T: Type)->T) <MyEnumB>
< A | B >
... 生成...
pub enum MyEnumA {
A,
B,
}
pub enum MyEnumB {
A,
B,
}
第二种方法更简洁,但只能用于记录,并且在类型之后
{
name: Text
}
//\\ (env:rust_type <MyStructA> ? {})
{
name: Text
}
//\\ (env:rust_type <MyStructB> ? {})
... 生成...
pub struct MyStructA {
pub name: String,
}
pub struct MyStructB {
pub name: String,
}
您可以使用 let
绑定来减少冗长
let rust_type = env:rust_type ? (\(T: Type)->\(T: Type)->T)
let rust_struct = \(T: Type) -> (env:rust_struct T ? {})
let Abc = rust_type <Abc> < A | B | C >
let Def = rust_type <Def> < D | E | F >
let Ghi = { g: Bool, h: Bool, i: Bool } //\\ (rust_struct <Ghi>)
let Jkl = { j: Bool, k: Bool, l: Bool } //\\ (rust_struct <Jkl>)
示例
之前
./dhall/schema/person.dhall
{
name: Text,
age_range: <
Baby |
Toddler |
Child |
Teenager |
Adult |
Senior
>,
occupation: Optional {
title: Text,
salary: Natural,
}
}
./src/dhall.rs
#[serde_dhall_typegen::dhall_types("./dhall/schema/")]
mod dhall { }
之后
./src/dhall.rs (相当于)
mod dhall {
#[derive(Debug, Clone, Eq, PartialEq, Hash, ::serde::Serialize, ::serde::Deserialize)]
pub struct Person {
pub age_range: PersonAnon0,
pub name: String,
pub occupation: Option<PersonAnon1>,
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, ::serde::Serialize, ::serde::Deserialize)]
pub enum PersonAnon0 {
Teenager,
Senior,
Baby,
Toddler,
Child,
Adult,
}
impl PersonAnon0 {
pub fn is_teenager(&self) -> bool {
match self {
Self::Teenager => true,
_ => false,
}
}
pub fn is_senior(&self) -> bool {
match self {
Self::Senior => true,
_ => false,
}
}
pub fn is_baby(&self) -> bool {
match self {
Self::Baby => true,
_ => false,
}
}
pub fn is_toddler(&self) -> bool {
match self {
Self::Toddler => true,
_ => false,
}
}
pub fn is_child(&self) -> bool {
match self {
Self::Child => true,
_ => false,
}
}
pub fn is_adult(&self) -> bool {
match self {
Self::Adult => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, ::serde::Serialize, ::serde::Deserialize)]
pub struct PersonAnon1 {
pub salary: u64,
pub title: String,
}
}
当前限制
- 提供的目录中的所有 .dhall 文件都必须有效并满足类型要求,否则编译将失败。
- 所有生成的结构体都具有公共成员。
- 生成的函数是全部或无,您不能排除可变访问函数,例如。
- 无法将属性应用于生成的结构体和枚举(例如
#[non_exhaustive]
)。 - Dhall 模式中的默认值被忽略。
- 每个类型仅支持单个类型参数。
依赖关系
~6–15MB
~213K SLoC