use core::{
fmt,
marker::PhantomData,
mem,
ops::Deref,
ptr::{slice_from_raw_parts, slice_from_raw_parts_mut},
};
use crate::{
kernel::{self, cfg::CfgBuilder, Kernel, Port, StartupHook},
utils::{Init, ZeroInit},
};
pub const INIT_HOOK_PRIORITY: i32 = -0x7000_0000;
#[doc(include = "./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: Kernel, T: ?Sized> Hunk<System, T> {
pub const fn build() -> CfgHunkBuilder<System, T, DefaultInitTag> {
CfgHunkBuilder {
_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 CfgHunkBuilder<System, T: ?Sized, InitTag> {
_phantom: PhantomData<(System, InitTag, T)>,
len: usize,
align: usize,
}
impl<System: Kernel, T: ?Sized, InitTag> CfgHunkBuilder<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) -> CfgHunkBuilder<System, T, ZeroInitTag>
where
T: ZeroInit,
{
unsafe { self.zeroed_unchecked() }
}
pub const unsafe fn zeroed_unchecked(self) -> CfgHunkBuilder<System, T, ZeroInitTag> {
CfgHunkBuilder {
_phantom: PhantomData,
len: self.len,
align: self.align,
}
}
}
impl<System: Kernel, T, InitTag: HunkIniter<T>> CfgHunkBuilder<System, T, InitTag> {
pub const fn finish(self, cfg: &mut CfgBuilder<System>) -> Hunk<System, T> {
let untyped_hunk = kernel::Hunk::<System>::build()
.len(mem::size_of::<T>())
.align(max(mem::align_of::<T>(), 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::build()
.priority(INIT_HOOK_PRIORITY)
.start(|start| {
let untyped_hunk = kernel::Hunk::<System>::from_offset(start).as_ptr();
InitTag::init(&mut *(untyped_hunk as *mut mem::MaybeUninit<T>));
})
.unchecked()
.param(start)
.finish(cfg);
}
}
Hunk {
offset: start as _,
_phantom: PhantomData,
}
}
}
impl<System: Port, T, InitTag: HunkIniter<T>> CfgHunkBuilder<System, [T], InitTag> {
pub const fn finish(self, cfg: &mut CfgBuilder<System>) -> Hunk<System, [T]> {
assert!(self.align.is_power_of_two(), "`align` is not power of two");
let untyped_hunk = kernel::Hunk::<System>::build()
.len(mem::size_of::<T>() * self.len)
.align(max(mem::align_of::<T>(), 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, T> Init for Hunk<System, [T]> {
const INIT: Self = Self {
offset: slice_from_raw_parts_mut(core::ptr::null_mut(), 0),
_phantom: PhantomData,
};
}
impl<System: Kernel, 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,
}
}
}
impl<System: Kernel, T: ?Sized> Hunk<System, T> {
#[inline]
pub fn untyped_hunk(this: Self) -> kernel::Hunk<System> {
kernel::Hunk::from_offset(this.offset as *const u8 as usize)
}
#[inline]
pub fn as_ptr(this: Self) -> *const T {
this.offset.set_ptr_value(Self::untyped_hunk(this).as_ptr())
}
#[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]
pub unsafe fn as_bytes(this: Self) -> &'static [u8] {
unsafe { &*Self::as_bytes_ptr(this) }
}
}
impl<System: Kernel, T: ?Sized> AsRef<T> for Hunk<System, T> {
fn as_ref(&self) -> &T {
unsafe { &*Self::as_ptr(*self) }
}
}
impl<System: Kernel, T: ?Sized> Deref for Hunk<System, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
const fn max(x: usize, y: usize) -> usize {
if x > y {
x
} else {
y
}
}