[][src]Trait safer_ffi::layout::ReprC

pub unsafe trait ReprC: Sized {
    type CLayout: CType;
    fn is_valid(it: &Self::CLayout) -> bool;
}

The meat of the crate. The trait. This trait describes that a type has a defined / fixed #[repr(C)] layout.

This is expressed at the type level by the unsafe (trait) type association of ReprC::CLayout, which must be a CType.

Because of that property, the type may be used in the API of an #[ffi_export]-ed function, where ABI-wise it will be replaced by its equivalent C layout.

Then, #[ffi_export] will transmute the CType parameters back to the provided ReprC types, using from_raw_unchecked.

Although, from a pure point of view, no checks are performed at this step whatsoever, in practice, when debug_assertions are enabled, some "sanity checks" are performed on the input parameters: ReprC::is_valid is called in that case (as part of the implementation of from_raw).

  • Although that may look innocent, it is actually pretty powerful tool:

    For instance, a non-null pointer coming from C can, this way, be automatically checked and unwrapped, and the same applies for enumerations having a finite number of valid bit-patterns.

Safety

It must be sound to transmute from a ReprC::CLayout instance when the bit pattern represents a safe instance of Self.

Implementing ReprC

It is generally recommended to avoid manually (and unsafe-ly) implementing the ReprC trait. Instead, the recommended and blessed way is to use the #[derive_ReprC] attribute (when the proc_macros feature is enabled, or the ReprC! macro when it is not) on your #[repr(C)] struct (or your field-less #[repr(<integer>)] enum).

Examples

Simple struct

use ::safer_ffi::prelude::*;

#[derive_ReprC]
#[repr(C)]
struct Instant {
    seconds: u64,
    nanos: u32,
}
  • corresponding to the following C definition:

    typedef struct {
        uint64_t seconds;
        uint32_t nanos;
    } Instant_t;
    

or you can use what the attribute macro expands to, to avoid requiring the proc_macros feature:

use ::safer_ffi::prelude::*;

ReprC! {
    #[repr(C)]
    struct Instant {
        seconds: u64,
        nanos: u32,
    }
}

Field-less enum

use ::safer_ffi::prelude::*;

#[derive_ReprC]
#[repr(u8)]
enum Status {
    Ok = 0,
    Busy,
    NotInTheMood,
    OnStrike,
    OhNo,
}
  • corresponding to the following C definition:

    typedef uint8_t Status_t; enum {
        STATUS_OK = 0,
        STATUS_BUSY,
        STATUS_NOT_IN_THE_MOOD,
        STATUS_ON_STRIKE,
        STATUS_OH_NO,
    }
    

or you can use what the attribute macro expands to, to avoid requiring the proc_macros feature:

use ::safer_ffi::prelude::*;

ReprC! {
    #[repr(u8)]
    enum Status {
        Ok = 0,
        Busy,
        NotInTheMood,
        OnStrike,
        OhNo,
    }
}

Generic struct

use ::safer_ffi::prelude::*;

#[derive_ReprC]
#[repr(C)]
struct Point<Coordinate : ReprC> {
    x: Coordinate,
    y: Coordinate,
}

Each monomorphization leads to its own C definition:

  • Point<i32>

    typedef struct {
        int32_t x;
        int32_t y;
    } Point_int32_t;
    
  • Point<f64>

    typedef struct {
        double x;
        double y;
    } Point_double_t;
    

This is where the attribute macro shines. Indeed, the ReprC! macro has some parsing limitations (for the sake of simplicity and performance) that require unorthodox syntax when generics are involved (see the macro documentation for more info about it):

use ::safer_ffi::prelude::*;

ReprC! {
    #[repr(C)]
    struct Point[Coordinate]
    where {
        Coordinate : ReprC,
    }
    {
        x: Coordinate,
        y: Coordinate,
    }
}

Associated Types

type CLayout: CType

The CType having the same layout as Self.

Loading content...

Required methods

fn is_valid(it: &Self::CLayout) -> bool

Sanity checks that can be performed on an instance of the CType layout.

Such checks are performed when calling from_raw, or equivalently (⚠️ only with debug_assertions enabled ⚠️), from_raw_unchecked.

Implementation-wise, this function is only a "sanity check" step:

  • It is valid (although rather pointless) for this function to always return true, even if the input may be unsafe to transmute to Self, or even be an invalid value of type Self.

  • In the other direction, it is not unsound, although it would be a logic error, to always return false.

  • This is because it is impossible to have a function that for any type is able to tell if a given bit pattern is a safe value of that type.

