safer_ffi/closure/
arc.rs

1#![cfg_attr(rustfmt, rustfmt::skip)]
2//! `Arc<dyn 'static + Send + Sync + Fn(...) -> _>` but with a `#[repr(C)]`
3//! layout (inlined virtual method table).
4
5use ::alloc::sync::Arc;
6
7use_prelude!();
8
9macro_rules! with_tuple {(
10    $ArcDynFn_N:ident => (
11        $( $A_N:ident, $($A_k:ident ,)* )?
12    )
13) => (
14    impl<Ret $(, $A_N $(, $A_k)*)?>
15        crate::boxed::FitForCArc
16    for
17        dyn 'static + Send + Sync + Fn($($A_N $(, $A_k)*)?) -> Ret
18    where
19        Ret : ReprC, $(
20        $A_N : ReprC, $(
21        $A_k : ReprC, )*)?
22    {
23        type CArcWrapped = $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>;
24    }
25
26    ReprC! {
27        @[doc = concat!(
28            "`Arc<dyn Send + Sync + Fn(" $(,
29                stringify!($A_N) $(, ", ", stringify!($A_k))*
30            )?,
31            ") -> Ret>`",
32        )]
33        #[repr(C)]
34        pub
35        struct $ArcDynFn_N [Ret $(, $A_N $(, $A_k)*)?]
36        where {
37            Ret : ReprC, $(
38            $A_N : ReprC, $(
39            $A_k : ReprC, )*)?
40        }
41        {
42            env_ptr: ptr::NonNull<c_void>,
43            call:
44                unsafe extern "C"
45                fn (
46                    env_ptr: ptr::NonNull<c_void> $(,
47                        $A_N $(,
48                        $A_k
49                    )*)?
50                ) -> Ret
51            ,
52            release:
53                unsafe extern "C"
54                fn (env_ptr: ptr::NonNull<c_void>)
55            ,
56            retain: Option<
57                unsafe extern "C"
58                fn (env_ptr: ptr::NonNull<c_void>)
59            >,
60        }
61    }
62
63    const_assert!(
64        for[T]
65        [T : ?Sized + Send + Sync] => [Arc<T> : Send + Sync]
66    );
67    /// `Arc<dyn Send + Sync + ...> : Send`
68    unsafe impl<Ret $(, $A_N $(, $A_k)*)?> Send
69        for $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
70    where
71        Ret : ReprC, $(
72        $A_N : ReprC, $(
73        $A_k : ReprC, )*)?
74    {}
75    /// `Arc<dyn Send + Sync + ...> : Sync`
76    unsafe impl<Ret $(, $A_N $(, $A_k)*)?> Sync
77        for $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
78    where
79        Ret : ReprC, $(
80        $A_N : ReprC, $(
81        $A_k : ReprC, )*)?
82    {}
83
84    impl<F, Ret $(, $A_N $(, $A_k)*)?>
85        From<Arc<F>>
86    for
87        $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
88    where
89        Ret : ReprC, $(
90        $A_N : ReprC, $(
91        $A_k : ReprC, )*)?
92        F : Fn( $($A_N $(, $A_k)*)? ) -> Ret,
93        F : Send + Sync + 'static,
94    {
95        #[inline]
96        fn from (f: Arc<F>)
97          -> Self
98        {
99            Self::new(f)
100        }
101    }
102
103    impl<Ret $(, $A_N $(, $A_k)*)?>
104        $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
105    where
106        Ret : ReprC, $(
107        $A_N : ReprC, $(
108        $A_k : ReprC, )*)?
109    {
110        #[inline]
111        pub
112        fn new<F> (f: Arc<F>)
113          -> Self
114        where
115            F : Fn( $($A_N $(, $A_k)*)? ) -> Ret,
116            F : Send + Sync + 'static,
117        {
118            // Safety: `F` can be "raw-coerced" to `dyn 'static + Send + Fn...`
119            // thanks to the generic bounds on F.
120            Self {
121                env_ptr: unsafe {
122                    ptr::NonNull::new_unchecked(Arc::into_raw(f) as _)
123                },
124                release: {
125                    unsafe extern "C"
126                    fn release<F> (env_ptr: ptr::NonNull<c_void>)
127                    where
128                        F : Send + Sync + 'static,
129                    {
130                        drop::<Arc<F>>(Arc::from_raw(env_ptr.cast().as_ptr()));
131                    }
132                    release::<F>
133                },
134                retain: Some({
135                    unsafe extern "C"
136                    fn retain<F> (env_ptr: ptr::NonNull<c_void>)
137                    where
138                        F : Send + Sync + 'static,
139                    {
140                        mem::forget(Arc::<F>::clone(&
141                            mem::ManuallyDrop::new(Arc::from_raw(
142                                env_ptr.cast().as_ptr()
143                            ))
144                        ));
145                    }
146                    retain::<F>
147                }),
148                call: {
149                    unsafe extern "C"
150                    fn call<F, Ret $(, $A_N $(, $A_k)*)?> (
151                        env_ptr: ptr::NonNull<c_void> $(,
152                        $A_N : $A_N $(,
153                        $A_k : $A_k )*)?
154                    ) -> Ret
155                    where
156                        F : Fn($($A_N $(, $A_k)*)?) -> Ret,
157                        F : Send + Sync + 'static,
158                    {
159                        let env_ptr = env_ptr.cast();
160                        let f: &F = env_ptr.as_ref();
161                        f( $($A_N $(, $A_k)*)? )
162                    }
163                    call::<F, Ret $(, $A_N $(, $A_k)*)?>
164                },
165            }
166        }
167    }
168
169    impl<Ret $(, $A_N $(, $A_k)*)?> Drop
170        for $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
171    where
172        Ret : ReprC, $(
173        $A_N : ReprC, $(
174        $A_k : ReprC, )*)?
175    {
176        #[inline]
177        fn drop (self: &'_ mut Self)
178        {
179            unsafe {
180                (self.release)(self.env_ptr)
181            }
182        }
183    }
184
185    impl<Ret $(, $A_N $(, $A_k)*)?> Clone
186        for $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
187    where
188        Ret : ReprC, $(
189        $A_N : ReprC, $(
190        $A_k : ReprC, )*)?
191    {
192        #[inline]
193        fn clone (self: &'_ Self)
194          -> Self
195        {
196            let retain = self.retain.expect(concat!(
197                "Cannot `.clone()` a `",
198                stringify!($ArcDynFn_N),
199                "` whose `.retain` function pointer is `NULL`",
200            ));
201            unsafe {
202                retain(self.env_ptr);
203                Self { .. *self }
204            }
205        }
206    }
207
208    impl<Ret $(, $A_N $(, $A_k)*)?>
209        $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
210    where
211        Ret : ReprC, $(
212        $A_N : ReprC, $(
213        $A_k : ReprC, )*)?
214    {
215        #[inline]
216        pub
217        fn call (
218            self: &'_ Self $(,
219            $A_N : $A_N $(,
220            $A_k : $A_k )*)?
221        ) -> Ret
222        {
223            unsafe {
224                (self.call)(self.env_ptr, $($A_N $(, $A_k)*)?)
225            }
226        }
227    }
228
229    impl<Ret $(, $A_N $(, $A_k)*)?> fmt::Debug
230        for $ArcDynFn_N <Ret $(, $A_N $(, $A_k)*)?>
231    where
232        Ret : ReprC, $(
233        $A_N : ReprC, $(
234        $A_k : ReprC, )*)?
235    {
236        fn fmt (self: &'_ Self, fmt: &'_ mut fmt::Formatter<'_>)
237          -> fmt::Result
238        {
239            fmt .debug_struct(stringify!($ArcDynFn_N))
240                .field("env_ptr", &self.env_ptr)
241                .field("call", &self.call)
242                .field("release", &self.release)
243                .field("retain", &self.retain)
244                .finish()
245        }
246    }
247)}
248
249macro_rules! with_tuples {
250    (
251        $ArcDynFn0:ident,
252    ) => (
253        with_tuple!($ArcDynFn0 => ());
254    );
255
256    (
257        $ArcDynFn0:ident,
258        ($ArcDynFn_N:ident, $A_N:ident),
259        $(
260            ($ArcDynFn_K:ident, $A_K:ident),
261        )*
262    ) => (
263        with_tuple!($ArcDynFn_N => (
264            $A_N, $($A_K ,)*
265        ));
266        with_tuples!(
267            $ArcDynFn0,
268            $(
269                ($ArcDynFn_K, $A_K),
270            )*
271        );
272    );
273}
274
275#[cfg(not(docs))]
276with_tuples! {
277    ArcDynFn0,
278
279    (ArcDynFn9, A9),
280    (ArcDynFn8, A8),
281    (ArcDynFn7, A7),
282    (ArcDynFn6, A6),
283
284    (ArcDynFn5, A5),
285    (ArcDynFn4, A4),
286    (ArcDynFn3, A3),
287    (ArcDynFn2, A2),
288    (ArcDynFn1, A1),
289}
290
291#[cfg(docs)]
292with_tuples! {
293    ArcDynFn0,
294    (ArcDynFn1, A1),
295}