extern_c/
helpers.rs

1/// Stable Rust polyfill for a `where mem::size_of::<Self>() == 0` clause.
2///
3/// The trait will *technically* be implemented for all sizes, but any choice
4/// of a non-zero-sized type that ever makes it to codegen (during
5/// `cargo build`, but not `cargo check`) will thus cause a compilation error.
6///
7/// This mechanism, called a "post-monomorphization error", ss thus worse than a
8/// proper "trait not implemented" error, but better than a runtime panic.
9pub
10trait ZeroSizedElseWrathOfTheGඞds : Sized {
11    #[doc(hidden)] /** Not part of the public API */
12    const WRATH_OF_THE_GඞDS: () = assert!(::core::mem::size_of::<Self>() == 0);
13}
14
15impl<F> ZeroSizedElseWrathOfTheGඞds for F {}
16
17impls! {
18    _11, _10, _9, _8, _7, _6,
19    _5, _4, _3, _2, _1, _0,
20}
21// where
22macro_rules! impls {(
23        $(
24                $Hd:ident $(,
25                $Rest:ident )* $(,)? )?
26) => (
27    $(impls! { $($Rest),* })?
28
29    impl<F, $($Hd $(, $Rest)* ,)? R>
30        FnExt<($($Hd, $($Rest),*)?)>
31    for
32        F
33    where
34        F : Fn($($Hd $(, $Rest)*)?) -> R,
35        F : 'static + Sync + ZeroSizedElseWrathOfTheGඞds,
36    {
37        type CSignature = extern "C" fn($($Hd $(, $Rest)*)?) -> R;
38
39        fn extern_c(f: Self) -> Self::CSignature {
40            _ = Self::WRATH_OF_THE_GඞDS;
41
42            // Conceptually, a `Box::leak()` or `SOME_GLOBAL_MAP.insert(f)`
43            let _leaked_into_zst_symbolic_heap = ::core::mem::forget(f);
44
45            extern "C"
46            fn extern_c_thunk<F, $($Hd $(, $Rest)* ,)? R>($(
47                $Hd: $Hd $(,
48                $Rest: $Rest )*)?
49            ) -> R
50            where
51                F : Fn($($Hd $(, $Rest)*)?) -> R,
52            {
53                let out_of_thin_air: [F; 0] = [];
54                (unsafe {
55                    // SAFETY:
56                    //   - conceptually, this is `SOME_GLOBAL_MAP.get(f)`
57                    //   - in practice, since this is a ZST which we have
58                    //     `mem::forget`-ten, we can just produce any kind of
59                    //      well-aligned and non-deallocated pointer and say it
60                    //      is a valid reference.
61                    //      The "end" of an empty array properly fits both
62                    //      requirements.
63                    &*out_of_thin_air.as_ptr()
64                })(
65                    // now Just Call It™
66                    $($Hd $(, $Rest)*)?
67                )
68            }
69
70            extern_c_thunk::<F, $($Hd $(, $Rest)* ,)? R>
71        }
72    }
73)} use impls;
74
75pub
76trait FnExt<Args> : 'static + Sync + ZeroSizedElseWrathOfTheGඞds {
77    type CSignature;
78
79    fn extern_c(this: Self) -> Self::CSignature;
80}