In practice, if this function returns false, then such result must be trusted, i.e., transmuting such instance to the Self type will, at the very least, break a safety invariant, and it will even most probably break a validity invariant.

On the other hand, if the function returns true, then the result is inconclusive; there is no explicit reason to stop going on, but that doesn't necessarily make it sound.

TL,DR

This function may yield false positives but no false negatives.

Example: Self = &'borrow i32

When Self = &'borrow i32, we know that the backing pointer is necessarily non-null and well-aligned.

This means that bit-patterns such as 0 as *const i32 or 37 as *const i32 are "blatantly unsound" to transmute to a &'borrow i32, and thus <&'borrow i32 as ReprC>::is_valid will return false in such cases.

But if given 4 as *const i32, or if given { let p = &*Box::new(42) as *const i32; p }, then is_valid will return true in both cases, since it doesn't know better.

Example: bool or #[repr(u8)] enum Foo { A, B }

In the case of bool, or in the case of a #[repr(<integer>)] field-less enum, then the valid bit-patterns and the invalid bit-patterns are all known and finite.

In that case, ReprC::is_valid will return a bool that truly represents the validity of the bit-pattern, in both directions

  • i.e., no false positives (validity-wise);

Still, there may be safety invariants involved with custom types, so even then it is unclear.

Loading content...

Implementations on Foreign Types

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

type CLayout = *const T::CLayout

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

type CLayout = *mut T::CLayout

impl ReprC for ()[src]

type CLayout = CVoid

impl<T: ?Sized> ReprC for PhantomData<T>[src]

type CLayout = CVoid

impl ReprC for f32[src]

type CLayout = Self

impl ReprC for f64[src]

type CLayout = Self

impl ReprC for u8[src]

type CLayout = Self

impl ReprC for u16[src]

type CLayout = Self

impl ReprC for u32[src]

type CLayout = Self

impl ReprC for u64[src]

type CLayout = Self

impl ReprC for usize[src]

type CLayout = Self

impl ReprC for i8[src]

type CLayout = Self

impl ReprC for i16[src]

type CLayout = Self

impl ReprC for i32[src]

type CLayout = Self

impl ReprC for i64[src]

type CLayout = Self

impl ReprC for isize[src]

type CLayout = Self

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

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

type CLayout = Option<unsafe extern "C" fn() -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn() -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn() -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn() -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn(_: A1::CLayout) -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn(_: A1::CLayout) -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn(_: A1::CLayout) -> Ret::CLayout>

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

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

type CLayout = Option<unsafe extern "C" fn(_: A1::CLayout) -> Ret::CLayout>

impl<Item: ReprC> ReprC 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 CLayout = [Item::CLayout; 1]

impl<Item: ReprC> ReprC 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 CLayout = [Item::CLayout; 2]

impl ReprC for bool[src]

type CLayout = Bool

impl<T: ReprC> ReprC for NonNull<T>[src]

impl<'a, T: 'a + ReprC> ReprC for &'a T[src]

impl<'a, T: 'a + ReprC> ReprC for &'a mut T[src]

impl<T: ReprC + HasNiche> ReprC for Option<T>[src]

type CLayout = <T as ReprC>::CLayout

impl ReprC for c_void[src]

type CLayout = CVoid

Loading content...

Implementors

impl ReprC for char_p_boxed where
    NonNullOwned<c_char>: ReprC
[src]

type CLayout = <NonNullOwned<c_char> as ReprC>::CLayout

impl ReprC for char_p_raw where
    NonNullRef<c_char>: ReprC
[src]

type CLayout = <NonNullRef<c_char> as ReprC>::CLayout

impl ReprC for String where
    Vec<u8>: ReprC
[src]

type CLayout = <Vec<u8> as ReprC>::CLayout

impl ReprC for str_boxed where
    slice_boxed<u8>: ReprC
[src]

type CLayout = <slice_boxed<u8> as ReprC>::CLayout

impl<'lt> ReprC for char_p_ref<'lt> where
    NonNullRef<c_char>: ReprC
[src]

type CLayout = <NonNullRef<c_char> as ReprC>::CLayout

impl<'lt> ReprC for str_ref<'lt> where
    slice_ref<'lt, u8>: ReprC
[src]

type CLayout = <slice_ref<'lt, u8> as ReprC>::CLayout

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

type CLayout = RefDynFnMut0_Layout<'lt, Ret>

