safer_ffi/
_lib.rs

1#![warn(warnings)] // Prevent `-Dwarnings` from causing breakage.
2#![allow(clippy::all)]
3#![cfg_attr(rustfmt, rustfmt::skip)]
4#![cfg_attr(feature = "nightly",
5    feature(doc_cfg)
6)]
7#![cfg_attr(not(feature = "std"),
8    no_std,
9)]
10
11#![allow(
12    nonstandard_style,
13    trivial_bounds,
14    unused_parens,
15)]
16#![warn(
17    missing_copy_implementations,
18    missing_debug_implementations,
19)]
20#![deny(
21    bare_trait_objects,
22    elided_lifetimes_in_paths,
23    unconditional_recursion,
24    unused_must_use,
25)]
26#![doc = include_str!("../README.md")]
27
28#[macro_use]
29extern crate macro_rules_attribute;
30
31#[macro_use]
32#[path = "utils/_mod.rs"]
33#[doc(hidden)] /** Not part of the public API **/ pub
34mod __utils__;
35use __utils__ as utils;
36
37#[apply(hidden_export)]
38use ::paste;
39
40/// Export a function to be callable by C.
41///
42/// # Example
43///
44/// ```rust
45/// use ::safer_ffi::prelude::ffi_export;
46///
47/// #[ffi_export]
48/// /// Add two integers together.
49/// fn add (x: i32, y: i32) -> i32
50/// {
51///     x + y
52/// }
53/// ```
54///
55///   - ensures that [the generated headers](/safer_ffi/headers/) will include the
56///     following definition:
57///
58///     ```C
59///     #include <stdint.h>
60///
61///     /* \brief
62///      * Add two integers together.
63///      */
64///     int32_t add (int32_t x, int32_t y);
65///     ```
66///
67///   - exports an `add` symbol pointing to the C-ABI compatible
68///     `int32_t (*)(int32_t x, int32_t y)` function.
69///
70///     (The crate type needs to be `cdylib` or `staticlib` for this to work,
71///     and, of course, the C compiler invocation needs to include
72///     `-L path/to/the/compiled/library -l name_of_your_crate`)
73///
74///       - when in doubt, use `staticlib`.
75///
76/// # `ReprC`
77///
78/// You can use any Rust types in the singature of an `#[ffi_export]`-
79/// function, provided each of the types involved in the signature is [`ReprC`].
80///
81/// Otherwise the layout of the involved types in the C world is **undefined**,
82/// which `#[ffi_export]` will detect, leading to a compilation error.
83///
84/// To have custom structs implement [`ReprC`], it suffices to annotate the
85/// `struct` definitions with the <code>#\[[derive_ReprC]\]</code>
86/// (on top of the obviously required `#[repr(C)]`).
87pub use ::safer_ffi_proc_macros::ffi_export;
88
89/// Identity macro when `feature = "headers"` is enabled, otherwise
90/// this macro outputs nothing.
91pub use ::safer_ffi_proc_macros::cfg_headers;
92
93/// Creates a compile-time checked [`char_p::Ref`]`<'static>` out of a
94/// string literal.
95///
96/// # Example
97///
98/// ```rust
99/// use ::safer_ffi::prelude::*;
100///
101/// #[ffi_export]
102/// fn concat (s1: char_p::Ref<'_>, s2: char_p::Ref<'_>)
103///   -> char_p::Box
104/// {
105///     format!("{}{}", s1.to_str(), s2.to_str())
106///         .try_into()
107///         .unwrap() // No inner nulls in our format string
108/// }
109///
110/// fn main ()
111/// {
112///     assert_eq!(
113///         concat(c!("Hello, "), c!("World!")).as_ref(),
114///         c!("Hello, World!"),
115///     );
116/// }
117/// ```
118///
119/// If the string literal contains an inner null byte, then the macro
120/// will detect it at compile time and thus cause a compile-time error
121/// (allowing to skip the then unnecessary runtime check!):
122///
123/// ```rust,compile_fail
124/// let _ = ::safer_ffi::c!("Hell\0, World!"); // <- Compile error
125/// ```
126///
127/// [`char_p::Ref`]: `crate::prelude::char_p::Ref`
128pub use ::safer_ffi_proc_macros::c_str as c;
129
130/// Safely implement [`ReprC`]
131/// for a `#[repr(C)]` struct **when all its fields are [`ReprC`]**.
132///
133/// # Examples
134///
135/// ### Simple `struct`
136///
137/// ```rust
138/// use ::safer_ffi::prelude::*;
139///
140/// #[derive_ReprC]
141/// #[repr(C)]
142/// struct Instant {
143///     seconds: u64,
144///     nanos: u32,
145/// }
146/// ```
147///
148///   - corresponding to the following C definition:
149///
150///     ```C
151///     typedef struct {
152///         uint64_t seconds;
153///         uint32_t nanos;
154///     } Instant_t;
155///     ```
156///
157/// ### Field-less `enum`
158///
159/// ```rust
160/// use ::safer_ffi::prelude::*;
161///
162/// #[derive_ReprC]
163/// #[repr(u8)]
164/// enum Status {
165///     Ok = 0,
166///     Busy,
167///     NotInTheMood,
168///     OnStrike,
169///     OhNo,
170/// }
171/// ```
172///
173///   - corresponding to the following C definition:
174///
175///     ```C
176///     typedef uint8_t Status_t; enum {
177///         STATUS_OK = 0,
178///         STATUS_BUSY,
179///         STATUS_NOT_IN_THE_MOOD,
180///         STATUS_ON_STRIKE,
181///         STATUS_OH_NO,
182///     }
183///     ```
184///
185/// ### Generic `struct`
186///
187/// In that case, it is required that the struct's generic types carry a
188/// `: ReprC` bound each:
189///
190/// ```rust
191/// use ::safer_ffi::prelude::*;
192///
193/// #[derive_ReprC]
194/// #[repr(C)]
195/// struct Point<Coordinate : ReprC> {
196///     x: Coordinate,
197///     y: Coordinate,
198/// }
199/// #
200/// # fn main() {}
201/// ```
202///
203/// Each monomorphization leads to its own C definition:
204///
205///   - **`Point<i32>`**
206///
207///     ```C
208///     typedef struct {
209///         int32_t x;
210///         int32_t y;
211///     } Point_int32_t;
212///     ```
213///
214///   - **`Point<f64>`**
215///
216///     ```C
217///     typedef struct {
218///         double x;
219///         double y;
220///     } Point_double_t;
221///     ```
222pub use ::safer_ffi_proc_macros::derive_ReprC;
223
224#[macro_use]
225#[path = "layout/_mod.rs"]
226pub mod layout;
227
228__cfg_headers__! {
229    #[doc(hidden)] pub
230    use ::inventory;
231
232    #[cfg_attr(feature = "nightly",
233        doc(cfg(feature = "headers")),
234    )]
235    #[path = "headers/_mod.rs"]
236    pub
237    mod headers;
238
239    #[allow(missing_copy_implementations, missing_debug_implementations)]
240    #[doc(hidden)] /** Not part of the public API */ pub
241    struct FfiExport {
242        pub
243        name: &'static str,
244
245        pub
246        gen_def:
247            fn(&mut dyn headers::Definer, headers::Language)
248              -> std::io::Result<()>
249        ,
250    }
251
252    self::inventory::collect!(FfiExport);
253}
254
255cfg_alloc! {
256    extern crate alloc;
257}
258
259cfg_alloc! {
260    pub
261    mod boxed;
262}
263
264pub
265mod bytes;
266
267#[doc(inline)]
268pub use self::c_char_module::c_char;
269#[path = "c_char.rs"]
270mod c_char_module;
271
272pub
273mod char_p;
274
275pub
276mod closure;
277
278#[cfg(feature = "dyn-traits")]
279#[cfg_attr(feature = "nightly",
280    doc(cfg(feature = "dyn-traits")),
281)]
282#[path = "dyn_traits/_mod.rs"]
283pub
284mod dyn_traits;
285
286#[cfg(feature = "futures")]
287#[cfg_attr(all(docs, feature = "nightly"),
288    doc(cfg(feature = "futures"))
289)]
290#[doc(no_inline)]
291pub use dyn_traits::futures;
292
293pub
294mod libc;
295
296pub
297mod option;
298
299pub
300mod ptr;
301
302pub
303mod slice;
304
305#[cfg(feature = "stabby")]
306#[cfg_attr(all(docs, feature = "nightly"),
307    doc(cfg(feature = "stabby"))
308)]
309#[path = "stabby/_mod.rs"]
310pub
311mod stabby;
312
313#[path = "string/_mod.rs"]
314pub
315mod string;
316
317#[doc(no_inline)]
318pub
319use tuple::*;
320
321pub
322mod tuple;
323
324cfg_alloc! {
325    #[doc(inline)]
326    pub use string::String;
327
328    #[doc(inline)]
329    pub use vec::Vec;
330    pub mod vec;
331}
332
333#[doc(inline)]
334pub use layout::impls::c_int;
335
336pub
337mod prelude {
338    #[doc(no_inline)]
339    pub use crate::{
340        ffi_export,
341        layout::ReprC,
342    };
343    pub
344    mod char_p {
345        #[doc(no_inline)]
346        pub use crate::char_p::{
347            char_p_raw as Raw,
348            char_p_ref as Ref,
349        };
350        cfg_alloc! {
351            #[doc(no_inline)]
352            pub use crate::char_p::{
353                char_p_boxed as Box,
354                new,
355            };
356        }
357    }
358    pub
359    mod c_slice {
360        #[doc(no_inline)]
361        pub use crate::slice::{
362            slice_mut as Mut,
363            slice_raw as Raw,
364            slice_ref as Ref,
365        };
366        cfg_alloc! {
367            #[doc(no_inline)]
368            pub use crate::slice::slice_boxed as Box;
369        }
370    }
371    pub
372    mod repr_c {
373        cfg_alloc! {
374            #[doc(no_inline)]
375            pub use crate::{
376                boxed::Box,
377                string::String,
378                vec::Vec,
379                option::TaggedOption,
380            };
381
382            pub
383            type Arc<T> = <T as crate::boxed::FitForCArc>::CArcWrapped;
384        }
385    }
386    pub
387    mod str {
388        #[doc(no_inline)]
389        pub use crate::string::{
390            // str_raw as Raw,
391            str_ref as Ref,
392        };
393        cfg_alloc! {
394            #[doc(no_inline)]
395            pub use crate::string::str_boxed as Box;
396        }
397    }
398
399    #[doc(no_inline)]
400    pub use {
401        crate::layout::derive_ReprC,
402        ::safer_ffi_proc_macros::derive_ReprC2,
403        crate::c,
404        ::core::{
405            convert::{
406                TryFrom as _,
407                TryInto as _,
408            },
409            ops::Not as _,
410        },
411    };
412
413    pub use ::uninit::prelude::{
414        // Out reference itself
415        Out,
416        // Helper trait to go from `&mut T` and `&mut MaybeUninit<T>` to `Out<T>`
417        AsOut,
418        // Helper trait to have `AsOut` when `T : !Copy`
419        ManuallyDropMut,
420    };
421
422    #[cfg(feature = "dyn-traits")]
423    #[cfg_attr(all(docs, feature = "nightly"),
424        doc(cfg(feature = "dyn-traits"))
425    )]
426    pub use crate::dyn_traits::VirtualPtr;
427}
428
429#[macro_export]
430macro_rules! NULL {() => (
431    $crate::ඞ::ptr::null_mut()
432)}
433
434#[cfg(feature = "log")]
435#[apply(hidden_export)]
436use ::log;
437
438#[cfg(feature = "js")]
439// #[apply(hidden_export)]
440#[path = "js/_mod.rs"]
441pub mod js;
442
443#[apply(hidden_export)]
444#[allow(missing_copy_implementations, missing_debug_implementations)]
445struct __PanicOnDrop__ {} impl Drop for __PanicOnDrop__ {
446    fn drop (self: &'_ mut Self)
447    {
448        panic!()
449    }
450}
451
452#[apply(hidden_export)]
453macro_rules! __abort_with_msg__ { ($($tt:tt)*) => (
454    match ($crate::__PanicOnDrop__ {}) { _ => {
455        $crate::ඞ::__error__!($($tt)*);
456        $crate::ඞ::panic!($($tt)*);
457    }}
458)}
459
460extern crate self as safer_ffi;
461
462#[apply(hidden_export)]
463use __ as ඞ;
464
465#[apply(hidden_export)]
466mod __ {
467    #[cfg(feature = "alloc")]
468    pub extern crate alloc;
469
470    pub use {
471        ::core::{
472            self,
473            marker::PhantomData,
474            pin::Pin,
475            primitive::{
476                u8, u16, u32, usize, u64, u128,
477                i8, i16, i32, isize, i64, i128,
478                bool,
479                char,
480                str,
481            },
482        },
483        ::scopeguard::{
484            self,
485        },
486        crate::{
487            ptr,
488            layout::{
489                CLayoutOf,
490                ConcreteReprC,
491                CType,
492                OpaqueKind,
493                ReprC,
494                __HasNiche__,
495            },
496            prelude::*,
497        },
498    };
499
500    #[cfg(feature = "headers")]
501    pub use {
502        crate::{
503            headers::{
504                Definer,
505                Language,
506                languages::{
507                    self,
508                    EnumVariant,
509                    FunctionArg,
510                    HeaderLanguage,
511                    StructField,
512                },
513            },
514            inventory,
515            FfiExport,
516        },
517    };
518
519    match_cfg! {
520        feature = "std" => {
521            pub use ::std::{*,
522                self,
523                prelude::rust_2021::*,
524            };
525        },
526        feature = "alloc" => {
527            pub use {
528                ::core::{*,
529                    prelude::rust_2021::*,
530                },
531                ::alloc::{
532                    boxed::Box,
533                    string::String,
534                    vec::Vec,
535                },
536            };
537        },
538        _ => {
539            pub use ::core::{*,
540                prelude::rust_2021::*,
541            };
542        }
543    }
544
545    /// Hack needed to `feature(trivial_bounds)` in stable Rust:
546    ///
547    /// Instead of `where Ty : Bounds…`, it suffices to write:
548    /// `where for<'trivial> Identity<'trivial, Ty> : Bounds…`.
549    pub
550    type Identity<'hrtb, T> =
551        <T as IdentityIgnoring<'hrtb>>::ItSelf
552    ;
553    // where
554    pub
555    trait IdentityIgnoring<'__> {
556        type ItSelf : ?Sized;
557    }
558    impl<T : ?Sized> IdentityIgnoring<'_> for T {
559        type ItSelf = Self;
560    }
561
562    match_cfg! {
563        feature = "log" => {
564            #[apply(hidden_export)]
565            macro_rules! __error__ {( $($msg:tt)* ) => (
566                $crate::log::error! { $($msg)* }
567            )}
568        },
569        feature = "std" => {
570            #[apply(hidden_export)]
571            macro_rules! __error__ {( $($msg:tt)* ) => (
572                $crate::ඞ::eprintln! { $($msg)* }
573            )}
574        },
575        _ => {
576            #[apply(hidden_export)]
577            macro_rules! __error__ {( $($msg:tt)* ) => (
578                /* nothing we can do */
579            )}
580        },
581    }
582    pub use __error__;
583
584    #[allow(missing_debug_implementations)]
585    pub
586    struct UnwindGuard /* = */ (
587        pub &'static str,
588    );
589
590    impl Drop for UnwindGuard {
591        fn drop (self: &'_ mut Self)
592        {
593            let &mut Self(fname) = self;
594            __abort_with_msg__!("\
595                Error, attempted to panic across the FFI \
596                boundary of `{fname}()`, \
597                which is Undefined Behavior.\n\
598                Aborting for soundness.\
599            ");
600        }
601    }
602
603    #[cfg(feature = "alloc")]
604    pub
605    fn append_unqualified_name (
606        out: &'_ mut String,
607        ty_name: &'_ str,
608    )
609    {
610        #[inline(never)]
611        fn mb_split_with<'r> (
612            orig: &'r str,
613            splitter: fn(&'r str) -> Option<(&'r str, &'r str)>,
614        ) -> (&'r str, Option<&'r str>)
615        {
616            splitter(orig).map_or((orig, None), |(l, r)| (l, Some(r)))
617        }
618
619        let ty_name = ty_name.trim();
620        if let Some(tuple_innards) = ty_name.strip_prefix('(') {
621            // Tuple
622            tuple_innards
623                .strip_suffix(')').unwrap()
624                .split(',')
625                .for_each(|generic| {
626                    append_unqualified_name(out, generic);
627                })
628            ;
629        } else if let Some(bracketed_innards) = ty_name.strip_prefix('[') {
630            // Array or Slice
631            let (elem_ty, mb_len) = mb_split_with(
632                bracketed_innards.strip_suffix(']').unwrap(),
633                |s| s.rsplit_once(';'),
634            );
635            append_unqualified_name(out, elem_ty);
636            if let Some(len) = mb_len {
637                append_unqualified_name(out, len);
638            }
639        } else {
640            // Canonical Type Path
641            out.push('_');
642            let (mut path, mb_generics) = mb_split_with(
643                ty_name,
644                |s| s.split_once('<'),
645            );
646            let is_valid_for_ident = |c: char| {
647                c.is_alphanumeric() || matches!(c, '_')
648            };
649            if let Some(trait_path) = path.strip_prefix("dyn ") {
650                out.push_str("dyn_");
651                path = trait_path;
652            }
653            if path.chars().all(|c| is_valid_for_ident(c) || c == ':') {
654                let unqualified = path.rsplitn(2, ':').next().unwrap().trim();
655                out.push_str(unqualified);
656            } else {
657                // Weird type, fall back to replacing non_alphanumerics:
658                path.chars().for_each(|c| {
659                    out.push(if is_valid_for_ident(c) { c } else { '_' });
660                });
661            }
662            if let Some(generics) = mb_generics {
663                let generics = generics.strip_suffix('>').unwrap();
664                generics.split(',').for_each(|generic| {
665                    append_unqualified_name(out, generic);
666                });
667            }
668        }
669    }
670
671    #[doc(hidden)] /** Not part of the public API! */
672    #[macro_export]
673    macro_rules! ඞassert_expr {( $e:expr $(,)? ) => ( $e )}
674    #[doc(inline)]
675    pub use ඞassert_expr as assert_expr;
676}