use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit};
use crate::bind::{bind, bind_default, Bind, FnBind};
use r3_core::{
hunk::Hunk,
kernel::{cfg::Cfg, traits},
utils::Init,
};
#[const_trait]
pub trait Source<System> {
type Target: 'static;
fn into_unsafe_cell_hunk<C>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, UnsafeCell<MaybeUninit<Self::Target>>>
where
C: ~const traits::CfgBase<System = System>;
}
pub struct DefaultSource<T>(PhantomData<T>);
impl<T> Init for DefaultSource<T> {
const INIT: Self = Self(PhantomData);
}
impl<System, T> const Source<System> for DefaultSource<T>
where
System: traits::KernelBase + traits::KernelStatic,
T: 'static + Default + Send,
{
type Target = T;
fn into_unsafe_cell_hunk<C>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, UnsafeCell<MaybeUninit<Self::Target>>>
where
C: ~const traits::CfgBase<System = System>,
{
TakeBindSource(bind_default(cfg)).into_unsafe_cell_hunk(cfg)
}
}
pub struct NewBindSource<Binder, Func> {
pub binder: Binder,
pub func: Func,
}
impl<System, Binder, Func> const Source<System> for NewBindSource<Binder, Func>
where
System: traits::KernelBase + traits::KernelStatic,
Func: ~const FnBind<Binder>,
Func::Output: Send,
{
type Target = Func::Output;
fn into_unsafe_cell_hunk<C>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, UnsafeCell<MaybeUninit<Self::Target>>>
where
C: ~const traits::CfgBase<System = System>,
{
let Self { binder, func } = self;
TakeBindSource(bind(binder, func).finish(cfg)).into_unsafe_cell_hunk(cfg)
}
}
pub struct TakeBindSource<'pool, System, T>(pub(crate) Bind<'pool, System, T>);
impl<System, T> const Source<System> for TakeBindSource<'_, System, T>
where
System: traits::KernelBase + traits::KernelStatic,
T: 'static + Send,
{
type Target = T;
fn into_unsafe_cell_hunk<C>(
self,
cfg: &mut Cfg<C>,
) -> Hunk<System, UnsafeCell<MaybeUninit<Self::Target>>>
where
C: ~const traits::CfgBase<System = System>,
{
bind((self.0.take_mut(),), |_: &mut _| {})
.unpure()
.finish(cfg);
unsafe { self.0.hunk().transmute::<UnsafeCell<MaybeUninit<T>>>() }
}
}
pub struct HunkSource<System, T>(pub(crate) Hunk<System, UnsafeCell<MaybeUninit<T>>>);
impl<System, T> const Source<System> for HunkSource<System, T>
where
T: 'static,
{
type Target = T;
fn into_unsafe_cell_hunk<C>(
self,
_: &mut Cfg<C>,
) -> Hunk<System, UnsafeCell<MaybeUninit<Self::Target>>>
where
C: ~const traits::CfgBase<System = System>,
{
self.0
}
}
#[macropol::macropol] macro_rules! impl_source_setter {
(
$( #[$($meta:tt)*] )*
impl $DefinerName:ident<$($Param:tt)*
) => {
impl_source_setter! {
@iter
attributes: {{ $( #[$($meta)*] )* }},
definer_name: {{ $DefinerName }},
generics: {{ }},
definer_ty: {{ $DefinerName< }},
param_template: {{ $($Param)* }},
concrete_source_var: {{ $ConcreteSource }},
}
};
(@iter
attributes: {$attributes:tt},
definer_name: {$definer_name:tt},
generics: {$generics:tt},
definer_ty: {{ $( $definer_ty:tt )* }},
param_template: {{> $($rest:tt)* }},
concrete_source_var: {$concrete_source_var:tt},
) => {
$(
compile_error!(concat!("Extra token in input: `$&rest`"));
)*
impl_source_setter! {
@end
attributes: {$attributes},
definer_name: {$definer_name},
generics: {$generics},
definer_ty: {{ $( $definer_ty )* > }},
concrete_source_var: {$concrete_source_var},
}
};
(@iter
attributes: {$attributes:tt},
definer_name: {$definer_name:tt},
generics: {{ $( $generics:tt )* }},
definer_ty: {{ $( $definer_ty:tt )* }},
param_template: {{ #Source $($rest:tt)* }},
concrete_source_var: {{ $( $concrete_source_var:tt )* }},
) => {
impl_source_setter! {
@iter
attributes: {$attributes},
definer_name: {$definer_name},
generics: {{ $( $generics )* T }},
definer_ty: {{ $( $definer_ty )* $( $concrete_source_var )* }},
param_template: {{ $($rest)* }},
concrete_source_var: {{ $( $concrete_source_var )* }},
}
};
(@iter
attributes: {$attributes:tt},
definer_name: {$definer_name:tt},
generics: {{ $( $generics:tt )* }},
definer_ty: {{ $( $definer_ty:tt )* }},
param_template: {{ $any:tt $($rest:tt)* }},
concrete_source_var: { $concrete_source_var:tt },
) => {
impl_source_setter! {
@iter
attributes: {$attributes},
definer_name: {$definer_name},
generics: {{ $( $generics )* $any }},
definer_ty: {{ $( $definer_ty )* $any }},
param_template: {{ $($rest)* }},
concrete_source_var: { $concrete_source_var },
}
};
(@end
attributes: {{
$( #[autowrap($wrap_with:expr, $Wrapper:ident)] )?
$( #[no_autowrap$no_autowrap:tt] )?
}},
definer_name: {{ $definer_name:ident }},
generics: {{ $( $generics:tt )* }},
definer_ty: {{ $( $definer_ty:tt )* }},
concrete_source_var: {{ $( $concrete_source_var:tt )* }},
) => {
mod __pr {
pub use crate::{
sync::source::{Source, NewBindSource, TakeBindSource, HunkSource},
bind::{Bind, fn_bind_map, FnBindMap},
hunk::Hunk,
};
pub use core::{cell::UnsafeCell, mem::MaybeUninit};
}
macro_rules! Definer {
( $( $concrete_source_var )*:ty ) => { $( $definer_ty )* };
}
$(
#[allow(type_alias_bounds)] type MappedFunc<Func, T: 'static> = __pr::FnBindMap<
Func,
impl FnOnce(T) -> $Wrapper<T> + Send + Copy + 'static
>;
type AutoWrapped<T> = $Wrapper<T>;
macro MappedFunc($Func:ty, $T:ty) { MappedFunc<$Func, $T> }
)?
$(
type AutoWrapped<T> = T;
macro MappedFunc($Func:ty, $T:ty) { $Func }
)?
impl<$( $generics )*> Definer!(DefaultSource<AutoWrapped<T>>)
where
T: 'static
{
pub const fn init<Func>(self, func: Func)
-> Definer!(__pr::NewBindSource<(), MappedFunc!(Func, T)>)
where
__pr::NewBindSource<(), MappedFunc!(Func, T)>:
__pr::Source<System, Target = AutoWrapped<T>>,
{
$definer_name {
source: __pr::NewBindSource {
binder: (),
func $( : __pr::fn_bind_map(func, $wrap_with) )?,
},
..self
}
}
pub const fn init_with_bind<Binder, Func>(
self,
binder: Binder,
func: Func,
) -> Definer!(__pr::NewBindSource<Binder, MappedFunc!(Func, T)>)
where
__pr::NewBindSource<Binder, MappedFunc!(Func, T)>:
__pr::Source<System, Target = AutoWrapped<T>>,
{
$definer_name {
source: __pr::NewBindSource {
binder,
func $( : __pr::fn_bind_map(func, $wrap_with) )?,
},
..self
}
}
$(
)?
pub const fn take_bind<'pool>(
self,
bind: __pr::Bind<'pool, System, AutoWrapped<T>>,
) -> Definer!(__pr::TakeBindSource<'pool, System, AutoWrapped<T>>) {
$definer_name {
source: __pr::TakeBindSource(bind),
..self
}
}
$(
)?
pub const unsafe fn wrap_hunk_unchecked<'pool>(
self,
hunk: __pr::Hunk<System, __pr::UnsafeCell<__pr::MaybeUninit<AutoWrapped<T>>>>,
) -> Definer!(__pr::HunkSource<System, AutoWrapped<T>>)
{
$definer_name {
source: __pr::HunkSource(hunk),
..self
}
}
}
};
}