impl<'lt, Ret> ReprC for safer_ffi::closure::borrowed::RefDynFnMut0_Layout<'lt, Ret> where
    NonNull<c_void>: ReprC,
    unsafe extern "C" fn(env_ptr: NonNull<c_void>) -> Ret: ReprC,
    PhantomData<&'lt ()>: ReprC,
    Ret: ReprC,
    Ret: ReprC
[src]

type CLayout = Self

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

type CLayout = RefDynFnMut1_Layout<'lt, Ret, A1>

impl<'lt, Ret, A1> ReprC for safer_ffi::closure::borrowed::RefDynFnMut1_Layout<'lt, Ret, A1> where
    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 CLayout = Self

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

type CLayout = slice_mut_Layout<'lt, T>

impl<'lt, T> ReprC for safer_ffi::slice::slice_mut_Layout<'lt, T> where
    NonNullMut<T>: ReprC,
    usize: ReprC,
    PhantomData<&'lt ()>: ReprC,
    T: ReprC,
    T: 'lt, 
[src]

type CLayout = Self

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

type CLayout = slice_ref_Layout<'lt, T>

impl<'lt, T> ReprC for safer_ffi::slice::slice_ref_Layout<'lt, T> where
    NonNullRef<T>: ReprC,
    usize: ReprC,
    PhantomData<&'lt ()>: ReprC,
    T: ReprC,
    T: 'lt, 
[src]

type CLayout = Self

impl<'out, T: 'out + Sized + ReprC> ReprC for Out<'out, T>[src]

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

type CLayout = ArcDynFn0_Layout<Ret>

impl<Ret> ReprC for safer_ffi::closure::arc::ArcDynFn0_Layout<Ret> where
    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 CLayout = Self

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

impl<Ret> ReprC for safer_ffi::closure::boxed::BoxDynFnMut0_Layout<Ret> where
    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 CLayout = Self

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

type CLayout = ArcDynFn1_Layout<Ret, A1>

impl<Ret, A1> ReprC for safer_ffi::closure::arc::ArcDynFn1_Layout<Ret, A1> where
    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 CLayout = Self

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

type CLayout = BoxDynFnMut1_Layout<Ret, A1>

impl<Ret, A1> ReprC for safer_ffi::closure::boxed::BoxDynFnMut1_Layout<Ret, A1> where
    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 CLayout = Self

impl<T> ReprC for Box<T> where
    NonNullOwned<T>: ReprC
[src]

type CLayout = <NonNullOwned<T> as ReprC>::CLayout

impl<T> ReprC for safer_ffi::slice::slice_boxed<T> where
    NonNullOwned<T>: ReprC,
    <NonNullOwned<T> as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    usize: ReprC,
    <usize as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    T: ReprC
[src]

impl<T> ReprC for safer_ffi::slice::slice_boxed_Layout<T> where
    NonNullOwned<T>: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type CLayout = Self

impl<T> ReprC for safer_ffi::slice::slice_raw<T> where
    NonNull<T>: ReprC,
    <NonNull<T> as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    usize: ReprC,
    <usize as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    T: ReprC
[src]

impl<T> ReprC for safer_ffi::slice::slice_raw_Layout<T> where
    NonNull<T>: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type CLayout = Self

impl<T> ReprC for safer_ffi::vec::Vec<T> where
    NonNullOwned<T>: ReprC,
    <NonNullOwned<T> as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    usize: ReprC,
    <usize as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    usize: ReprC,
    <usize as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    T: ReprC
[src]

type CLayout = Vec_Layout<T>

impl<T> ReprC for safer_ffi::vec::Vec_Layout<T> where
    NonNullOwned<T>: ReprC,
    usize: ReprC,
    usize: ReprC,
    T: ReprC
[src]

type CLayout = Self

impl<T0, T1> ReprC for safer_ffi::tuple::Tuple2<T0, T1> where
    T0: ReprC,
    <T0 as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    T1: ReprC,
    <T1 as ReprC>::CLayout: CType<OPAQUE_KIND = Concrete>,
    T0: ReprC,
    T1: ReprC
[src]

type CLayout = Tuple2_Layout<T0, T1>

impl<T0, T1> ReprC for safer_ffi::tuple::Tuple2_Layout<T0, T1> where
    T0: ReprC,
    T1: ReprC,
    T0: ReprC,
    T1: ReprC
[src]

type CLayout = Self

impl<T: ReprC> ReprC for NonNullMut<T>[src]

impl<T: ReprC> ReprC for NonNullOwned<T>[src]

impl<T: ReprC> ReprC for NonNullRef<T>[src]

Loading content...