Trait safer_ffi::layout::LegacyCType
source · [−]pub unsafe trait LegacyCType: Sized + Copy + CType {
type OPAQUE_KIND: T;
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result;
fn c_define_self(definer: &mut dyn Definer) -> Result<()>;
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result;
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>;
fn c_short_name() -> ImplDisplay<Self> { ... }
fn c_var(var_name: &str) -> ImplDisplay<'_, Self> { ... }
fn legacy_csharp_marshaler() -> Option<String> { ... }
fn csharp_ty() -> String { ... }
fn csharp_var(var_name: &str) -> String { ... }
}
Expand description
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 thesafer_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.
-
and recursively, a non-zero-sized
#[repr(C)]
struct ofCType
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.
- the
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 bool
s.
For such types, see the ReprC
trait.
Required Associated Types
type OPAQUE_KIND: T
Required Methods
sourcefn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
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:
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:
CType! {
#[repr(C)]
struct Foo { /* fields */ }
}
will have Foo
as its short_name
.
A generic struct such as:
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
.
sourcefn c_define_self(definer: &mut dyn Definer) -> Result<()>
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 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).
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 }
#[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"),
)
})
}
// ...
}
sourcefn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
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 name may need to be inserted in the middle of the types, such as 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
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>
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]
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.
}
sourcefn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
Extra typedef code (e.g. [LayoutKind.Sequential] struct ...
)
Provided Methods
sourcefn c_short_name() -> ImplDisplay<Self>
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
]()
.
sourcefn c_var(var_name: &str) -> ImplDisplay<'_, Self>
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
]()
.
sourcefn legacy_csharp_marshaler() -> Option<String>
fn legacy_csharp_marshaler() -> Option<String>
Optional marshaler attached to the type (e.g.,
[MarshalAs(UnmanagedType.FunctionPtr)]
)
sourcefn csharp_var(var_name: &str) -> String
fn csharp_var(var_name: &str) -> String
Convenience function for formatting {ty} {var}
in CSharp.
Implementations on Foreign Types
sourceimpl<T: CType> LegacyCType for *const T
impl<T: CType> LegacyCType for *const T
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl<T: CType> LegacyCType for *mut T
impl<T: CType> LegacyCType for *mut T
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for f32
impl LegacyCType for f32
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn c_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for f64
impl LegacyCType for f64
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn c_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for u8
impl LegacyCType for u8
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for u16
impl LegacyCType for u16
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for u32
impl LegacyCType for u32
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for u64
impl LegacyCType for u64
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for usize
impl LegacyCType for usize
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for i8
impl LegacyCType for i8
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for i16
impl LegacyCType for i16
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for i32
impl LegacyCType for i32
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for i64
impl LegacyCType for i64
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl LegacyCType for isize
impl LegacyCType for isize
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(_: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
type OPAQUE_KIND = Concrete
sourceimpl<Ret: CType> LegacyCType for Option<unsafe extern "C" fn() -> Ret>
impl<Ret: CType> LegacyCType for Option<unsafe extern "C" fn() -> Ret>
Simplified for lighter documentation, but the actual impls include up to 9 function parameters.
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
fn legacy_csharp_marshaler() -> Option<String>
type OPAQUE_KIND = Concrete
sourceimpl<Ret: CType, A2: CType> LegacyCType for Option<unsafe extern "C" fn(_: A2) -> Ret>
impl<Ret: CType, A2: CType> LegacyCType for Option<unsafe extern "C" fn(_: A2) -> Ret>
Simplified for lighter documentation, but the actual impls include up to 9 function parameters.
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
fn legacy_csharp_marshaler() -> Option<String>
type OPAQUE_KIND = Concrete
sourceimpl<Ret: CType, A1: CType, A2: CType> LegacyCType for Option<unsafe extern "C" fn(_: A1, _: A2) -> Ret>
impl<Ret: CType, A1: CType, A2: CType> LegacyCType for Option<unsafe extern "C" fn(_: A1, _: A2) -> Ret>
Simplified for lighter documentation, but the actual impls include up to 9 function parameters.
fn c_short_name_fmt(fmt: &mut Formatter<'_>) -> Result
fn c_define_self(definer: &mut dyn Definer) -> Result<()>
fn c_var_fmt(fmt: &mut Formatter<'_>, var_name: &str) -> Result
fn csharp_define_self(definer: &mut dyn Definer) -> Result<()>
fn csharp_ty() -> String
fn legacy_csharp_marshaler() -> Option<String>
type OPAQUE_KIND = Concrete
sourceimpl<Item: CType> LegacyCType for [Item; 1]
impl<Item: CType> LegacyCType for [Item; 1]
Simplified for lighter documentation, but the actual impls
range from 1
up to 32
, plus a bunch of significant
lengths up to 1024
.
sourceimpl<Item: CType> LegacyCType for [Item; 2]
impl<Item: CType> LegacyCType for [Item; 2]
Simplified for lighter documentation, but the actual impls
range from 1
up to 32
, plus a bunch of significant
lengths up to 1024
.