3个不稳定版本
0.2.0 | 2021年1月1日 |
---|---|
0.1.1 | 2021年1月1日 |
0.1.0 | 2021年1月1日 |
#275 在 #style
在 indirect-once 中使用
5KB
92 行
indirect-once
类似glibc的 ifunc
的一次性可解析运行时间接引用。
用法
indirect-once
包提供了一些宏来帮助实现类似glibc的 ifunc
的运行时间接引用(但不需要特殊的编译器支持)。暴露的API旨在在精神上与 ifunc
API相似,但具有Rust风格。
示例
indirect-once
支持两种宏风格。
过程宏
默认风格是属性过程宏。这种风格看起来更简洁,更接近原始的 ifunc
(也被作为属性暴露)。这种风格的缺点是它会引入对一些过程宏工具包的依赖,这可能会增加编译时间(如 syn
、proc_macro2
、quote
等)。如果您认为保持依赖图小或尽量降低编译时间非常重要,可以通过禁用 proc-macro
功能来选择退出。
use indirect_once::*;
// Two implementations of foo. One should be picked at runtime based on hardware features.
fn foo_with_avx(x: i32, y: u8, p: bool) -> u16 { unimplemented!() };
fn foo_with_sse(x: i32, y: u8, p: bool) -> u16 { unimplemented!() };
// A resolver function to decide which to pick. Gets called at most once, the first time foo is called.
fn resolve_foo() -> &'static fn(i32, u8, bool) -> u16 {
if(cpu_has_avx!()) {
&(foo_with_avx as _)
} else {
&(foo_with_sse as _)
}
}
// Now define the real foo.
#[indirect(resolver = "resolve_foo")]
pub fn foo(x: i32, y: u8, p: bool) -> u16 {}
macro_rules!
宏
另一种宏风格是简单的 macro_rules!
宏。生成的代码非常相似,但它不会引入任何过程宏包。
use indirect_once::*;
// Two implementations of foo. One should be picked at runtime based on hardware features.
fn foo_with_avx(x: i32, y: u8, p: bool) -> u16 { unimplemented!() };
fn foo_with_sse(x: i32, y: u8, p: bool) -> u16 { unimplemented!() };
// A resolver function to decide which to pick. Gets called at most once, the first time foo is called.
fn resolve_foo() -> &'static fn(i32, u8, bool) -> u16 {
if(cpu_has_avx!()) {
&(foo_with_avx as _)
} else {
&(foo_with_sse as _)
}
}
// Now define the real foo.
pub indirect_fn! {
resolver = resolve_foo; fn foo(x: i32, y: u8, p: bool) -> u16 {}
}
行为
在两种风格中,在宏或属性中指定的 resolver
参数中的函数只在新声明的函数第一次被调用时调用一次。
默认情况下,实现使用 std::sync::Once
,但 parking-lot
功能将其替换为基于 parking_lot::Once
的后端。在任何情况下,一旦解析器运行了一次,这应该是一个简单的原子加载。
许可证
indirect-once
在 MIT 许可证和 Apache 2.0 许可证下双许可。您可以选择您更喜欢的任何一个。
依赖项
~1.2–6.5MB
~38K SLoC