17个版本
新 0.4.0-rc.1 | 2024年8月15日 |
---|---|
0.3.10 | 2024年5月23日 |
0.3.8 | 2024年3月24日 |
0.3.4 | 2023年11月29日 |
0.1.0 | 2023年2月15日 |
#706 在 过程宏 中
1,676 每月下载量
在 5 个crate中使用(通过 crux_core)
43KB
891 行
Crux Macros
此crate提供三个derive宏(Effect
、Export
和 Capability
),可用于与 crux_core
及相关(或自定义)功能一起使用。
1. Effect
可以使用 Effect
derive宏来创建Shell在执行Core的副作用时使用的effect枚举。它还为Capabilities结构体推导出 WithContext
。
默认情况下,生成的枚举名称为 Effect
,但可以覆盖(见下文)。该宏还需要知道您app结构的名称(默认为 App
,但可以指定)。
它还需要知道您使用且其请求类型为非单元结构体的任何功能(实现了 Operation
特性)的操作类型。
根据惯例,该宏实际上应被称为
WithContext
,但名称Effect
可能更有效地描述生成的代码。
它作为derive宏实现,而不是attribute宏,因为它需要在结构体本身内的非宏属性中进行配置(这是不可能通过attribute宏实现的)。
示例用法
如果您想生成名为 Effect
的枚举,并且您的app结构名为 App
,并且您使用的功能仅具有单元操作,则可以简单地使用该宏而无需额外配置
#[derive(Effect)]
pub struct Capabilities {
pub render: Render<Event>,
}
如果您希望生成的Effect枚举有不同的名称,可以指定另一个名称
#[derive(Effect)]
#[effect(name = "MyEffect")]
pub struct Capabilities {
pub render: Render<Event>,
}
如果你的应用结构体(实现了 App
特性)的名字不是 App
,你可以指定它的名字
#[derive(Effect)]
pub struct Capabilities {
pub render: Render<Event>,
}
要同时指定 app
和 name
,你可以使用属性两次,如下所示
#[derive(Effect)]
#[effect(name = "MyEffect")]
pub struct Capabilities {
pub render: Render<Event>,
}
或者,更地道的方法是将它们合并为一个用法,如下所示
#[derive(Effect)]
#[effect(name = "MyEffect")]
pub struct Capabilities {
pub render: Render<Event>,
}
完整的用法可能看起来像这样
#[derive(Effect)]
#[effect(name = "MyEffect")]
pub struct CatFactCapabilities {
pub http: Http<MyEvent>,
pub key_value: KeyValue<MyEvent>,
pub platform: Platform<MyEvent>,
pub render: Render<MyEvent>,
pub time: Time<MyEvent>,
}
2. 导出
Export
派生宏会在你的 shared_types
库的外部类型生成期间,生成用于注册你能力类型的代码。
要使用它,在你的 shared
包中声明一个 typegen
功能,然后使用 Export
派生宏注释你的 Capabilities
结构体
#[cfg_attr(feature = "typegen", derive(crux_core::macros::Export))]
#[derive(Effect)]
pub struct Capabilities {
pub render: Render<Event>,
pub http: Http<MyEvent>,
//...
}
然后,在 shared_types
包的 build.rs
文件中,当你注册你的 App
时,你能力使用的类型也会被注册
use crux_core::typegen::TypeGen;
use shared::{App, Event};
use std::path::PathBuf;
fn main() {
println!("cargo:rerun-if-changed=../shared");
let mut gen = TypeGen::new();
gen.register_app::<App>().expect("register");
let output_root = PathBuf::from("./generated");
gen.swift("SharedTypes", output_root.join("swift"))
.expect("swift type gen failed");
gen.java("com.example.counter.shared_types", output_root.join("java"))
.expect("java type gen failed");
gen.typescript("shared_types", output_root.join("typescript"))
.expect("typescript type gen failed");
}
3. 能力
Capability
派生宏可以用于在编写自己的能力时实现 Capability
特性。它生成的代码类似于以下内容
impl<Ev> crux_core::capability::Capability<Ev> for Render<Ev> {
type Operation = RenderOperation;
type MappedSelf<MappedEv> = Render<MappedEv>;
fn map_event<F, NewEv>(&self, f: F) -> Self::MappedSelf<NewEv>
where
F: Fn(NewEv) -> Ev + Send + Sync + Copy + 'static,
Ev: 'static,
NewEv: 'static,
{
Render::new(self.context.map_event(f))
}
}
这允许你从一个现有的能力中派生出一个能力的实例,并将其适配到不同的 Event 类型,这在从较小的 Crux 应用程序组合 Crux 应用程序时非常有用,可以自动将子事件包装在父事件中。
依赖项
~0.6–1.1MB
~24K SLoC