Skip to main content

injectorpp/interface/
macros.rs

1/// Converts a function to a `FuncPtr`.
2///
3/// This macro handles both generic and non-generic functions:
4/// - For generic functions, provide the function name and type parameters separately: `func!(function_name, fn(Type1, Type2))`
5/// - For non-generic functions, simply provide the function: `func!(function_name, fn())`
6#[macro_export]
7macro_rules! func {
8    // Case 1: Generic function — provide function name and types separately
9    ($f:ident :: <$($gen:ty),*>, $fn_type:ty) => {{
10        let fn_val:$fn_type = $f::<$($gen),*>;
11        let ptr = fn_val as *const ();
12        let sig = std::any::type_name_of_val(&fn_val);
13
14        unsafe { FuncPtr::new(ptr, sig) }
15    }};
16
17    // Case 2: Non-generic function
18    ($f:expr, $fn_type:ty) => {{
19        let fn_val:$fn_type = $f;
20        let ptr = fn_val as *const ();
21        let sig = std::any::type_name_of_val(&fn_val);
22
23        unsafe { FuncPtr::new(ptr, sig) }
24    }};
25
26    // Simplified fn with return
27    (func_info: fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
28        $crate::func!($f, fn($($arg_ty),*) -> $ret)
29    }};
30
31    (fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
32        $crate::func!($f, fn($($arg_ty),*) -> $ret)
33    }};
34
35    // Simplified fn with unit return
36    (func_info: fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
37        $crate::func!($f, fn($($arg_ty),*))
38    }};
39
40    (fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
41        $crate::func!($f, fn($($arg_ty),*))
42    }};
43
44    // Simplified unsafe fn with return
45    (func_info: unsafe fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
46        $crate::func!($f, unsafe fn($($arg_ty),*) -> $ret)
47    }};
48
49    (unsafe{} fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
50        $crate::func!($f, unsafe fn($($arg_ty),*) -> $ret)
51    }};
52
53    // Simplified unsafe fn with unit return
54    (func_info: unsafe fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
55        $crate::func!($f, unsafe fn($($arg_ty),*) -> ())
56    }};
57
58    (unsafe{} fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
59        $crate::func!($f, unsafe fn($($arg_ty),*) -> ())
60    }};
61
62    // Simplified unsafe extern "C" fn with return
63    (func_info: unsafe extern "C" fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
64        $crate::func!($f, unsafe extern "C" fn($($arg_ty),*) -> $ret)
65    }};
66
67    (unsafe{} extern "C" fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
68        $crate::func!($f, unsafe extern "C" fn($($arg_ty),*) -> $ret)
69    }};
70
71    // Simplified unsafe extern "C" fn with unit return
72    (func_info: unsafe extern "C" fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
73        $crate::func!($f, unsafe extern "C" fn($($arg_ty),*) -> ())
74    }};
75
76    (unsafe{} extern "C" fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
77        $crate::func!($f, unsafe extern "C" fn($($arg_ty),*) -> ())
78    }};
79
80    // Simplified unsafe extern "system" fn with return
81    (func_info: unsafe extern "system" fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
82        $crate::func!($f, unsafe extern "system" fn($($arg_ty),*) -> $ret)
83    }};
84
85    (unsafe{} extern "system" fn ( $f:expr ) ( $($arg_ty:ty),* ) -> $ret:ty) => {{
86        $crate::func!($f, unsafe extern "system" fn($($arg_ty),*) -> $ret)
87    }};
88
89    // Simplified unsafe extern "system" fn with unit return
90    (func_info: unsafe extern "system" fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
91        $crate::func!($f, unsafe extern "system" fn($($arg_ty),*) -> ())
92    }};
93
94    (unsafe{} extern "system" fn ( $f:expr ) ( $($arg_ty:ty),* )) => {{
95        $crate::func!($f, unsafe extern "system" fn($($arg_ty),*) -> ())
96    }};
97}
98
99/// Converts a function to a `FuncPtr`.
100///
101/// This macro handles both generic and non-generic functions:
102/// - For generic functions, provide the function name and type parameters separately: `func!(function_name::<Type1, Type2>)`
103/// - For non-generic functions, simply provide the function: `func!(function_name)`
104///
105/// # Safety
106///
107/// This macro uses unsafe code internally and comes with the following requirements:
108/// - The function pointer must remain valid for the entire duration it's used by injectorpp
109/// - The function signature must match exactly what the injectorpp expects at runtime
110/// - Mismatched function signatures will lead to undefined behavior or memory corruption
111/// - Function pointers created with this macro should only be used with the appropriate injectorpp APIs
112#[macro_export]
113macro_rules! func_unchecked {
114    // Case 1: Generic function — provide function name and types separately
115    ($f:ident :: <$($gen:ty),*>) => {{
116        let fn_val = $f::<$($gen),*>;
117        let ptr = fn_val as *const ();
118
119        FuncPtr::new(ptr, "")
120    }};
121
122    // Case 2: Non-generic function
123    ($f:expr) => {{
124        let fn_val = $f;
125        let ptr = fn_val as *const ();
126
127        FuncPtr::new(ptr, "")
128    }};
129}
130
131/// Converts a closure to a `FuncPtr`.
132///
133/// This macro allows you to use Rust closures as mock implementations in injectorpp
134/// by converting them to function pointers.
135///
136/// # Parameters
137///
138/// - `$closure`: The closure to convert
139/// - `$fn_type`: The explicit function type signature that the closure conforms to
140#[macro_export]
141macro_rules! closure {
142    ($closure:expr, $fn_type:ty) => {{
143        let fn_val: $fn_type = $closure;
144        let sig = std::any::type_name_of_val(&fn_val);
145
146        unsafe { FuncPtr::new(fn_val as *const (), sig) }
147    }};
148}
149
150/// Converts a closure to a `FuncPtr`.
151///
152/// This macro allows you to use Rust closures as mock implementations in injectorpp
153/// by converting them to function pointers.
154///
155/// # Parameters
156///
157/// - `$closure`: The closure to convert
158/// - `$fn_type`: The explicit function type signature that the closure conforms to
159///
160/// # Safety
161///
162/// This macro uses unsafe code internally and comes with significant safety requirements:
163/// - The closure's signature must exactly match the provided function type
164/// - The closure must not capture any references or variables with lifetimes shorter than the mock's usage
165/// - The closure must remain valid for the entire duration it's used by injectorpp
166/// - Mismatched function signatures will lead to undefined behavior or memory corruption
167#[macro_export]
168macro_rules! closure_unchecked {
169    ($closure:expr, $fn_type:ty) => {{
170        let fn_val: $fn_type = $closure;
171        FuncPtr::new(fn_val as *const (), "")
172    }};
173}
174
175#[doc(hidden)]
176pub fn __assert_future_output<Fut, T>(_: &mut Fut)
177where
178    Fut: std::future::Future<Output = T>,
179{
180}
181
182/// Ensure the async function can be correctly used in injectorpp.
183#[macro_export]
184macro_rules! async_func {
185    ($expr:expr, $ty:ty) => {{
186        let mut __fut = $expr;
187
188        let _ = __assert_future_output::<_, $ty>(&mut __fut);
189
190        let sig = std::any::type_name::<fn() -> std::task::Poll<$ty>>();
191        (std::pin::pin!(__fut), sig)
192    }};
193}
194
195/// Ensure the async function can be correctly used in injectorpp.
196///
197/// # Safety
198///
199/// This macro skips the signature check and assumes the caller knows what they are doing.
200#[macro_export]
201macro_rules! async_func_unchecked {
202    ($expr:expr) => {
203        std::pin::pin!($expr)
204    };
205}
206
207/// Config a return value for faking an async function.
208#[macro_export]
209macro_rules! async_return {
210    ($val:expr, $ty:ty) => {{
211        fn generated_poll_fn() -> std::task::Poll<$ty> {
212            std::task::Poll::Ready($val)
213        }
214
215        $crate::func!(generated_poll_fn, fn() -> std::task::Poll<$ty>)
216    }};
217}
218
219/// Config a return value for faking an async function.
220///
221/// # Safety
222///
223/// This macro skips the signature check and assumes the caller knows what they are doing.
224#[macro_export]
225macro_rules! async_return_unchecked {
226    ($val:expr, $ty:ty) => {{
227        fn generated_poll_fn() -> std::task::Poll<$ty> {
228            std::task::Poll::Ready($val)
229        }
230
231        $crate::func_unchecked!(generated_poll_fn)
232    }};
233}
234
235/// Creates a mock function implementation with configurable behavior and verification.
236///
237/// This macro generates a function that can be used to replace real functions during testing.
238/// It supports configuring return values, parameter validation, side effects through
239/// reference parameters, and verification of call counts.
240///
241/// # Parameters
242///
243/// - `func_type`: Required. The function signature to mock (e.g., `fn(x: i32) -> bool`).
244/// - `when`: Optional. A condition on the function parameters that must be true for the mock to execute.
245/// - `assign`: Optional. Code block to execute for modifying reference parameters.
246/// - `returns`: Required for non-unit functions. The value to return from the mock.
247/// - `times`: Optional. Verifies the function is called exactly this many times.
248///
249/// # Safety
250///
251/// This macro uses unsafe code internally and comes with significant safety requirements:
252/// - The function signature must exactly match the signature of the function being mocked
253/// - The mock must handle all possible input parameters correctly
254/// - Memory referenced by parameters must remain valid for the duration of the function call
255/// - Type mismatches between the mocked function and its implementation will cause undefined behavior
256/// - Mock functions created with this macro must only be used with the `will_execute` method
257#[macro_export]
258macro_rules! fake {
259    // === NON-UNIT RETURNING FUNCTIONS (return type not "()") ===
260
261    // With when, assign, returns, and times.
262    (
263        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
264        when: $cond:expr,
265        assign: { $($assign:tt)* },
266        returns: $ret_val:expr,
267        times: $expected:expr
268    ) => {{
269         use std::sync::atomic::{AtomicUsize, Ordering};
270         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
271         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
272         fn fake($($arg_name: $arg_ty),*) -> $ret {
273             if $cond {
274                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
275                 if prev >= $expected {
276                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
277                 }
278                 { $($assign)* }
279                 $ret_val
280             } else {
281                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
282             }
283         }
284         let f: fn($($arg_ty),*) -> $ret = fake;
285         let raw_ptr = f as *const ();
286         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
287    }};
288    // With when, assign, and returns (no times).
289    (
290        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
291        when: $cond:expr,
292        assign: { $($assign:tt)* },
293        returns: $ret_val:expr
294    ) => {{
295         let verifier = CallCountVerifier::Dummy;
296         fn fake($($arg_name: $arg_ty),*) -> $ret {
297             if $cond {
298                 { $($assign)* }
299                 $ret_val
300             } else {
301                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
302             }
303         }
304         let f: fn($($arg_ty),*) -> $ret = fake;
305         let raw_ptr = f as *const ();
306         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
307    }};
308    // With when and returns, times, but no assign.
309    (
310        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
311        when: $cond:expr,
312        returns: $ret_val:expr,
313        times: $expected:expr
314    ) => {{
315         use std::sync::atomic::{AtomicUsize, Ordering};
316         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
317         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
318         fn fake($($arg_name: $arg_ty),*) -> $ret {
319             if $cond {
320                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
321                 if prev >= $expected {
322                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
323                 }
324                 $ret_val
325             } else {
326                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
327             }
328         }
329         let f: fn($($arg_ty),*) -> $ret = fake;
330         let raw_ptr = f as *const ();
331         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
332    }};
333    // With when and returns (no times, no assign).
334    (
335        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
336        when: $cond:expr,
337        returns: $ret_val:expr
338    ) => {{
339         let verifier = CallCountVerifier::Dummy;
340         fn fake($($arg_name: $arg_ty),*) -> $ret {
341             if $cond {
342                 $ret_val
343             } else {
344                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
345             }
346         }
347         let f: fn($($arg_ty),*) -> $ret = fake;
348         let raw_ptr = f as *const ();
349         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
350    }};
351    (
352        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
353        when: $cond:expr,
354        returns: $ret_val:expr
355    ) => {{
356         let verifier = CallCountVerifier::Dummy;
357         unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
358             if $cond {
359                 $ret_val
360             } else {
361                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
362             }
363         }
364         let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
365         let raw_ptr = f as *const ();
366         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
367    }};
368    // With assign, returns and times
369    (
370        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
371        assign: { $($assign:tt)* },
372        returns: $ret_val:expr,
373        times: $expected:expr
374    ) => {{
375         use std::sync::atomic::{AtomicUsize, Ordering};
376         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
377         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
378         fn fake($($arg_name: $arg_ty),*) -> $ret {
379             if true {
380                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
381                 if prev >= $expected {
382                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
383                 }
384                 { $($assign)* }
385                 $ret_val
386             } else {
387                unreachable!()
388             }
389         }
390         let f: fn($($arg_ty),*) -> $ret = fake;
391         let raw_ptr = f as *const ();
392         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
393    }};
394    // With assign and returns
395    (
396        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
397        assign: { $($assign:tt)* },
398        returns: $ret_val:expr
399    ) => {{
400         let verifier = CallCountVerifier::Dummy;
401         fn fake($($arg_name: $arg_ty),*) -> $ret {
402             if true {
403                { $($assign)* }
404                 $ret_val
405             } else {
406                 unreachable!()
407             }
408         }
409         let f: fn($($arg_ty),*) -> $ret = fake;
410         let raw_ptr = f as *const ();
411         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
412    }};
413    // With times and returns
414    (
415        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
416        returns: $ret_val:expr,
417        times: $expected:expr
418    ) => {{
419         use std::sync::atomic::{AtomicUsize, Ordering};
420         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
421         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
422         fn fake($($arg_name: $arg_ty),*) -> $ret {
423             if true {
424                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
425                 if prev >= $expected {
426                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
427                 }
428                 $ret_val
429             } else {
430                 unreachable!()
431             }
432         }
433         let f: fn($($arg_ty),*) -> $ret = fake;
434         let raw_ptr = f as *const ();
435         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
436    }};
437    // With returns only.
438    (
439        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
440        returns: $ret_val:expr
441    ) => {{
442         let verifier = CallCountVerifier::Dummy;
443         fn fake($($arg_name: $arg_ty),*) -> $ret {
444             if true {
445                 $ret_val
446             } else {
447                 unreachable!()
448             }
449         }
450         let f: fn($($arg_ty),*) -> $ret = fake;
451         let raw_ptr = f as *const ();
452         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
453    }};
454    (
455        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
456        returns: $ret_val:expr
457    ) => {{
458         let verifier = CallCountVerifier::Dummy;
459         unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
460             if true {
461                 $ret_val
462             } else {
463                 unreachable!()
464             }
465         }
466         let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
467         let raw_ptr = f as *const ();
468         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
469    }};
470
471    // === UNIT RETURNING FUNCTIONS (-> ()) ===
472
473    // With when, assign, and times.
474    (
475        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
476        when: $cond:expr,
477        assign: { $($assign:tt)* },
478        times: $expected:expr
479    ) => {{
480         use std::sync::atomic::{AtomicUsize, Ordering};
481         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
482         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
483         fn fake($($arg_name: $arg_ty),*) {
484             if $cond {
485                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
486                 if prev >= $expected {
487                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
488                 }
489                 { $($assign)* }
490             } else {
491                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
492             }
493         }
494         let f: fn($($arg_ty),*) -> $ret = fake;
495         let raw_ptr = f as *const ();
496         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
497    }};
498    // With when and times (no assign).
499    (
500        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
501        when: $cond:expr,
502        times: $expected:expr
503    ) => {{
504         use std::sync::atomic::{AtomicUsize, Ordering};
505         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
506         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
507         fn fake($($arg_name: $arg_ty),*) {
508             if $cond {
509                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
510                 if prev >= $expected {
511                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
512                 }
513             } else {
514                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
515             }
516         }
517         let f: fn($($arg_ty),*) -> $ret = fake;
518         let raw_ptr = f as *const ();
519         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
520    }};
521    // With when and assign (no times).
522    (
523        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
524        when: $cond:expr,
525        assign: { $($assign:tt)* }
526    ) => {{
527         let verifier = CallCountVerifier::Dummy;
528         fn fake($($arg_name: $arg_ty),*) {
529             if $cond {
530                 { $($assign)* }
531             } else {
532                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
533             }
534         }
535         let f: fn($($arg_ty),*) = fake;
536         let raw_ptr = f as *const ();
537         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
538    }};
539    // With assign only
540    (
541        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
542        assign: { $($assign:tt)* }
543    ) => {{
544         let verifier = CallCountVerifier::Dummy;
545         fn fake($($arg_name: $arg_ty),*) {
546             if true {
547                 { $($assign)* }
548             } else {
549                unreachable!()
550             }
551         }
552         let f: fn($($arg_ty),*) = fake;
553         let raw_ptr = f as *const ();
554         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
555    }};
556    // With assign and times
557    (
558        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
559        assign: { $($assign:tt)* },
560        times: $expected:expr
561    ) => {{
562
563        use std::sync::atomic::{AtomicUsize, Ordering};
564         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
565         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
566         fn fake($($arg_name: $arg_ty),*) {
567             if true {
568                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
569                 if prev >= $expected {
570                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
571                 }
572                 { $($assign)* }
573             } else {
574                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
575             }
576         }
577         let f: fn($($arg_ty),*) = fake;
578         let raw_ptr = f as *const ();
579         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
580    }};
581    // With times only (when defaults to true, no assign).
582    (
583        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> (),
584        times: $expected:expr
585    ) => {{
586         use std::sync::atomic::{AtomicUsize, Ordering};
587         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
588         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
589         fn fake($($arg_name: $arg_ty),*) {
590             if true {
591                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
592                 if prev >= $expected {
593                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
594                 }
595             } else {
596                 unreachable!()
597             }
598         }
599         let f: fn($($arg_ty),*) = fake;
600         let raw_ptr = f as *const ();
601         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
602    }};
603    // With neither (no when, no times, no assign, no returns).
604    (
605        func_type: fn($($arg_name:ident: $arg_ty:ty),*) -> ()
606    ) => {{
607         let verifier = CallCountVerifier::Dummy;
608         fn fake($($arg_name: $arg_ty),*) {
609             if true { } else { unreachable!() }
610         }
611         let f: fn($($arg_ty),*) = fake;
612         let raw_ptr = f as *const ();
613         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
614    }};
615
616    // === NORMAL UNSAFE NON-UNIT RETURNING FUNCTIONS ===
617    // With returns only for unsafe fn
618    (
619        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
620        returns: $ret_val:expr
621    ) => {{
622        let verifier = CallCountVerifier::Dummy;
623        unsafe fn fake($($arg_name: $arg_ty),*) -> $ret {
624            if true {
625                $ret_val
626            } else {
627                unreachable!()
628            }
629        }
630        let f: unsafe fn($($arg_ty),*) -> $ret = fake;
631        let raw_ptr = f as *const ();
632        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
633    }};
634    // With returns and times for unsafe fn
635    (
636        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
637        returns: $ret_val:expr,
638        times: $expected:expr
639    ) => {{
640        use std::sync::atomic::{AtomicUsize, Ordering};
641        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
642        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
643        unsafe fn fake($($arg_name: $arg_ty),*) -> $ret {
644            if true {
645                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
646                if prev >= $expected {
647                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
648                }
649                $ret_val
650            } else {
651                unreachable!()
652            }
653        }
654        let f: unsafe fn($($arg_ty),*) -> $ret = fake;
655        let raw_ptr = f as *const ();
656        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
657    }};
658    // With assign and returns for unsafe fn
659    (
660        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
661        assign: { $($assign:tt)* },
662        returns: $ret_val:expr
663    ) => {{
664        let verifier = CallCountVerifier::Dummy;
665        unsafe fn fake($($arg_name: $arg_ty),*) -> $ret {
666            if true {
667                { $($assign)* }
668                $ret_val
669            } else {
670                unreachable!()
671            }
672        }
673        let f: unsafe fn($($arg_ty),*) -> $ret = fake;
674        let raw_ptr = f as *const ();
675        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
676    }};
677    // With assign, returns, and times for unsafe fn
678    (
679        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
680        assign: { $($assign:tt)* },
681        returns: $ret_val:expr,
682        times: $expected:expr
683    ) => {{
684        use std::sync::atomic::{AtomicUsize, Ordering};
685        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
686        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
687        unsafe fn fake($($arg_name: $arg_ty),*) -> $ret {
688            if true {
689                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
690                if prev >= $expected {
691                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
692                }
693                { $($assign)* }
694                $ret_val
695            } else {
696                unreachable!()
697            }
698        }
699        let f: unsafe fn($($arg_ty),*) -> $ret = fake;
700        let raw_ptr = f as *const ();
701        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
702    }};
703    // === NORMAL UNSAFE UNIT RETURNING FUNCTIONS ===
704    // With times for unsafe fn
705    (
706        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> (),
707        times: $expected:expr
708    ) => {{
709        use std::sync::atomic::{AtomicUsize, Ordering};
710        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
711        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
712        unsafe fn fake($($arg_name: $arg_ty),*) {
713            if true {
714                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
715                if prev >= $expected {
716                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
717                }
718            } else {
719                unreachable!()
720            }
721        }
722        let f: unsafe fn($($arg_ty),*) = fake;
723        let raw_ptr = f as *const ();
724        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
725    }};
726    // With assign only
727    (
728        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> (),
729        assign: { $($assign:tt)* }
730    ) => {{
731        let verifier = CallCountVerifier::Dummy;
732        unsafe fn fake($($arg_name: $arg_ty),*) {
733            if true {
734                { $($assign)* }
735            } else {
736                unreachable!()
737            }
738        }
739        let f: unsafe fn($($arg_ty),*) = fake;
740        let raw_ptr = f as *const ();
741        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
742    }};
743    // With assign and times
744    (
745        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> (),
746        assign: { $($assign:tt)* },
747        times: $expected:expr
748    ) => {{
749
750        use std::sync::atomic::{AtomicUsize, Ordering};
751         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
752         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
753         unsafe fn fake($($arg_name: $arg_ty),*) {
754             if true {
755                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
756                 if prev >= $expected {
757                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
758                 }
759                 { $($assign)* }
760             } else {
761                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
762             }
763         }
764         let f: unsafe fn($($arg_ty),*) = fake;
765         let raw_ptr = f as *const ();
766         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
767    }};
768    // Without times for unsafe fn
769    (
770        func_type: unsafe fn($($arg_name:ident: $arg_ty:ty),*) -> ()
771    ) => {{
772        let verifier = CallCountVerifier::Dummy;
773        unsafe fn fake($($arg_name: $arg_ty),*) {
774            if true { } else { unreachable!() }
775        }
776        let f: unsafe fn($($arg_ty),*) = fake;
777        let raw_ptr = f as *const ();
778        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
779    }};
780
781    // === EXTERN "C" NON-UNIT RETURNING FUNCTIONS ===
782    // With when, assign, returns, and times.
783    (
784        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
785        when: $cond:expr,
786        assign: { $($assign:tt)* },
787        returns: $ret_val:expr,
788        times: $expected:expr
789    ) => {{
790        use std::sync::atomic::{AtomicUsize, Ordering};
791        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
792        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
793        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
794            if $cond {
795                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
796                if prev >= $expected {
797                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
798                }
799                { $($assign)* }
800                $ret_val
801            } else {
802                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
803            }
804        }
805        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
806        let raw_ptr = f as *const ();
807        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
808    }};
809    // With when, assign, and returns
810    (
811        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
812        when: $cond:expr,
813        assign: { $($assign:tt)* },
814        returns: $ret_val:expr
815    ) => {{
816        let verifier = CallCountVerifier::Dummy;
817        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
818            if $cond {
819                { $($assign)* }
820                $ret_val
821            } else {
822                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
823            }
824        }
825        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
826        let raw_ptr = f as *const ();
827        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
828    }};
829    // With when and returns, times
830    (
831        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
832        when: $cond:expr,
833        returns: $ret_val:expr,
834        times: $expected:expr
835    ) => {{
836        use std::sync::atomic::{AtomicUsize, Ordering};
837        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
838        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
839        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
840            if $cond {
841                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
842                if prev >= $expected {
843                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
844                }
845                $ret_val
846            } else {
847                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
848            }
849        }
850        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
851        let raw_ptr = f as *const ();
852        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
853    }};
854    // With assign, returns, and times
855    (
856        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
857        assign: { $($assign:tt)* },
858        returns: $ret_val:expr,
859        times: $expected:expr
860    ) => {{
861        use std::sync::atomic::{AtomicUsize, Ordering};
862        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
863        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
864        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
865            if true {
866                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
867                if prev >= $expected {
868                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
869                }
870                { $($assign)* }
871                $ret_val
872            } else {
873                unreachable!()
874            }
875        }
876        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
877        let raw_ptr = f as *const ();
878        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
879    }};
880    // With assign and returns
881    (
882        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
883        assign: { $($assign:tt)* },
884        returns: $ret_val:expr
885    ) => {{
886        let verifier = CallCountVerifier::Dummy;
887        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
888            if true {
889                { $($assign)* }
890                $ret_val
891            } else {
892                unreachable!()
893            }
894        }
895        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
896        let raw_ptr = f as *const ();
897        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
898    }};
899    // With returns and times
900    (
901        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
902        returns: $ret_val:expr,
903        times: $expected:expr
904    ) => {{
905        use std::sync::atomic::{AtomicUsize, Ordering};
906        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
907        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
908        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) -> $ret {
909            if true {
910                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
911                if prev >= $expected {
912                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
913                }
914                $ret_val
915            } else {
916                unreachable!()
917            }
918        }
919        let f: unsafe extern "C" fn($($arg_ty),*) -> $ret = fake;
920        let raw_ptr = f as *const ();
921        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
922    }};
923    // === EXTERN "C" UNIT RETURNING FUNCTIONS ===
924    // With when, assign, and times
925    (
926        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
927        when: $cond:expr,
928        assign: { $($assign:tt)* },
929        times: $expected:expr
930    ) => {{
931        use std::sync::atomic::{AtomicUsize, Ordering};
932        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
933        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
934        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
935            if $cond {
936                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
937                if prev >= $expected {
938                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
939                }
940                { $($assign)* }
941            } else {
942                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
943            }
944        }
945        let f: unsafe extern "C" fn($($arg_ty),*) = fake;
946        let raw_ptr = f as *const ();
947        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
948    }};
949    // With when and times (no assign).
950    (
951        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
952        when: $cond:expr,
953        times: $expected:expr
954    ) => {{
955        use std::sync::atomic::{AtomicUsize, Ordering};
956        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
957        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
958        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
959            if $cond {
960                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
961                if prev >= $expected {
962                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
963                }
964            } else {
965                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
966            }
967        }
968        let f: unsafe extern "C" fn($($arg_ty),*) = fake;
969        let raw_ptr = f as *const ();
970        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
971    }};
972    // With when and assign (no times).
973    (
974        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
975        when: $cond:expr,
976        assign: { $($assign:tt)* }
977    ) => {{
978        let verifier = CallCountVerifier::Dummy;
979        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
980            if $cond {
981                { $($assign)* }
982            } else {
983                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
984            }
985        }
986        let f: unsafe extern "C" fn($($arg_ty),*) = fake;
987        let raw_ptr = f as *const ();
988        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
989    }};
990    // With assign only
991    (
992        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
993        assign: { $($assign:tt)* }
994    ) => {{
995        let verifier = CallCountVerifier::Dummy;
996        unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
997            if true {
998                { $($assign)* }
999            } else {
1000                unreachable!()
1001            }
1002        }
1003        let f: unsafe extern "C" fn($($arg_ty),*) = fake;
1004        let raw_ptr = f as *const ();
1005        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1006    }};
1007    // With assign and times
1008    (
1009        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1010        assign: { $($assign:tt)* },
1011        times: $expected:expr
1012    ) => {{
1013
1014        use std::sync::atomic::{AtomicUsize, Ordering};
1015         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1016         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1017         unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
1018             if true {
1019                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1020                 if prev >= $expected {
1021                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1022                 }
1023                 { $($assign)* }
1024             } else {
1025                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1026             }
1027         }
1028         let f: unsafe extern "C" fn($($arg_ty),*) = fake;
1029         let raw_ptr = f as *const ();
1030         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1031    }};
1032    // With times only (when defaults to true, no assign).
1033    (
1034        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1035        times: $expected:expr
1036    ) => {{
1037         use std::sync::atomic::{AtomicUsize, Ordering};
1038         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1039         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1040         unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
1041             if true {
1042                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1043                 if prev >= $expected {
1044                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1045                 }
1046             } else {
1047                 unreachable!()
1048             }
1049         }
1050         let f: unsafe extern "C" fn($($arg_ty),*) = fake;
1051         let raw_ptr = f as *const ();
1052         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1053    }};
1054    // With neither (no when, no times, no assign, no returns).
1055    (
1056        func_type: unsafe extern "C" fn($($arg_name:ident: $arg_ty:ty),*) -> ()
1057    ) => {{
1058         let verifier = CallCountVerifier::Dummy;
1059         unsafe extern "C" fn fake($($arg_name: $arg_ty),*) {
1060             if true { } else { unreachable!() }
1061         }
1062         let f: unsafe extern "C" fn($($arg_ty),*) = fake;
1063         let raw_ptr = f as *const ();
1064         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1065    }};
1066    // === EXTERN "system" NON-UNIT RETURNING FUNCTIONS ===
1067    // With when, assign, returns, and times.
1068    (
1069        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1070        when: $cond:expr,
1071        assign: { $($assign:tt)* },
1072        returns: $ret_val:expr,
1073        times: $expected:expr
1074    ) => {{
1075        use std::sync::atomic::{AtomicUsize, Ordering};
1076        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1077        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1078        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1079            if $cond {
1080                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1081                if prev >= $expected {
1082                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1083                }
1084                { $($assign)* }
1085                $ret_val
1086            } else {
1087                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1088            }
1089        }
1090        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1091        let raw_ptr = f as *const ();
1092        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1093    }};
1094    // With when, assign, and returns
1095    (
1096        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1097        when: $cond:expr,
1098        assign: { $($assign:tt)* },
1099        returns: $ret_val:expr
1100    ) => {{
1101        let verifier = CallCountVerifier::Dummy;
1102        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1103            if $cond {
1104                { $($assign)* }
1105                $ret_val
1106            } else {
1107                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1108            }
1109        }
1110        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1111        let raw_ptr = f as *const ();
1112        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1113    }};
1114    // With when and returns, times
1115    (
1116        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1117        when: $cond:expr,
1118        returns: $ret_val:expr,
1119        times: $expected:expr
1120    ) => {{
1121        use std::sync::atomic::{AtomicUsize, Ordering};
1122        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1123        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1124        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1125            if $cond {
1126                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1127                if prev >= $expected {
1128                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1129                }
1130                $ret_val
1131            } else {
1132                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1133            }
1134        }
1135        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1136        let raw_ptr = f as *const ();
1137        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1138    }};
1139    // With assign, returns, and times
1140    (
1141        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1142        assign: { $($assign:tt)* },
1143        returns: $ret_val:expr,
1144        times: $expected:expr
1145    ) => {{
1146        use std::sync::atomic::{AtomicUsize, Ordering};
1147        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1148        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1149        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1150            if true {
1151                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1152                if prev >= $expected {
1153                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1154                }
1155                { $($assign)* }
1156                $ret_val
1157            } else {
1158                unreachable!()
1159            }
1160        }
1161        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1162        let raw_ptr = f as *const ();
1163        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1164    }};
1165    // With assign and returns
1166    (
1167        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1168        assign: { $($assign:tt)* },
1169        returns: $ret_val:expr
1170    ) => {{
1171        let verifier = CallCountVerifier::Dummy;
1172        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1173            if true {
1174                { $($assign)* }
1175                $ret_val
1176            } else {
1177                unreachable!()
1178            }
1179        }
1180        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1181        let raw_ptr = f as *const ();
1182        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1183    }};
1184    // With returns and times
1185    (
1186        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1187        returns: $ret_val:expr,
1188        times: $expected:expr
1189    ) => {{
1190        use std::sync::atomic::{AtomicUsize, Ordering};
1191        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1192        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1193        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1194            if true {
1195                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1196                if prev >= $expected {
1197                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1198                }
1199                $ret_val
1200            } else {
1201                unreachable!()
1202            }
1203        }
1204        let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1205        let raw_ptr = f as *const ();
1206        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1207    }};
1208    (
1209        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> $ret:ty,
1210        returns: $ret_val:expr
1211    ) => {{
1212         let verifier = CallCountVerifier::Dummy;
1213         unsafe extern "system" fn fake($($arg_name: $arg_ty),*) -> $ret {
1214             if true {
1215                 $ret_val
1216             } else {
1217                 unreachable!()
1218             }
1219         }
1220         let f: unsafe extern "system" fn($($arg_ty),*) -> $ret = fake;
1221         let raw_ptr = f as *const ();
1222         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1223    }};
1224    // === EXTERN "system" UNIT RETURNING FUNCTIONS ===
1225    // With when, assign, and times
1226    (
1227        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1228        when: $cond:expr,
1229        assign: { $($assign:tt)* },
1230        times: $expected:expr
1231    ) => {{
1232        use std::sync::atomic::{AtomicUsize, Ordering};
1233        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1234        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1235        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1236            if $cond {
1237                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1238                if prev >= $expected {
1239                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1240                }
1241                { $($assign)* }
1242            } else {
1243                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1244            }
1245        }
1246        let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1247        let raw_ptr = f as *const ();
1248        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1249    }};
1250    // With when and times (no assign).
1251    (
1252        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1253        when: $cond:expr,
1254        times: $expected:expr
1255    ) => {{
1256        use std::sync::atomic::{AtomicUsize, Ordering};
1257        static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1258        let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1259        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1260            if $cond {
1261                let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1262                if prev >= $expected {
1263                    panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1264                }
1265            } else {
1266                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1267            }
1268        }
1269        let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1270        let raw_ptr = f as *const ();
1271        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1272    }};
1273    // With when and assign (no times).
1274    (
1275        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1276        when: $cond:expr,
1277        assign: { $($assign:tt)* }
1278    ) => {{
1279        let verifier = CallCountVerifier::Dummy;
1280        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1281            if $cond {
1282                { $($assign)* }
1283            } else {
1284                panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1285            }
1286        }
1287        let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1288        let raw_ptr = f as *const ();
1289        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1290    }};
1291    // With assign only
1292    (
1293        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1294        assign: { $($assign:tt)* }
1295    ) => {{
1296        let verifier = CallCountVerifier::Dummy;
1297        unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1298            if true {
1299                { $($assign)* }
1300            } else {
1301                unreachable!()
1302            }
1303        }
1304        let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1305        let raw_ptr = f as *const ();
1306        (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1307    }};
1308    // With assign and times
1309    (
1310        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1311        assign: { $($assign:tt)* },
1312        times: $expected:expr
1313    ) => {{
1314
1315        use std::sync::atomic::{AtomicUsize, Ordering};
1316         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1317         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1318         unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1319             if true {
1320                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1321                 if prev >= $expected {
1322                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1323                 }
1324                 { $($assign)* }
1325             } else {
1326                 panic!("Fake function defined at {}:{}:{} called with unexpected arguments", file!(), line!(), column!());
1327             }
1328         }
1329         let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1330         let raw_ptr = f as *const ();
1331         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1332    }};
1333    // With times only (when defaults to true, no assign).
1334    (
1335        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> (),
1336        times: $expected:expr
1337    ) => {{
1338         use std::sync::atomic::{AtomicUsize, Ordering};
1339         static FAKE_COUNTER: AtomicUsize = AtomicUsize::new(0);
1340         let verifier = CallCountVerifier::WithCount { counter: &FAKE_COUNTER, expected: $expected };
1341         unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1342             if true {
1343                 let prev = FAKE_COUNTER.fetch_add(1, Ordering::SeqCst);
1344                 if prev >= $expected {
1345                     panic!("Fake function defined at {}:{}:{} called more times than expected", file!(), line!(), column!());
1346                 }
1347             } else {
1348                 unreachable!()
1349             }
1350         }
1351         let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1352         let raw_ptr = f as *const ();
1353         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1354    }};
1355    // With neither (no when, no times, no assign, no returns).
1356    (
1357        func_type: unsafe extern "system" fn($($arg_name:ident: $arg_ty:ty),*) -> ()
1358    ) => {{
1359         let verifier = CallCountVerifier::Dummy;
1360         unsafe extern "system" fn fake($($arg_name: $arg_ty),*) {
1361             if true { } else { unreachable!() }
1362         }
1363         let f: unsafe extern "system" fn($($arg_ty),*) = fake;
1364         let raw_ptr = f as *const ();
1365         (unsafe { FuncPtr::new(raw_ptr, std::any::type_name_of_val(&f)) }, verifier)
1366    }};
1367}