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}