#module #cross-platform #compile-time #static

nightly macro def-mod

简化模块实现路由并静态验证导出

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 过程宏

MIT 许可证

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