use core::marker::PhantomData;
use crate::{
kernel::{cfg::CfgBuilder, startup, Port},
utils::ComptimeVec,
};
impl<System: Port> startup::StartupHook<System> {
pub const fn build() -> CfgStartupHookBuilder<System> {
CfgStartupHookBuilder::new()
}
}
#[must_use = "must call `finish()` to complete registration"]
pub struct CfgStartupHookBuilder<System> {
_phantom: PhantomData<System>,
start: Option<fn(usize)>,
param: usize,
priority: i32,
unchecked: bool,
}
impl<System: Port> CfgStartupHookBuilder<System> {
const fn new() -> Self {
Self {
_phantom: PhantomData,
start: None,
param: 0,
priority: 0,
unchecked: false,
}
}
pub const fn start(self, start: fn(usize)) -> Self {
Self {
start: Some(start),
..self
}
}
pub const fn param(self, param: usize) -> Self {
Self { param, ..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(self, cfg: &mut CfgBuilder<System>) -> startup::StartupHook<System> {
let inner = &mut cfg.inner;
if self.priority < 0 && !self.unchecked {
panic!("negative priority is unsafe and should be unlocked by `unchecked`");
}
let order = inner.startup_hooks.len();
inner.startup_hooks.push(CfgBuilderStartupHook {
start: if let Some(x) = self.start {
x
} else {
panic!("`start` is not specified")
},
param: self.param,
priority: self.priority,
order,
});
startup::StartupHook::new()
}
}
#[doc(hidden)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CfgBuilderStartupHook {
start: fn(usize),
param: usize,
priority: i32,
order: usize,
}
pub(super) const fn sort_hooks(startup_hooks: &mut ComptimeVec<CfgBuilderStartupHook>) {
sort_unstable_by!(
startup_hooks.len(),
|i| startup_hooks.get_mut(i),
|x, y| if x.priority != y.priority {
x.priority < y.priority
} else {
x.order < y.order
}
);
}
impl CfgBuilderStartupHook {
pub const fn to_attr(&self) -> startup::StartupHookAttr {
startup::StartupHookAttr {
start: self.start,
param: self.param,
}
}
}