macro_rules! ReprC {
(
$( @[doc = $doc:expr] )?
$(#[doc = $prev_doc:tt])* // support doc comments _before_ `#[repr(C)]`
#[repr(C)]
$(#[$($meta:tt)*])*
$pub:vis
struct $StructName:ident $(
[
$($lt:lifetime ,)*
$($($generics:ident),+ $(,)?)?
]
$(where { $($bounds:tt)* })?
)?
{
$(
$(#[$($field_meta:tt)*])*
$field_pub:vis
$field_name:ident : $field_ty:ty
),+ $(,)?
}
) => { ... };
(
$( @[doc = $doc:expr] )?
$(#[doc = $prev_doc:tt])*
#[repr(transparent)]
$(#[$meta:meta])*
$pub:vis
struct $StructName:ident $(
[$($generics:tt)*] $(
where { $($bounds:tt)* }
)?
)?
(
$(#[$field_meta:meta])*
$field_pub:vis
$field_ty:ty $(,
$($rest:tt)* )?
);
) => { ... };
(
$(#[doc = $prev_doc:tt])*
#[repr($Int:ident)]
$(#[$($meta:tt)*])*
$pub:vis
enum $EnumName:ident {
$(
$($(#[doc = $variant_doc:expr])+)?
// $(#[$variant_meta:meta])*
$Variant:ident $(= $discriminant:expr)?
),+ $(,)?
}
) => { ... };
(
$(#[doc = $prev_doc:tt])*
#[repr(C $(, $Int:ident)?)]
$(#[$meta:meta])*
$pub:vis
enum $EnumName:ident {
$($variants:tt)*
}
) => { ... };
(
$(#[doc = $prev_doc:tt])*
#[
ReprC
::
opaque
$(
( $($c_name:expr)? )
)?
]
$(#[$meta:meta])*
$pub:vis
struct $StructName:ident $(
[
$($lt:lifetime ,)*
$($($generics:ident),+ $(,)?)?
]
$(where { $($bounds:tt)* })?
)?
{ $($opaque:tt)* }
) => { ... };
(@validate_int_repr u8) => { ... };
(@validate_int_repr u16) => { ... };
(@validate_int_repr u32) => { ... };
(@validate_int_repr u64) => { ... };
(@validate_int_repr u128) => { ... };
(@validate_int_repr i8) => { ... };
(@validate_int_repr i16) => { ... };
(@validate_int_repr i32) => { ... };
(@validate_int_repr i64) => { ... };
(@validate_int_repr i128) => { ... };
(@deny_C C) => { ... };
(@deny_C c_int) => { ... };
(@deny_C c_uint) => { ... };
(@deny_C $otherwise:tt) => { ... };
(@first ($($fst:tt)*) $($ignored:tt)*) => { ... };
}
Expand description
Safely implement ReprC
for a #[repr(C)]
struct when all its fields are ReprC
.
Syntax
Note: given that this macro is implemented as a macro_rules!
macro for
the sake of compilation speed, it cannot parse arbitrary generic parameters
and where clauses.
Instead, it expects a special syntax whereby the generic parameters are
written between square brackets, and only introduce lifetime
parameters
and type parameters, with no bounds whatsoever (and a necessary trailing
comma for the lifetime parameters); the bounds must all be added to the
optional following where { <where clauses here> }
(note the necessary
braces):
-
Instead of:
ⓘuse ::safer_ffi::layout::ReprC; ReprC! { #[repr(C)] struct GenericStruct<'lifetime, T : 'lifetime> where T : ReprC, { inner: &'lifetime T, } }
-
You need to write:
use ::safer_ffi::layout::ReprC; ReprC! { #[repr(C)] struct GenericStruct['lifetime, T] where { T : 'lifetime + ReprC, } { inner: &'lifetime T, } }
#[derive_ReprC]
If all this looks cumbersome to you, and if you don’t care about the
compilation-from-scratch time, then it is highly advised you enable
the proc_macros
feature:
[dependencies]
safer-ffi = { version = "...", features = ["proc_macros"] }
and use the #[derive_ReprC]
attribute macro instead,
which will do the rewriting for you.