5 个版本 (重大更新)
0.5.0 | 2019年7月31日 |
---|---|
0.4.0 | 2018年12月21日 |
0.3.0 | 2018年12月20日 |
0.2.0 | 2018年12月20日 |
0.1.0 | 2018年12月19日 |
#1888 in 过程宏
24KB
361 代码行
def_mod!
提供了标准模块声明的熟悉语法,同时具有更简单的实现路由和静态验证模块导出的附加优势。
extern crate def_mod;
use def_mod::def_mod;
def_mod! {
// This has the exact same behaviour as Rust's.
mod my_mod;
// Much like the one above, it also has the same effect as Rust's.
mod my_first_mod {
// This will check if a method with the name `method` and type `fn(u32) -> u8` was exported.
// It will fail to compile if it finds none.
fn method(_: u32) -> u8;
// Much like the method declaration from above, this will check to see if a type was exported.
type MyStruct;
// Much like the normal method check, that functionality is also extended to types.
// So you can check if a type has a specific method exported.
type MyOtherStruct {
// This will check if this method exists on this type. (MyOtherStruct::method)
fn method(_: u32) -> u8;
}
}
// You can declare attributes like normal.
#[cfg(windows)]
mod my_second_mod;
// When declaring an attribute, you can optionally add a string literal.
// This literal is used as the path attribute for the module file.
// All attributes declared with a path are treated as _mutually exclusive_.
// So a `mod` declaration is generated for each.
// This makes it a lot easier to manage cross-platform code.
// Note: attributes that don't have a path are copied to each module declaration.
#[cfg(windows)] = "sys/win/mod.rs"
#[cfg(not(windows))] = "sys/nix/mod.rs"
mod sys;
// Expands to:
#[cfg(windows)]
#[path = "sys/win/mod.rs"]
mod sys;
#[cfg(not(windows))]
#[path = "sys/nix/mod.rs"]
mod sys;
// You can also declare attributes on methods or types themselves, and they will be used when verifying the type.
// This module itself will be verified when not on a windows system.
#[cfg(not(windows))]
mod my_third_mod {
// This method will only be verified when on linux.
#[cfg(linux)]
fn interop() -> u8;
// Same with this type. It will only be verified when on a macos system
#[cfg(macos)]
type SomeStruct {
fn interop() -> u8;
}
}
}
fn main() {
}
注意:def_mod
使用语法技巧进行类型断言。
这意味着当您使用路径简写时,它仍然只会检查已加载的模块,而不是所有可能的模块。
一个很好的例子是当您有两个针对特定平台的模块。
通常编译的模块是唯一会被检查的模块。
如果您想检查这些模块,则需要显式启用它们的编译。
因为您可以声明任意的 #[cfg] 属性,所以 def_mod
没有一种通用方式来知道如何做到这一点。
完全取决于您。
如果您对宏生成的代码感兴趣
方法断言被转换为类似以下的内容
fn method(_: u32) -> u8;
// into
const _VALUE: fn(u32) -> u8 = my_mod::method;
泛型方法断言要复杂一些
fn generic<'a , T: 'a>(_: u32, _: T, _: fn(T) -> T) -> &'a T;
// will turn into into (Note: This is nested inside of the load function itself.)
#[allow(non_snake_case)]
fn _load_module_name_generic<'a, T: 'a>() {
let _VALUE:
fn(_: u32, _: T,
_: fn(T) -> T) -> &'a T =
other::generic;
}
类型断言被转换为一个带有使用声明的新的作用域
def_mod! {
mod my_mod {
type Test;
}
}
// Into
{
use self::my_mod::Test;
// Any method assertions for the type will also be placed inside the same scope.
}
所有这些都放入宏生成的函数中。
例如,给定类似以下的内容
def_mod! {
mod my_mod {
fn plus_one(value: u8) -> u8;
type MyStruct {
fn new() -> Self;
fn dupe(&self) -> Self;
fn clear(&mut self);
}
fn generic<'a , T: 'a>(_: u32, _: T, _: fn(T) -> T) -> &'a T;
}
}
它将被转换为以下内容
mod my_mod;
fn _load_my_mod() {
const _ASSERT_METHOD_0: fn(u8) -> u8 = self::my_mod::plus_one;
{
use self::my_mod::MyStruct;
const _ASSERT_METHOD_1: fn() -> MyStruct = MyStruct::new;
const _ASSERT_METHOD_2: fn(_self: &MyStruct) -> MyStruct = MyStruct::dupe;
const _ASSERT_METHOD_3: fn(_self: &mut MyStruct) -> MyStruct = MyStruct::clear;
}
#[allow(non_snake_case)]
fn _load_my_mod_generic<'a, T: 'a>() {
let _ASSERT_METHOD_4:
fn(_: u32, _: T,
_: fn(T) -> T) -> &'a T =
my_mod::generic;
}
}
依赖
~2MB
~47K SLoC