use std::{mem, ops, pin, ptr};
use dope_core::{
driver::{self, schedule, settings},
io,
};
use o3::base::cell::region;
use super::forward;
use crate::{executor, topology::lending};
#[pin_project::pin_project]
#[repr(transparent)]
pub struct Bound<'app, 'd, H, T> {
#[pin]
pub(super) inner: lending::raw::Pair<'app, 'd, H, T>,
}
impl<'app, 'd, H, T> Bound<'app, 'd, H, T> {
pub(crate) const fn new(head: pin::Pin<&'app mut H>, tail: T) -> Self {
const {
assert!(mem::size_of::<Self>() == mem::size_of::<(pin::Pin<&'app mut H>, T)>());
assert!(mem::align_of::<Self>() == mem::align_of::<(pin::Pin<&'app mut H>, T)>());
assert!(!mem::needs_drop::<Self>());
}
Self {
inner: lending::raw::Pair::new(head, tail),
}
}
pub fn tail(self: pin::Pin<&Self>) -> pin::Pin<&T> {
self.project_ref().inner.tail()
}
}
unsafe impl<'app, 'd, H, T> lending::raw::Project for Bound<'app, 'd, H, T> {
type App = lending::raw::Pair<'app, 'd, H, T>;
fn shared(self: pin::Pin<&Self>) -> pin::Pin<&Self::App> {
self.project_ref().inner
}
fn exclusive(self: pin::Pin<&mut Self>) -> pin::Pin<&mut Self::App> {
self.project().inner
}
}
impl<'app, 'd, H, T> executor::raw::Layout<'d> for Bound<'app, 'd, H, T>
where
H: executor::raw::Layout<'d>,
T: executor::raw::Layout<'d>,
{
type ParkPlan = <lending::raw::Pair<'app, 'd, H, T> as executor::raw::Layout<'d>>::ParkPlan;
}
unsafe impl<'app, 'd, H, T> executor::raw::App<'d> for Bound<'app, 'd, H, T>
where
H: executor::raw::App<'d>,
T: executor::raw::App<'d>,
{
const ROUTES: settings::Routes =
<lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::ROUTES;
const WAKE_ROUTES: settings::Routes =
<lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::WAKE_ROUTES;
const COORDS: usize = <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::COORDS;
fn select_park() -> Option<Self::ParkPlan> {
<lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::select_park()
}
fn prepare_park(
app: pin::Pin<&Self>,
plan: &mut Self::ParkPlan,
) -> Option<executor::raw::Count> {
<lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::prepare_park(
lending::raw::Project::shared(app),
plan,
)
}
unsafe fn park<'call, 'driver, 'turn>(
app: pin::Pin<&'call mut Self>,
plan: &mut Self::ParkPlan,
park: executor::raw::Park<'driver, 'turn, 'd>,
) where
'd: 'driver + 'turn,
{
unsafe { forward::park(app, plan, park) }
}
unsafe fn activate<'call, 'driver, 'turn>(
app: pin::Pin<&'call mut Self>,
activate: executor::raw::Activate<'driver, 'turn, 'd>,
) -> bool
where
'd: 'driver + 'turn,
{
unsafe { forward::activate(app, activate) }
}
fn admit(
app: pin::Pin<&Self>,
needs: &mut settings::claim::Needs,
) -> Result<(), settings::errors::Claim> {
<lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::admit(
lending::raw::Project::shared(app),
needs,
)
}
fn released(released: executor::raw::Released<'_, Self>) -> executor::raw::Released<'_, Self> {
unsafe { released.visit(|app| app.project().inner.project().tail) }
}
fn install<'call, 'owner>(
call: executor::raw::Install<'call, 'owner, 'd, Self>,
) -> executor::raw::Install<'call, 'owner, 'd, Self> {
forward::install(call)
}
fn dispatch<'call, 'driver, 'turn>(
call: executor::raw::Dispatch<'call, 'driver, 'turn, 'd, Self>,
) -> ops::ControlFlow<io::Event<'d>> {
forward::dispatch(call)
}
fn progress(
app: pin::Pin<&Self>,
view: executor::raw::Progress<'_, '_, 'd>,
) -> schedule::Progress<'d> {
<lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::progress(
lending::raw::Project::shared(app),
view,
)
}
fn stopping(
app: pin::Pin<&Self>,
view: executor::raw::Progress<'_, '_, 'd>,
) -> schedule::Progress<'d> {
<lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::stopping(
lending::raw::Project::shared(app),
view,
)
}
fn shutdown<'call, 'turn, 'driver>(
call: executor::raw::Shutdown<'call, 'turn, 'driver, 'd, Self>,
) -> executor::raw::Shutdown<'call, 'turn, 'driver, 'd, Self> {
let (mut app, turn, driver) = call.into_parts();
let tail = app.as_mut().project().inner.project().tail;
let call = executor::raw::Shutdown::new(tail, turn, driver);
let (turn, driver) = forward::shutdown(call).into_drive();
let head = app.as_mut().project().inner.project().head;
let call = executor::raw::Shutdown::new(head, turn, driver);
let (turn, driver) = forward::shutdown(call).into_drive();
executor::raw::Shutdown::new(app, turn, driver)
}
fn finish<'call, 'finish, 'owner, 'epoch>(
call: executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self>,
) -> executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self> {
let (mut app, install, finish) = call.into_parts();
let tail = app.as_mut().project().inner.project().tail;
let call = executor::raw::Finish::new(tail, install, finish);
let (install, finish) =
<lending::raw::Owner<mem::ManuallyDrop<T>, T> as executor::raw::Finishes<'d>>::call(
call,
)
.into_finish();
let mut head = app.as_mut().project().inner.project().head;
let _ = <lending::raw::Borrowed<'_, H> as executor::raw::App<'d>>::released(
executor::raw::Released::new(head.as_mut()),
);
let call = executor::raw::Finish::new(head, install, finish);
let (install, finish) =
<lending::raw::Borrowed<'_, H> as executor::raw::Finishes<'d>>::call(call)
.into_finish();
executor::raw::Finish::new(app, install, finish)
}
}
impl<'parent, 'd, H, T> Bound<'parent, 'd, H, T>
where
H: executor::raw::App<'d>,
T: executor::raw::App<'d>,
{
pub(crate) unsafe fn finish_tail<'call, 'finish, 'owner, 'epoch>(
call: executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self>,
plan: Option<<Self as executor::raw::Layout<'d>>::ParkPlan>,
) -> (
lending::raw::Borrowed<'parent, H>,
Option<<H as executor::raw::Layout<'d>>::ParkPlan>,
) {
let (mut app, install, finish) = call.into_parts();
let tail = app.as_mut().project().inner.project().tail;
let call = executor::raw::Finish::new(tail, install, finish);
let _ = <lending::raw::Owner<mem::ManuallyDrop<T>, T> as executor::raw::Finishes<'d>>::call(
call,
);
let head = app.as_mut().project().inner.project().head;
let head = unsafe { ptr::read(head.get_unchecked_mut()) };
(head, plan.and_then(|plan| plan.3))
}
}
unsafe impl<'d, H, T> executor::raw::Drain<'d> for Bound<'_, 'd, H, T>
where
H: executor::raw::App<'d>,
T: executor::raw::Drain<'d>,
{
fn begin(
self: pin::Pin<&mut Self>,
turn: schedule::Turn<'_, 'd>,
driver: &mut driver::Context<'_, 'd>,
) {
executor::raw::Drain::begin(self.project().inner, turn, driver);
}
fn progress(
self: pin::Pin<&Self>,
region: ®ion::Token<region::Identity<'d>>,
) -> schedule::Progress<'d> {
executor::raw::Drain::progress(self.project_ref().inner, region)
}
fn force(
self: pin::Pin<&mut Self>,
turn: schedule::Turn<'_, 'd>,
driver: &mut driver::Context<'_, 'd>,
) {
executor::raw::Drain::force(self.project().inner, turn, driver);
}
}
const _: () = {
assert!(mem::size_of::<Bound<'_, '_, (), ()>>() == mem::size_of::<&mut ()>());
assert!(mem::align_of::<Bound<'_, '_, (), ()>>() == mem::align_of::<&mut ()>());
assert!(!mem::needs_drop::<Bound<'_, '_, (), ()>>());
};