riot_wrappers/auto_init.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
//! Tools for declaring a function that is run during initialization
//!
//! The [`auto_init!`](super::auto_init!) macro is this module's main product.
/// Wrapper around [riot_sys::auto_init_module_t]
///
/// Its main purpose is to make it Sync; its constructor also takes responsibility of fields that
/// may or may not be present in the struct depending on the build configuration.
#[repr(transparent)]
pub struct AutoInitModule(riot_sys::auto_init_module_t);
impl AutoInitModule {
/// Initializer for module auto-initialization
///
/// Do not call this directly: Its result must be placed in a static in a special section in
/// memory, which is handled by the [`auto_init!`](super::auto_init!) macro.
pub const fn new(
init_function: extern "C" fn(),
priority: u16,
name: &'static core::ffi::CStr,
) -> Self {
let result;
#[cfg(marker_config_auto_init_enable_debug)]
{
result = Self(riot_sys::auto_init_module_t {
init: Some(init_function),
prio: priority,
name: name.as_ptr() as _,
});
}
#[cfg(not(marker_config_auto_init_enable_debug))]
{
let _ = priority;
let _ = name;
result = Self(riot_sys::auto_init_module_t {
init: Some(init_function),
});
}
result
}
}
// unsafe: The items do not publicly expose anything, so just referencing them from anywhere does no
// harm. (Actual usage happens through XFA from C).
unsafe impl Sync for AutoInitModule {}
/// Run the function `$func` during auto initialization, with the priority giving the position in
/// the initialization sequence.
///
/// Note that the priority has to be a literal value. Supporting configured priorities would be
/// possible with proc macros, but their complexity would be excessive as long as this is not
/// needed.
#[macro_export]
macro_rules! auto_init {
( $func:ident, $priority:literal ) => {
// Cheating our way around how we can't build identifiers like proc macros can: We're
// referring to a function with a name; there's nothing stopping us from creating a module
// with the same name.
mod $func {
extern "C" fn wrapped_as_extern_c() {
super::$func()
}
#[link_section = concat!(".roxfa.auto_init_xfa.", $priority)]
#[export_name = concat!("auto_init_xfa_", stringify!($func))] // do we need this?
static AUTO_INIT_MODULE: $crate::auto_init::AutoInitModule =
$crate::auto_init::AutoInitModule::new(
wrapped_as_extern_c,
$priority,
// unsafe: Constructing from an identifier which can't have null bytes
unsafe {
core::ffi::CStr::from_bytes_with_nul_unchecked(
concat!(stringify!($func), "\0").as_bytes(),
)
},
);
}
};
}