[][src]Trait safer_ffi::layout::CType

pub unsafe trait CType: Sized + Copy {
    type OPAQUE_KIND: __;
    fn c_short_name_fmt(fmt: &mut Formatter) -> Result;
fn c_var_fmt(fmt: &mut Formatter, var_name: &str) -> Result; fn c_short_name() -> ImplDisplay<Self> { ... }
fn c_define_self(definer: &mut dyn Definer) -> Result<()> { ... }
fn c_var(var_name: &str) -> ImplDisplay<Self> { ... } }

One of the two core traits of this crate (with ReprC).

CType is an unsafe trait that binds a Rust type to a C typedef.

To optimise compile-times, the C typedef part is gated behind the headers cargo feature, so when that feature is not enabled, the trait may "look" like a marker trait, but it isn't.

That's why manually implementing this trait is strongly discouraged, although not forbidden:

  • If you trully want a manual implementation of CType (e.g., for an "opaque type" pattern, i.e., a forward declaration), then, to implement the trait so that it works no matter the status of the safer_ffi/headers feature, one must define the methods as if feature was present, but with a #[::safer_ffi::cfg_headers] gate slapped on each method.

Safety

The Rust type in an extern "C" function must have the same layout and ABI as the defined C type, and all the bit-patterns representing any instance of such C type must be valid and safe bit-patterns for the Rust type.

For the most common types, there are only two reasons to correctly be a CType:

  • being a primitive type, such as an integer type or a (slim) pointer.

    • This crates provides as many of these implementations as possible.
  • an recursively, a non-zero-sized #[repr(C)] struct of CType fields.

    • the CType! macro can be used to wrap a #[repr(C)] struct definition to safely and automagically implement the trait when it is sound to do so.

Note that types such as Rust's bool are ruled out by this definition, since it has the ABI of a u8 <-> uint8_t, and yet there are many bit-patterns for the uint8_t type that do not make valid bools.

For such types, see the ReprC trait.

Associated Types

Loading content...

Required methods

fn c_short_name_fmt(fmt: &mut Formatter) -> Result

A short-name description of the type, mainly used to fill "placeholders" such as when monomorphising generics structs or arrays.

This provides the implementation used by CType::c_short_name().

There are no bad implementations of this method, except, of course, for the obligation to provide a valid identifier chunk, i.e., the output must only contain alphanumeric digits and underscores.

For instance, given T : CType and const N: usize > 0, the type [T; N] (inline fixed-size array of N consecutive elements of type T) will be typedef-named as:

This example is not tested
write!(fmt, "{}_{}_array", <T as CType>::c_short_name(), N)

Generally, typedefs with a trailing _t will see that _t trimmed when used as a short_name.

Implementation by CType!:

A non generic struct such as:

This example is not tested
CType! {
    #[repr(C)]
    struct Foo { /* fields */ }
}

will have Foo as its short_name.

A generic struct such as:

This example is not tested
CType! {
    #[repr(C)]
    struct Foo[T] where { T : CType } { /* fields */ }
}

will have Foo_xxx as its short_name, with xxx being T's short_name.

fn c_var_fmt(fmt: &mut Formatter, var_name: &str) -> Result

The core method of the trait: it provides the implementation to be used by CType::c_var, by bringing a Formatter in scope.

This provides the implementation used by CType::c_var().

The implementations are thus much like any classic Display impl, except that:

  • it must output valid C code representing the type corresponding to the Rust type.

  • a var_name may be supplied, in which case the type must use that as its "variable name" (C being how it is, the var with arrays and function pointers).

Safety

Here is where the meat of the safety happens: associating a Rust type to a non-corresponding C definition will cause Undefined Behavior when a function using such type in its ABI is called.

Examples

i32

This example is not tested
unsafe impl CType for i32 {
    #[::safer_ffi::cfg_headers]
    fn c_var_fmt (
        fmt: &'_ mut fmt::Formatter<'_>,
        var_name: &'_ str,
    ) -> fmt::Result
    {
        write!(fmt, "int32_t {}", var_name)
    }

    // ...
}

Option<extern "C" fn (i32) -> u32>

This example is not tested
unsafe impl CType for Option<extern "C" fn (i32) -> u32> {
    #[::safer_ffi::cfg_headers]
    fn c_var_fmt (
        fmt: &'_ mut fmt::Formatter<'_>,
        var_name: &'_ str,
    ) -> fmt::Result
    {
        write!(fmt, "uint32_t (*{})(int32_t)", var_name)
    }

    // ...
}

[i32; 42]

This example is not tested
unsafe impl CType for [i32; 42] {
    #[::safer_ffi::cfg_headers]
    fn c_var_fmt (
        fmt: &'_ mut fmt::Formatter<'_>,
        var_name: &'_ str,
    ) -> fmt::Result
    {
        let typedef_name = format_args!("{}_t", Self::c_short_name());
        write!(fmt, "{} {}", typedef_name, var_name)
    }

