Skip to main content

dittolive_ditto_sys/
ffi_utils.rs

1#[rustfmt::skip]
2pub use
3::safer_ffi::{
4    dyn_traits::DynDrop,
5    layout::ReprC,
6    prelude::{char_p, Out},
7}
8;
9
10/// Marker trait that has to be implemented for stuff to be usable in types
11/// such as `repr_c::Vec`.
12#[diagnostic::on_unimplemented(
13    note = "\
14    This is a marker trait used to distinguish normal, well-defined, non-FFI-opaque types, from \
15            the latter, the `extern \"C\" {{ type`s.\n\nIf you are sure this is the case for this \
16            pointee type, then you can simply silence this error by manually writing the \
17            appropriate:\n\n    impl NonOpaque for Foo {{}}\n",
18    label = "Missing `impl NonOpaque for … {{}}`"
19)]
20pub trait NonOpaque: Sized {}
21
22/// Same as `c_slice`, but for coming with a `NonOpaque` obligation / safeguard.
23pub mod c_slice {
24    use super::*;
25
26    guarded_type_alias! {
27        pub
28        type Box<T> where { T : NonOpaque } = ::safer_ffi::prelude::c_slice::Box<T>;
29    }
30
31    guarded_type_alias! {
32        pub
33        type Ref<'lt, T> where { T : 'lt + NonOpaque } = ::safer_ffi::prelude::c_slice::Ref<'lt, T>;
34    }
35}
36
37impl NonOpaque for char_p::Box {}
38impl NonOpaque for char_p::Ref<'_> {}
39impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Box<T> {}
40impl<T: NonOpaque> NonOpaque for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
41impl NonOpaque for i64 {}
42impl NonOpaque for u64 {}
43impl NonOpaque for usize {}
44impl NonOpaque for u8 {}
45impl NonOpaque for bool {}
46/// Pointer indirection guarantees concreteness.
47impl<T> NonOpaque for repr_c::Box<T> where T: FfiDropBox {}
48impl<T> NonOpaque for repr_c::Arc<T> where T: FfiDropArc {}
49
50/// Marker trait to express types for which `Option<Self>` has the same layout as `Self`.
51/// (thanks to discriminant elision).
52pub trait HasNiche {}
53impl<T: HasNiche> NonOpaque for Option<T> {}
54
55impl HasNiche for char_p::Box {}
56impl HasNiche for char_p::Ref<'_> {}
57impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Box<T> {}
58impl<T: NonOpaque> HasNiche for ::safer_ffi::prelude::c_slice::Ref<'_, T> {}
59
60#[diagnostic::on_unimplemented(
61    message = "Pointee type may be opaque",
62    note = "\
63        If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
64            consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
65            companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
66)]
67pub trait FfiDropBox: Sized + ReprC {
68    /// # Safety
69    ///
70    /// Must not be called directly, only in `impl Drop for repr_c::Box<…>`.
71    unsafe fn drop_boxed(it: &mut repr_c::Box<Self>);
72}
73
74/// The drop glue can be written for concrete types.
75impl<T: NonOpaque + ReprC> FfiDropBox for T {
76    unsafe fn drop_boxed(it: &mut repr_c::Box<T>) {
77        unsafe {
78            drop(::std::boxed::Box::from_raw(it.0.ptr.as_mut_ptr()));
79        }
80    }
81}
82
83#[diagnostic::on_unimplemented(
84    message = "Pointee type may be opaque",
85    note = "\
86        If the pointee is some concrete type, rather than one defined by the FFI and opaque, then \
87            consider `impl`ementing `NonOpaque` for it.\n\nOtherwise, you will need to involve a \
88            companion `#[drop(…)] fn` declaration in the `unsafe extern \"C\" {{}}` block."
89)]
90pub trait FfiDropArc: Sized + ReprC {
91    /// # Safety
92    ///
93    /// Must not be called directly, only in `impl Drop for repr_c::Arc<…>`.
94    unsafe fn drop_arced(it: &mut repr_c::Arc<Self>);
95}
96
97/// The drop glue can be written for concrete types.
98impl<T: NonOpaque + ReprC> FfiDropArc for T {
99    unsafe fn drop_arced(it: &mut repr_c::Arc<T>) {
100        unsafe {
101            drop(::std::sync::Arc::from_raw(it.0.ptr.as_mut_ptr()));
102        }
103    }
104}
105
106/// Similar to [`::safer_ffi::prelude::repr_c`] but for a different definition
107/// of `Box`, to catch mistakes with code attempting to treat an
108/// opaque/`extern type` as if it were a well-defined and `Sized` type.
109///
110/// # Opaque types and FFI
111///
112/// Also known as `extern type`s. There is a proper proposal for them in Rust,
113/// but until that, we have had to polyfill them in this crate.
114///
115/// The gist of it, and key takeaway, is that an opaque/`extern type`:
116///
117///   - has an unknown size, so it's technically non-`Sized`,
118///   - and yet, the FFI usually handles these behind **thin** pointer indirection.
119///
120/// And, right now, "thin pointer to a non-`Sized` pointee" is a Rust oxymoron,
121/// due to how it failed to account for such a case and hinged on a `Sized <=> ThinPointee`
122/// architecture.
123///
124/// We work around that by having such types, when polyfilled by our
125/// `extern_type_polyfill!` macro, to be technically `Sized`, as zero-sized
126/// (non-`Copy`) entities: worst case scenario, we'd end up reading or writing 0
127/// bytes, so no harm done.
128///
129/// Right?
130///
131/// Well, the `Box<ExternType>` is a delicate matter: indeed, the *statically-dispatched*
132/// `Drop` glue of `Box<T : Sized>` is defined as follows:
133///
134/// ```rust, ignore
135/// unsafe {
136///     <*mut T>::drop_in_place(ptr);
137///     ::alloc::alloc::dealloc(ptr.cast(), Layout::new::<T>());
138/// }
139/// ```
140///
141///  1. it `drop_in_place()`s the pointee. Since these `extern type`s come with no drop glue, this
142///     is just a no-op (but which eventually would lead to a leak of FFI resources)
143///  2. it deällocates the ptr itself, promising to the allocator that it is a pointer to data of
144///     the given layout, mainly, of the "given" size of `0`! This is wrong, and thus, UB!
145///
146/// The solution, then, relies on defining a custom kind of `c::Box`:
147///
148///  1. `c::Box<T> ~ ptr::NonNull<T>`, layout-wise,
149///  2. `impl<Pointee> Drop for c::Box<Pointee> {` defined as follows:
150///       - if/when the `Pointee` is [`NonOpaque`], by deferring to `drop::<rust::Box<Pointee>>`,
151///       - otherwise, the `Pointee` has an obligation to provide us with a method to drop a
152///         `c::Box<Pointee>`, _via_ the [`FfiDropBox`] trait.
153///
154///         This then shall work in conjunction without `extern_type_polyfill!`
155///         _declarations_ of `extern type`s, since they will then be expected
156///         to declare an accompanying `extern fn dittoffi_free_thingy(_: c::Box<Thingy>);`
157///         _declaration_.
158///         We tell so to the macro through the
159///         `#[drop(to impl FfiDropBox for Thingy)]` annotation on such `fn`.
160///
161/// Once we have done all that, we have successfully defined a `ThinBox<T>`.
162///
163/// But, for the sake of "ergonomics", we'd like our good ol'
164/// `repr_c::Box<dyn Send + FnMut()>` to keep working.
165///
166/// Hence the extra `Box<T : ?Sized + PointeeFitForCBox>` helper trait:
167///
168///   - when `T : Sized`, `T : PointeeFitForCBox<CBoxed = ThinBox<T>>;`
169///   - when `T = dyn Send + FnMut(…)`, `T : PointeeFitForCBox<CBoxed = BoxDynFnMutN<…>>`.
170pub mod repr_c {
171    use ::safer_ffi::layout::ReprC;
172    pub use ::safer_ffi::prelude::repr_c::*;
173
174    use super::*;
175
176    guarded_type_alias! {
177        /// Same as `repr_c::Vec`, but for coming with a `NonOpaque` obligation / safeguard.
178        pub
179        type Vec<T> where { T : NonOpaque } = ::safer_ffi::prelude::repr_c::Vec<T>;
180    }
181
182    /// "Same" as `repr_c::Box`, in the thin case, but for coming with an `impl Drop` obligation,
183    /// and an appropriate override of `Drop`.
184    #[::safer_ffi::derive_ReprC]
185    #[repr(transparent)]
186    pub struct ThinBox<T>
187    where
188        T: FfiDropBox,
189    {
190        pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
191    }
192
193    impl<T> Drop for ThinBox<T>
194    where
195        T: FfiDropBox,
196    {
197        fn drop(&mut self) {
198            unsafe {
199                T::drop_boxed(::core::mem::transmute(self));
200            }
201        }
202    }
203
204    unsafe impl<T> Send for ThinBox<T>
205    where
206        T: FfiDropBox,
207        ::std::boxed::Box<T>: Send,
208    {
209    }
210
211    unsafe impl<T> Sync for ThinBox<T>
212    where
213        T: FfiDropBox,
214        ::std::boxed::Box<T>: Sync,
215    {
216    }
217
218    /// Needed in order to duck-type `::safer_ffi::prelude::repr_c::Box_`.
219    pub use self::Box as Box_;
220
221    /// `c::Box<T>` type.
222    ///
223    /// It is a new `struct` wrapper type unifying:
224    /// - `ThinBox<impl FfiDropBox>`,
225    /// - `BoxDynFnMutN<…>`,
226    /// - `c_slice::Box<T>`,
227    ///
228    /// under one single umbrella:
229    ///
230    /// - `c::Box<impl FfiDropBox>`,
231    /// - `c::Box<dyn Send + FnMut(…) -> …>`,
232    /// - `c::Box<[T]>`.
233    #[::safer_ffi::derive_ReprC]
234    #[repr(transparent)]
235    pub struct Box<T: ?Sized + PointeeFitForCBox>(pub(super) <T as PointeeFitForCBox>::CBoxed);
236
237    #[diagnostic::on_unimplemented(
238        message = "`repr_c::Box<dyn …>` requires `FnMut` rather than `Fn`, alongside `Send` only \
239                   (no `Sync`)",
240        label = "double-check that this be using `FnMut` rather than `Fn`, alongside `Send` only \
241                 (no `Sync`)"
242    )]
243    /// "Type-level function", defining what a `c::Box<Self>` ought to be, layout-wise.
244    pub trait PointeeFitForCBox<Diagnostics = ()> {
245        type CBoxed: ReprC;
246    }
247
248    // For instance:
249    impl<T: Sized + NonOpaque + ReprC> PointeeFitForCBox for [T] {
250        // `c::Box<[T]>` ought to be:
251        type CBoxed = c_slice::Box<T>;
252    }
253
254    // `ThinBox` case:
255    impl<T: Sized + FfiDropBox> PointeeFitForCBox for T {
256        type CBoxed = ThinBox<T>;
257    }
258
259    closure_impls! {
260        dyn Send + FnMut() -> R,
261        dyn Send + FnMut(A) -> R,
262        dyn Send + FnMut(A, B) -> R,
263        dyn Send + FnMut(A, B, C) -> R,
264        dyn Send + FnMut(A, B, C, D) -> R,
265    }
266    // where
267    #[rustfmt::skip]
268    macro_rules! closure_impls {(
269        $(
270            dyn Send + FnMut($($Arg:ident),*) -> $R:ident,
271        )*
272    ) => (
273        $(
274            impl<
275                $R : ReprC $(, $Arg : ReprC)*
276            >
277                PointeeFitForCBox
278            for
279                dyn 'static + Send + FnMut($($Arg),*) -> $R
280            {
281                type CBoxed = ::safer_ffi::prelude::repr_c::Box<
282                    dyn 'static + Send + FnMut($($Arg),*) -> $R,
283                >;
284            }
285
286            impl<
287                T,
288                $R : ReprC $(, $Arg : ReprC)*
289            >
290                From<::std::boxed::Box<T>>
291            for
292                Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
293            where
294                T : 'static + Send + FnMut($($Arg),*) -> $R,
295            {
296                fn from(f: ::std::boxed::Box<T>) -> Self {
297                    Self(f.into())
298                }
299            }
300
301            impl<$R : ReprC $(, $Arg : ReprC)*>
302                Box<dyn 'static + Send + FnMut($($Arg),*) -> $R>
303            {
304                #[allow(nonstandard_style)]
305                pub fn call(&mut self $(, $Arg: $Arg)*) -> $R {
306                    self.0.call($($Arg),*)
307                }
308            }
309
310            repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCBox_impl_diagnostics! {
311                dyn Send? + Sync? + Fn?($($Arg),*) -> $R,
312            }
313        )*
314    )}
315    use closure_impls;
316
317    impl<T> ::core::ops::Deref for Box<T>
318    where
319        T: FfiDropBox,
320    {
321        type Target = T;
322
323        fn deref(self: &'_ Self) -> &'_ T {
324            unsafe { self.0.ptr.as_ref() }
325        }
326    }
327
328    impl<T> ::core::ops::DerefMut for Box<T>
329    where
330        T: FfiDropBox,
331    {
332        fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
333            unsafe { self.0.ptr.as_mut() }
334        }
335    }
336
337    impl<T> ::core::ops::Deref for Box<[T]>
338    where
339        T: NonOpaque + ReprC,
340    {
341        type Target = [T];
342
343        fn deref(self: &'_ Self) -> &'_ [T] {
344            &self.0[..]
345        }
346    }
347
348    impl<T> ::core::ops::DerefMut for Box<[T]>
349    where
350        T: NonOpaque + ReprC,
351    {
352        fn deref_mut(self: &'_ mut Self) -> &'_ mut [T] {
353            &mut self.0[..]
354        }
355    }
356
357    impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Box<T>
358    where
359        T: FfiDropBox,
360    {
361        fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
362            T::fmt(self, f)
363        }
364    }
365
366    // ---------------------------------------------------------------------- //
367
368    /// "Same" as `repr_c::Arc`, in the thin case, but for coming with an `impl Drop` obligation,
369    /// and an appropriate override of `Drop`.
370    #[::safer_ffi::derive_ReprC]
371    #[repr(transparent)]
372    pub struct ThinArc<T>
373    where
374        T: FfiDropArc,
375    {
376        pub(super) ptr: ::safer_ffi::ptr::NonNullOwned<T>,
377    }
378
379    impl<T> Drop for ThinArc<T>
380    where
381        T: FfiDropArc,
382    {
383        fn drop(&mut self) {
384            unsafe {
385                T::drop_arced(::core::mem::transmute(self));
386            }
387        }
388    }
389
390    impl<T> Clone for ThinArc<T>
391    where
392        T: FfiDropArc,
393    {
394        fn clone(&self) -> Self {
395            unsafe {
396                ::std::sync::Arc::increment_strong_count(self.ptr.as_ptr());
397            }
398            Self {
399                ptr: ::safer_ffi::ptr::NonNullOwned::from(self.ptr.0),
400            }
401        }
402    }
403
404    unsafe impl<T> Send for ThinArc<T>
405    where
406        T: FfiDropArc,
407        ::std::sync::Arc<T>: Send,
408    {
409    }
410
411    unsafe impl<T> Sync for ThinArc<T>
412    where
413        T: FfiDropArc,
414        ::std::sync::Arc<T>: Sync,
415    {
416    }
417
418    /// Needed in order to duck-type `::safer_ffi::prelude::repr_c::Arc_`.
419    pub use self::Arc as Arc_;
420
421    /// `c::Arc<T>` type.
422    ///
423    /// It is a new `struct` wrapper type unifying:
424    /// - `ThinArc<impl FfiDropArc>`,
425    /// - `ArcDynFnMutN<…>`,
426    ///
427    /// under one single umbrella:
428    ///
429    /// - `c::Arc<impl FfiDropArc>`,
430    /// - `c::Arc<dyn Send + FnMut(…) -> …>`,
431    #[::safer_ffi::derive_ReprC]
432    #[repr(transparent)]
433    pub struct Arc<T: ?Sized + PointeeFitForCArc>(pub(super) <T as PointeeFitForCArc>::CArced);
434
435    #[diagnostic::on_unimplemented(
436        message = "`repr_c::Arc<dyn …>` requires `Fn` rather than `FnMut`, alongside `Send + Sync`",
437        label = "double-check that this be using `Fn` rather than `FnMut`, alongside `Send + Sync`"
438    )]
439    /// "Type-level function", defining what a `c::Arc<Self>` ought to be, layout-wise.
440    pub trait PointeeFitForCArc<Diagnostics = ()> {
441        type CArced: ReprC;
442    }
443
444    // `ThinArc` case:
445    impl<T: Sized + FfiDropArc> PointeeFitForCArc for T {
446        type CArced = ThinArc<T>;
447    }
448
449    arc_closure_impls! {
450        dyn Send + Sync + Fn() -> R,
451        dyn Send + Sync + Fn(A) -> R,
452        dyn Send + Sync + Fn(A, B) -> R,
453        dyn Send + Sync + Fn(A, B, C) -> R,
454        dyn Send + Sync + Fn(A, B, C, D) -> R,
455    }
456    // where
457    #[rustfmt::skip]
458    macro_rules! arc_closure_impls {(
459        $(
460            dyn Send + Sync + Fn($($Arg:ident),*) -> $R:ident,
461        )*
462    ) => (
463        $(
464            impl<
465                $R : ReprC $(, $Arg : ReprC)*
466            >
467                PointeeFitForCArc
468            for
469                dyn 'static + Send + Sync + Fn($($Arg),*) -> $R
470            {
471                type CArced = ::safer_ffi::prelude::repr_c::Arc<
472                    dyn 'static + Send + Sync + Fn($($Arg),*) -> $R,
473                >;
474            }
475
476            impl<
477                T,
478                $R : ReprC $(, $Arg : ReprC)*
479            >
480                From<::std::sync::Arc<T>>
481            for
482                Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
483            where
484                T : 'static + Send + Sync + Fn($($Arg),*) -> $R,
485            {
486                fn from(f: ::std::sync::Arc<T>) -> Self {
487                    Self(f.into())
488                }
489            }
490
491            impl<$R : ReprC $(, $Arg : ReprC)*>
492                Arc<dyn 'static + Send + Sync + Fn($($Arg),*) -> $R>
493            {
494                #[allow(nonstandard_style)]
495                pub fn call(&self $(, $Arg: $Arg)*) -> $R {
496                    self.0.call($($Arg),*)
497                }
498            }
499
500            repr_c_ptr_dyn_diagnostics::improve_lack_of_PointeeFitForCArc_impl_diagnostics! {
501                dyn Send? + Sync? + FnMut?($($Arg),*) -> $R,
502            }
503        )*
504    )}
505    use arc_closure_impls;
506
507    /// Diagnostic tricks (can technically be removed if hard to maintain, but for
508    /// now they yield nicer DX):
509    mod repr_c_ptr_dyn_diagnostics {
510        include!("repr_c_ptr_dyn_diagnostics.rs");
511    }
512
513    impl<T> ::core::ops::Deref for Arc<T>
514    where
515        T: FfiDropArc,
516    {
517        type Target = T;
518
519        fn deref(self: &'_ Self) -> &'_ T {
520            unsafe { self.0.ptr.as_ref() }
521        }
522    }
523
524    impl<T> ::core::ops::DerefMut for Arc<T>
525    where
526        T: FfiDropArc,
527    {
528        fn deref_mut(self: &'_ mut Self) -> &'_ mut T {
529            unsafe { self.0.ptr.as_mut() }
530        }
531    }
532
533    impl<T: ::std::fmt::Debug> ::std::fmt::Debug for Arc<T>
534    where
535        T: FfiDropArc,
536    {
537        fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
538            T::fmt(self, f)
539        }
540    }
541
542    impl<T> Clone for repr_c::Arc<T>
543    where
544        T: FfiDropArc,
545    {
546        fn clone(&self) -> Self {
547            Self { 0: self.0.clone() }
548        }
549    }
550
551    pub use result::*;
552    mod result {
553        include!(concat!(env!("CARGO_MANIFEST_DIR"), "/", "result.rs"));
554    }
555}
556
557#[cfg_attr(all(rustfmt), rustfmt::skip)]
558macro_rules! extern_type_polyfill {
559    (
560        $( #[$attrs:meta] )*
561        unsafe extern $($abi:literal)? {
562            $($contents:tt)*
563        }
564    ) => (
565        $crate::ffi_utils::extern_type_polyfill! {
566            @internal
567                [$($attrs)*]
568                [$($abi)?]
569            $($contents)*
570        }
571    );
572
573    // extern type case;
574    (
575        @internal $attrs:tt $abi:tt
576
577        $( #[$ty_attrs:meta] )*
578        $pub:vis type $TypeName:ident
579            $(:
580                $SendOrSync:ident
581                $(+ $SendOrSync2:ident)*
582                $(+)?
583            )?
584        ;
585
586        $($rest:tt)*
587    ) => (
588        $( #[$ty_attrs] )*
589        #[::safer_ffi::derive_ReprC]
590        #[repr(opaque)]
591        $pub
592        struct $TypeName {
593            _private: [u8; 0],
594            __not_send_nor_sync: ::core::marker::PhantomData<*const ()>,
595        }
596
597        ::paste::paste! {
598            $pub type [<Boxed $TypeName>] =
599                $crate::ffi_utils::repr_c::Box<$TypeName>
600            ;
601        }
602
603        $(
604            unsafe impl $SendOrSync for $TypeName {}
605            $(
606                unsafe impl $SendOrSync2 for $TypeName {}
607            )*
608        )?
609
610        // This impl never holds since `ExternDropFnAnnotation` never does since
611        // it requires a sealed `NeverImplemented` trait.
612        impl $crate::ffi_utils::NonOpaque for $TypeName
613        where
614            for<'_never_true> // <- this allows using a clause which is trivially `false`
615                              //    / always unsatisfiable.
616                              //    Here, this is useful so that if an `FfiDrop` obligation
617                              //    appears for `$TypeName`, and the companion `#[drop] fn` declaration
618                              //    is missing, Rust will fall back to looking for `NonOpaque`, and
619                              //    complain that *that* is not implemented, which was resulting
620                              //    in a very confusing or even misleading error message.
621                              //
622                              //    Now, thanks to this, it will, in turn, complain about the
623                              //    missing `ExternDropFnAnnotation`, and we have appropriately
624                              //    tweaked the `#[diagnostic::]`s of that `trait` to explain
625                              //    the situation and nudge the users towards the proper solution.
626                $TypeName : $crate::ffi_utils::diagnostic_hack::ExternDropFnAnnotation
627            ,
628        {}
629
630        $crate::ffi_utils::extern_type_polyfill! {
631            @internal $attrs $abi
632            $($rest)*
633        }
634    );
635
636    // FfiDropBox drop case
637    (
638        @internal $attrs:tt $abi:tt
639
640        #[drop(to impl FfiDropBox for $T:ty)]
641        $pub:vis fn $fname:ident (
642            $arg_name:tt : $BoxedTy:ty $(,)?
643        );
644
645        $($rest:tt)*
646    ) => (
647        $crate::ffi_utils::extern_type_polyfill! {
648            @internal $attrs $abi
649
650            /* `#[drop]` stripped */
651            $pub fn $fname (
652                $arg_name : $BoxedTy,
653            );
654
655            $($rest)*
656        }
657
658        impl $crate::ffi_utils::FfiDropBox for $T {
659            unsafe
660            fn drop_boxed (it: &'_ mut $BoxedTy)
661            {
662                unsafe {
663                    $fname(<*const $BoxedTy>::read(it))
664                }
665            }
666        }
667    );
668
669    // FfiDropArc drop case
670    (
671        @internal $attrs:tt $abi:tt
672
673        #[drop(to impl FfiDropArc for $T:ty)]
674        $pub:vis fn $fname:ident (
675            $arg_name:tt : $ArcedTy:ty $(,)?
676        );
677
678        $($rest:tt)*
679    ) => (
680        $crate::ffi_utils::extern_type_polyfill! {
681            @internal $attrs $abi
682
683            /* `#[drop]` stripped */
684            $pub fn $fname (
685                $arg_name : $ArcedTy,
686            );
687
688            $($rest)*
689        }
690
691        impl $crate::ffi_utils::FfiDropArc for $T {
692            unsafe
693            fn drop_arced (it: &'_ mut $ArcedTy)
694            {
695                unsafe {
696                    $fname(<*const $ArcedTy>::read(it))
697                }
698            }
699        }
700    );
701
702    // Default case
703    (
704        @internal [$($attrs:tt)*] [$($abi:literal)?]
705
706        $(#[$fn_attrs:meta])*
707        $pub:vis
708        $(unsafe $(@$if_unsafe:tt)?)?
709        fn $fname:ident $(< $($a:lifetime $(: $b:lifetime)?),* >)? (
710            $($arg_name:ident : $ArgTy:ty),* $(,)?
711        ) $(-> $Ret:ty)?;
712
713        $($rest:tt)*
714    ) => (
715        $(#[$fn_attrs])*
716        #[inline]
717        $pub
718        $($($if_unsafe)?
719            unsafe
720        )?
721        fn $fname $(< $($a $(: $b)?),* >)? (
722            $($arg_name : $ArgTy),*
723        ) $(-> $Ret)?
724        {
725            $( #[$attrs] )*
726            #[allow(improper_ctypes)]
727            extern $($abi)? {
728                $(#[$fn_attrs])*
729                $pub
730                fn $fname $(< $($a $(: $b)?),* >)? (
731                    $($arg_name : $ArgTy),*
732                ) $(-> $Ret)?
733                ;
734            }
735            unsafe {
736                $fname($($arg_name),*)
737            }
738        }
739
740        $crate::ffi_utils::extern_type_polyfill! {
741            @internal [$($attrs)*] [$($abi)?]
742            $($rest)*
743        }
744    );
745
746    (
747        @internal $attrs:tt $abi:tt
748        /* Nothing left to parse */
749    ) => (
750        /* Done. */
751    );
752}
753pub(crate) use extern_type_polyfill;
754
755#[cfg_attr(all(rustfmt), rustfmt::skip)]
756macro_rules! guarded_type_alias {
757    (
758        $( #[doc = $doc:tt] )*
759        $pub:vis
760        type $TypeName:ident [$($generics:tt)*]
761        where {
762            $($where_clauses:tt)*
763        } = $T:ty;
764    ) => (::paste::paste! {
765        #[cfg(not(doc))]
766        #[allow(nonstandard_style)]
767        $pub
768        trait [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
769        where
770            $($where_clauses)*
771        {
772            type T : ?Sized;
773        }
774
775        #[cfg(not(doc))]
776        impl<$($generics)*>
777            [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
778        for
779            ()
780        where
781            $($where_clauses)*
782        {
783            type T = $T;
784        }
785
786        #[cfg(not(doc))]
787        $pub type $TypeName<$($generics)*> =
788            <
789                ()
790                as
791                [<__ChecksForTyAlias__$TypeName>] <$($generics)*>
792            >::T
793        ;
794
795        $( #[doc = $doc] )*
796        #[cfg(doc)]
797        $pub type $TypeName<$($generics)*> where $($where_clauses)* = $T;
798
799    });
800
801    (
802        $( #[doc = $doc:expr] )*
803        $pub:vis type $TypeName:ident
804        <
805            $($lt:lifetime),*
806            $(,)?
807            $($T:ident),*
808        > $($rest:tt)*
809    ) => (
810        $crate::ffi_utils::guarded_type_alias! {
811            $(#[doc = $doc])*
812            $pub type $TypeName [$($lt ,)* $($T),*] $($rest)*
813        }
814    );
815}
816pub(crate) use guarded_type_alias;
817
818/// Defines a `#[repr(i32)] enum Foo { Bar, Baz }` as a
819/// `struct Foo { discriminant: i32 }` with `Foo::Bar, Foo::Baz` as `const`
820/// aliases of `Foo { discriminant: Bar as _ }`, _etc._
821///
822/// This properly models the non-exhaustive nature, **AT THE ABI-LEVEL**, of
823/// these FFI C `enum`s.
824#[cfg_attr(all(rustfmt), rustfmt::skip)]
825macro_rules! non_exhaustive_ffi_enum {(
826    #[repr($int:tt)]
827    $( #$attr:tt )*
828    $pub:vis
829    enum $EnumName:ident {
830        $(
831            $( #[doc $($doc:tt)*] )*
832            $Variant:ident $(= $value:expr)?
833        ),* $(,)?
834    }
835) => (
836    #[repr(transparent)]
837    $( #$attr )*
838    $pub
839    struct $EnumName {
840        discriminant: $int,
841    }
842
843    #[allow(warnings, clippy::all)]
844    const _: () = {
845        #[derive(Debug)]
846        #[repr($int)]
847        enum Discriminants {
848            $(
849                $Variant $(= $value)?
850            ),*
851        }
852
853        impl $EnumName {
854            $(
855                $( #[doc $($doc)*] )*
856                $pub const $Variant: Self = Self {
857                    discriminant: Discriminants::$Variant as _,
858                };
859            )*
860        }
861
862        impl ::core::fmt::Debug for $EnumName {
863            fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>)
864              -> ::core::fmt::Result
865            {
866                match *self {
867                $(
868                    | Self::$Variant => Discriminants::$Variant.fmt(f),
869                )*
870                    | Self { discriminant: unknown_discriminant } => {
871                        #[::core::prelude::v1::derive(::core::fmt::Debug)]
872                        struct $EnumName {
873                            unknown_discriminant: $int,
874                        }
875
876                        $EnumName { unknown_discriminant }.fmt(f)
877                    }
878                }
879            }
880        }
881    };
882)}
883pub(crate) use non_exhaustive_ffi_enum;
884
885pub mod diagnostic_hack {
886    mod seal {
887        pub trait NeverImplemented {}
888    }
889
890    #[rustfmt::skip]
891    #[diagnostic::on_unimplemented(
892        message = "\
893            The pointee type is missing its companion `#[drop(…)] fn …;` declaration.",
894        note = "\
895`extern type`s have no known size or statically-dispatchable `drop_in_place()` logic, \
896which is otherwise ordinarily the case, and the reason `drop::<Box<T>>()` is \
897well-defined.
898
899Since it is not the case here, we need to manually tell Rust how \"an owned pointed to \
900a `T`\" (a `c::Box<T>`) is to be dropped.
901
902This is done through the `FfiDropBox` trait, which is automagically defined and \
903implemented for `extern type`s which have the following kind of companion annotation:
904
905    #[apply(extern_type_polyfill!)]
906    extern \"C\" {{
907908
909        type Foo : …;
910
911        #[drop(to impl FfiDropBox for Foo)]
912        fn dittoffi_current_type_free(_: c::Box<Foo>);
913
914915    }}
916\
917        ",
918    )]
919    pub trait ExternDropFnAnnotation: Sized + seal::NeverImplemented {}
920}