use core::{
fmt,
marker::PhantomData,
mem,
ops::Deref,
ptr::{slice_from_raw_parts, slice_from_raw_parts_mut},
};
use crate::{
kernel::{self, cfg, hunk, raw, raw_cfg, Cfg, StartupHook},
utils::{Init, ZeroInit},
};
pub const INIT_HOOK_PRIORITY: i32 = -0x7000_0000;
#[doc = include_str!("./common.md")]
pub struct Hunk<System, T: ?Sized> {
offset: *const T,
_phantom: PhantomData<System>,
}
unsafe impl<System, T: ?Sized + Send> Send for Hunk<System, T> {}
unsafe impl<System, T: ?Sized + Sync> Sync for Hunk<System, T> {}
impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized> Hunk<System, T> {
pub const fn define() -> HunkDefiner<System, T, DefaultInitTag> {
HunkDefiner {
_phantom: PhantomData,
len: 1,
align: 1,
}
}
}
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct DefaultInitTag;
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct ZeroInitTag;
pub trait HunkIniter<T> {
const NEEDS_INIT: bool;
fn init(dest: &mut mem::MaybeUninit<T>);
}
impl<T: Init> HunkIniter<T> for DefaultInitTag {
const NEEDS_INIT: bool = true;
fn init(dest: &mut mem::MaybeUninit<T>) {
*dest = mem::MaybeUninit::new(T::INIT);
}
}
impl<T> HunkIniter<T> for ZeroInitTag {
const NEEDS_INIT: bool = false;
fn init(_: &mut mem::MaybeUninit<T>) {
}
}
#[must_use = "must call `finish()` to complete registration"]
pub struct HunkDefiner<System, T: ?Sized, InitTag> {
_phantom: PhantomData<(System, InitTag, T)>,
len: usize,
align: usize,
}
impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized, InitTag>
HunkDefiner<System, T, InitTag>
{
pub const fn len(self, len: usize) -> Self {
Self { len, ..self }
}
pub const fn align(self, align: usize) -> Self {
Self { align, ..self }
}
pub const fn zeroed(self) -> HunkDefiner<System, T, ZeroInitTag>
where
T: ZeroInit,
{
unsafe { self.zeroed_unchecked() }
}
pub const unsafe fn zeroed_unchecked(self) -> HunkDefiner<System, T, ZeroInitTag> {
HunkDefiner {
_phantom: PhantomData,
len: self.len,
align: self.align,
}
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T, InitTag: HunkIniter<T>>
HunkDefiner<System, T, InitTag>
{
pub const fn finish<C: ~const raw_cfg::CfgBase<System = System>>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, T> {
let untyped_hunk = kernel::Hunk::<System>::define()
.len(mem::size_of::<T>())
.align(mem::align_of::<T>().max(self.align))
.finish(cfg);
assert!(self.len == 1, "Non-array hunk must have `len` of `1`");
let start = untyped_hunk.offset();
if InitTag::NEEDS_INIT {
unsafe {
StartupHook::define()
.priority(INIT_HOOK_PRIORITY)
.start((start, |start| {
let untyped_hunk = kernel::Hunk::<System>::from_offset(start).as_ptr();
InitTag::init(&mut *(untyped_hunk as *mut mem::MaybeUninit<T>));
}))
.unchecked()
.finish(cfg);
}
}
Hunk {
offset: start as _,
_phantom: PhantomData,
}
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T, InitTag: HunkIniter<T>>
HunkDefiner<System, [T], InitTag>
{
pub const fn finish<C: ~const raw_cfg::CfgBase<System = System>>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, [T]> {
assert!(self.align.is_power_of_two(), "`align` is not power of two");
let untyped_hunk = kernel::Hunk::<System>::define()
.len(mem::size_of::<T>() * self.len)
.align(mem::align_of::<T>().max(self.align))
.finish(cfg);
let start = untyped_hunk.offset();
if InitTag::NEEDS_INIT {
todo!();
}
Hunk {
offset: slice_from_raw_parts_mut(start as _, self.len),
_phantom: PhantomData,
}
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T> Init for Hunk<System, [T]> {
#[allow(clippy::invalid_null_ptr_usage)]
const INIT: Self = Self {
offset: slice_from_raw_parts_mut(core::ptr::null_mut(), 0),
_phantom: PhantomData,
};
}
impl<System: raw::KernelBase + cfg::KernelStatic, T: fmt::Debug + ?Sized> fmt::Debug
for Hunk<System, T>
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("Hunk")
.field(&Self::as_ptr(*self))
.field(&&**self)
.finish()
}
}
impl<System, T: ?Sized> Clone for Hunk<System, T> {
fn clone(&self) -> Self {
*self
}
}
impl<System, T: ?Sized> Copy for Hunk<System, T> {}
impl<System, T: ?Sized> Hunk<System, T> {
pub const unsafe fn transmute<U>(self) -> Hunk<System, U> {
Hunk {
offset: self.offset.cast(),
_phantom: PhantomData,
}
}
pub const unsafe fn wrapping_offset(self, count: isize) -> Self
where
T: Sized,
{
Hunk {
offset: self.offset.wrapping_offset(count),
_phantom: PhantomData,
}
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized> Hunk<System, T> {
#[inline]
pub fn untyped_hunk(this: Self) -> kernel::Hunk<System> {
hunk::Hunk::from_offset(this.offset as *const u8 as usize)
}
#[inline]
pub fn as_ptr(this: Self) -> *const T {
(Self::untyped_hunk(this).as_ptr() as *const u8).with_metadata_of(this.offset)
}
#[inline]
pub fn as_bytes_ptr(this: Self) -> *const [u8] {
slice_from_raw_parts(Self::untyped_hunk(this).as_ptr(), mem::size_of_val(&*this))
}
#[inline]
#[allow(clippy::should_implement_trait)]
pub fn as_ref<'a>(this: Self) -> &'a T
where
T: 'a,
{
unsafe { &*Self::as_ptr(this) }
}
#[inline]
pub unsafe fn as_bytes(this: Self) -> &'static [u8] {
unsafe { &*Self::as_bytes_ptr(this) }
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized> AsRef<T> for Hunk<System, T> {
#[inline]
fn as_ref(&self) -> &T {
unsafe { &*Self::as_ptr(*self) }
}
}
impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized> Deref for Hunk<System, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
unsafe impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized> stable_deref_trait::StableDeref
for Hunk<System, T>
{
}
unsafe impl<System: raw::KernelBase + cfg::KernelStatic, T: ?Sized>
stable_deref_trait::CloneStableDeref for Hunk<System, T>
{
}