    // Since `c_var_fmt()` requires a one-time typedef, overriding
    // `c_define_self()` is necessary:
    #[::safer_ffi::cfg_headers]
    fn c_define_self (definer: &'_ mut dyn Definer)
      -> fmt::Result
    {
        let typedef_name = &format!("{}_t", Self::c_short_name());
        definer.define_once(typedef_name, &mut |definer| {
            // ensure the array element type is defined
            i32::c_define_self(definer)?;
            write!(definer.out(),
                "typedef struct {{ {0}; }} {1};\n",
                i32::c_var("arr[42]"), // `int32_t arr[42]`
                typedef_name,
            )
        })
    }

    // etc.
}
Loading content...

Provided methods

fn c_short_name() -> ImplDisplay<Self>

Convenience function for callers / users of types implementing CType.

The Display logic is auto-derived from the implementation of CType::c_short_name_fmt().

fn c_define_self(definer: &mut dyn Definer) -> Result<()>

Necessary one-time code for CType::c_var() to make sense.

Some types, such as char, are part of the language, and can be used directly by CType::c_var(). In that case, there is nothing else to define, and all is fine.

  • That is the default implementation of this method: doing nothing.

But most often than not, a typedef or an #include is required.

In that case, here is the place to put it, with the help of the provided Definer.

Idempotent

Given some definer: &mut dyn Definer, the c_define_self(definer) call must be idempotent w.r.t. code generated. In other words, two or more such calls must not generate any extra code w.r.t the first call.

This is easy to achieve thanks to definer:

This example is not tested
// This ensures the idempotency requirements are met.
definer.define_once(
    // some unique `&str`, ideally the C name being defined:
    "my_super_type_t",
    // Actual code generation logic, writing to `definer.out()`
    &mut |definer| {
        // If the typdef recursively needs other types being defined,
        // ensure it is the case by explicitly calling
        // `c_define_self(definer)` on those types.
        OtherType::c_define_self(definer)?;
        write!(definer.out(), "typedef ... my_super_type_t;", ...)
    },
)?

Safety

Given that the defined types may be used by CType::c_var_fmt(), the same safety disclaimers apply.

Examples

i32

The corresponding type for i32 in C is int32_t, but such type definition is not part of the language, it is brought by a library instead: <stdint.h> (or <inttypes.h> since it includes it).

This example is not tested
unsafe impl CType for i32 {
    #[::safer_ffi::cfg_headers]
    fn c_define_self (definer: &'_ mut dyn Definer)
      -> io::Result<()>
    {
        definer.define_once("<stdint.h>", &mut |definer| {
            write!(definer.out(), "\n#include <stdint.h>\n")
        })
    }

    // ...
}

#[repr(C)] struct Foo { x: i32 }

This example is not tested
#[repr(C)]
struct Foo {
    x: i32,
}

unsafe impl CType for i32 {
    #[::safer_ffi::cfg_headers]
    fn c_define_self (definer: &'_ mut dyn Definer)
      -> io::Result<()>
    {
        definer.define_once("Foo_t", &mut |definer| {
            // ensure int32_t makes sense
            <i32 as CType>::c_define_self(definer)?;
            write!(definer.out(),
                "typedef struct {{ {}; }} Foo_t;",
                <i32 as CType>::c_var("x"),
            )
        })
    }

    // ...
}

fn c_var(var_name: &str) -> ImplDisplay<Self>

Convenience function for callers / users of types implementing CType.

The Display logic is auto-derived from the implementation of CType::c_var_fmt().

Loading content...

Implementations on Foreign Types

impl<T: CType> CType for *const T[src]

type OPAQUE_KIND = Concrete

impl<T: CType> CType for *mut T[src]

type OPAQUE_KIND = Concrete

impl CType for f32[src]

type OPAQUE_KIND = Concrete

impl CType for f64[src]

type OPAQUE_KIND = Concrete

impl CType for u8[src]

type OPAQUE_KIND = Concrete

impl CType for u16[src]

type OPAQUE_KIND = Concrete

impl CType for u32[src]

type OPAQUE_KIND = Concrete

impl CType for u64[src]

type OPAQUE_KIND = Concrete

impl CType for usize[src]

type OPAQUE_KIND = Concrete

impl CType for i8[src]

type OPAQUE_KIND = Concrete

impl CType for i16[src]

type OPAQUE_KIND = Concrete

impl CType for i32[src]

type OPAQUE_KIND = Concrete

impl CType for i64[src]

type OPAQUE_KIND = Concrete

impl CType for isize[src]

type OPAQUE_KIND = Concrete

impl<Ret: CType> CType for Option<unsafe extern "C" fn() -> Ret>[src]

Simplified for lighter documentation, but the actual impls include up to 9 function parameters.

type OPAQUE_KIND = Concrete

impl<Ret: CType, A1: CType> CType for Option<unsafe extern "C" fn(_: A1) -> Ret>[src]

Simplified for lighter documentation, but the actual impls include up to 9 function parameters.

type OPAQUE_KIND = Concrete

impl<Item: CType> CType for [Item; 1][src]

Simplified for lighter documentation, but the actual impls range from 1 up to 32, plus a bunch of significant lengths up to 1024.

type OPAQUE_KIND = Concrete

impl<Item: CType> CType for [Item; 2][src]

Simplified for lighter documentation, but the actual impls range from 1 up to 32, plus a bunch of significant lengths up to 1024.

type OPAQUE_KIND = Concrete

Loading content...

Implementors

impl<'lt, Ret> CType for RefDynFnMut0<'lt, Ret> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret as ReprC>::CLayout: CType,
    <PhantomData<&'lt ()> as ReprC>::CLayout: CType,
    Ret: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret: ReprC,
    PhantomData<&'lt ()>: ReprC,
    Ret: ReprC,
    Ret: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<'lt, Ret, A1> CType for RefDynFnMut1<'lt, Ret, A1> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret as ReprC>::CLayout: CType,
    <PhantomData<&'lt ()> as ReprC>::CLayout: CType,
    Ret: ReprC,
    A1: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret: ReprC,
    PhantomData<&'lt ()>: ReprC,
    Ret: ReprC,
    A1: ReprC,
    Ret: ReprC,
    A1: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<'lt, T> CType for slice_mut<'lt, T> where
    <NonNullMut<T> as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    <PhantomData<&'lt ()> as ReprC>::CLayout: CType,
    T: ReprC,
    NonNullMut<T>: ReprC,
    usize: ReprC,
    PhantomData<&'lt ()>: ReprC,
    T: ReprC,
    T: 'lt, 
[src]

type OPAQUE_KIND = Concrete

impl<'lt, T> CType for slice_ref<'lt, T> where
    <NonNullRef<T> as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    <PhantomData<&'lt ()> as ReprC>::CLayout: CType,
    T: ReprC,
    NonNullRef<T>: ReprC,
    usize: ReprC,
    PhantomData<&'lt ()>: ReprC,
    T: ReprC,
    T: 'lt, 
[src]

type OPAQUE_KIND = Concrete

impl<Ret> CType for ArcDynFn0<Ret> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) as ReprC>::CLayout: CType,
    <Option<unsafe extern "C" fn(env_ptr: NonNull<c_void>)> as ReprC>::CLayout: CType,
    Ret: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>): ReprC,
    Option<unsafe extern "C" fn(env_ptr: NonNull<c_void>)>: ReprC,
    Ret: ReprC,
    Ret: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<Ret> CType for BoxDynFnMut0<Ret> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) as ReprC>::CLayout: CType,
    Ret: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>): ReprC,
    Ret: ReprC,
    Ret: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<Ret, A1> CType for ArcDynFn1<Ret, A1> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) as ReprC>::CLayout: CType,
    <Option<unsafe extern "C" fn(env_ptr: NonNull<c_void>)> as ReprC>::CLayout: CType,
    Ret: ReprC,
    A1: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>): ReprC,
    Option<unsafe extern "C" fn(env_ptr: NonNull<c_void>)>: ReprC,
    Ret: ReprC,
    A1: ReprC,
    Ret: ReprC,
    A1: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<Ret, A1> CType for BoxDynFnMut1<Ret, A1> where
    <NonNull<c_void> as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret as ReprC>::CLayout: CType,
    <unsafe extern "C" fn(env_ptr: NonNull<c_void>) as ReprC>::CLayout: CType,
    Ret: ReprC,
    A1: ReprC,
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>, _: A1) -> Ret: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>): ReprC,
    Ret: ReprC,
    A1: ReprC,
    Ret: ReprC,
    A1: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<T> CType for slice_boxed<T> where
    <NonNullOwned<T> as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    T: ReprC,
    NonNullOwned<T>: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<T> CType for slice_raw<T> where
    <NonNull<T> as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    T: ReprC,
    NonNull<T>: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<T> CType for Vec<T> where
    <NonNullOwned<T> as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    <usize as ReprC>::CLayout: CType,
    T: ReprC,
    NonNullOwned<T>: ReprC,
    usize: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type OPAQUE_KIND = Concrete

impl<T0, T1> CType for Tuple2<T0, T1> where
    <T0 as ReprC>::CLayout: CType,
    <T1 as ReprC>::CLayout: CType,
    T0: ReprC,
    T1: ReprC,
    T0: ReprC,
    T1: ReprC,
    T0: ReprC,
    T1: ReprC
[src]

type OPAQUE_KIND = Concrete

Loading content...