use super::{raw, raw_cfg, Cfg};
use crate::{
closure::{Closure, IntoClosureConst},
utils::{slice_sort_unstable_by, ComptimeVec, Init, PhantomInvariant},
};
#[doc = include_str!("../common.md")]
pub struct StartupHook<System: raw::KernelBase>(PhantomInvariant<System>);
impl<System: raw::KernelBase> StartupHook<System> {
pub const fn define() -> StartupHookDefiner<System> {
StartupHookDefiner::new()
}
const fn new() -> Self {
Self(Init::INIT)
}
}
#[must_use = "must call `finish()` to complete registration"]
pub struct StartupHookDefiner<System> {
_phantom: PhantomInvariant<System>,
start: Option<Closure>,
priority: i32,
unchecked: bool,
}
impl<System: raw::KernelBase> StartupHookDefiner<System> {
const fn new() -> Self {
Self {
_phantom: Init::INIT,
start: None,
priority: 0,
unchecked: false,
}
}
pub const fn start<C: ~const IntoClosureConst>(self, start: C) -> Self {
Self {
start: Some(start.into_closure_const()),
..self
}
}
pub const fn priority(self, priority: i32) -> Self {
Self { priority, ..self }
}
pub const unsafe fn unchecked(self) -> Self {
Self {
unchecked: true,
..self
}
}
pub const fn finish<C: ~const raw_cfg::CfgBase<System = System>>(
self,
cfg: &mut Cfg<C>,
) -> StartupHook<System> {
if self.priority < 0 && !self.unchecked {
panic!("negative priority is unsafe and should be unlocked by `unchecked`");
}
let startup_hooks = &mut cfg.startup_hooks;
let order = startup_hooks.len();
startup_hooks.push(CfgStartupHook {
start: self.start.expect("`start` is not specified"),
priority: self.priority,
order,
});
StartupHook::new()
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct CfgStartupHook {
start: Closure,
priority: i32,
order: usize,
}
pub(crate) const fn sort_hooks(startup_hooks: &mut ComptimeVec<CfgStartupHook>) {
slice_sort_unstable_by(
startup_hooks.as_mut_slice(),
closure!(|x: &CfgStartupHook, y: &CfgStartupHook| -> bool {
if x.priority != y.priority {
x.priority < y.priority
} else {
x.order < y.order
}
}),
);
}
#[doc(hidden)]
#[derive(Clone, Copy)]
pub struct StartupHookAttr {
pub(super) start: Closure,
}
impl Init for StartupHookAttr {
const INIT: Self = Self {
start: Closure::INIT,
};
}
impl CfgStartupHook {
#[allow(clippy::wrong_self_convention)]
pub const fn to_attr(&self) -> StartupHookAttr {
StartupHookAttr { start: self.start }
}
}