1#![allow(unused_imports)]
2
3#[cfg(feature = "proc-macro")]
4pub use indirect_once_derive::*;
5
6#[cfg(not(feature = "parking-lot"))]
7use std::sync::Once;
8#[cfg(feature = "parking-lot")]
9use parking_lot::Once;
10
11#[macro_export]
12macro_rules! indirect_fn {
13 (resolver = $resolver: ident ; fn $name:ident($($arg: ident : $pty: ty),*) {}) => { $crate::indirect_fn!(resolver = $resolver; fn $name($($arg: $pty),*) -> () {})};
14 (resolver = $resolver: ident ; fn $name:ident($($arg: ident : $pty: ty),*) -> $ret: ty {})=> {
15 fn $name($($arg: $pty),*) -> $ret {
16 static mut IMPL: Option<&'static fn($($pty),*) -> $ret> = None;
17 static INIT: Once = Once::new();
18
19 unsafe {
20 INIT.call_once(|| {
21 IMPL = Some($resolver());
22 });
23 (IMPL.unwrap())($($arg),*)
24 }
25 }
26 }
27}
28
29#[cfg(test)]
30mod tests {
31 use super::*;
32
33 fn incr(x: i32) -> i32 {
34 x + 1
35 }
36
37 fn decr(x: i32) -> i32 {
38 x - 1
39 }
40
41 fn foo() -> &'static fn(i32) -> i32 {
42 &(incr as fn(i32) -> i32)
43 }
44
45 fn bar() -> &'static fn(i32) -> i32 {
46 &(decr as fn(i32) -> i32)
47 }
48
49 #[test]
50 #[cfg(feature = "proc-macro")]
51 fn it_works() {
52 #[indirect(resolver = "foo")]
53 fn hello_world(arg: i32) -> i32 {}
54
55 assert_eq!(hello_world(10), 11);
56 }
57
58 #[test]
59 #[cfg(feature = "proc-macro")]
60 fn it_works_2() {
61 #[indirect(resolver = "bar")]
62 fn hello_hello(arg: i32) -> i32 {}
63
64 assert_eq!(hello_hello(10), 9);
65 }
66
67 #[test]
68 #[cfg(feature = "proc-macro")]
69 fn multiple_arguments() {
70 fn do_thingy(one: i32, two: i32, really: bool) -> (bool, i32) {
71 if really {
72 (really, one + two)
73 } else {
74 (really, two)
75 }
76 }
77
78 fn pick() -> &'static fn(i32, i32, bool) -> (bool, i32) {
79 &(do_thingy as _)
80 }
81
82 #[indirect(resolver = "pick")]
83 fn foo(one: i32, two: i32, three: bool) -> (bool, i32) {}
84
85 assert_eq!(foo(1, 2, true), (true, 3))
86 }
87
88 #[test]
89 fn macro_impl() {
90 indirect_fn! {
91 resolver = foo; fn dog(param: i32) -> i32 {}
92 }
93
94 assert_eq!(dog(41), 42);
95 }
96}