use std::{marker, mem, ops, pin};
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 Owner<S, T> {
#[pin]
stored: S,
app: marker::PhantomData<T>,
}
impl<S, T> Owner<S, T> {
pub(super) const fn new(stored: S) -> Self {
Self {
stored,
app: marker::PhantomData,
}
}
}
unsafe impl<S: lending::raw::Project<App = T>, T> lending::raw::Project for Owner<S, T> {
type App = T;
fn shared(self: pin::Pin<&Self>) -> pin::Pin<&Self::App> {
self.project_ref().stored.shared()
}
fn exclusive(self: pin::Pin<&mut Self>) -> pin::Pin<&mut Self::App> {
self.project().stored.exclusive()
}
}
impl<'d, S, T> executor::raw::Layout<'d> for Owner<S, T>
where
T: executor::raw::Layout<'d>,
{
type ParkPlan = <T as executor::raw::Layout<'d>>::ParkPlan;
}
unsafe impl<'d, S, T> executor::raw::App<'d> for Owner<S, T>
where
S: lending::raw::Project<App = T>,
T: executor::raw::App<'d>,
Self: executor::raw::Finishes<'d, Self>,
{
const ROUTES: settings::Routes = T::ROUTES;
const WAKE_ROUTES: settings::Routes = T::WAKE_ROUTES;
const COORDS: usize = <T as executor::raw::App<'d>>::COORDS;
fn select_park() -> Option<Self::ParkPlan> {
<T as executor::raw::App<'d>>::select_park()
}
fn prepare_park(
app: pin::Pin<&Self>,
plan: &mut Self::ParkPlan,
) -> Option<executor::raw::Count> {
<T as executor::raw::App<'d>>::prepare_park(lending::raw::Project::shared(app), plan)
}
unsafe fn park<'app, 'driver, 'turn>(
app: pin::Pin<&'app 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<'app, 'driver, 'turn>(
app: pin::Pin<&'app 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> {
T::admit(lending::raw::Project::shared(app), needs)
}
fn released(released: executor::raw::Released<'_, Self>) -> executor::raw::Released<'_, Self> {
unsafe { released.visit(lending::raw::Project::exclusive) }
}
fn install<'app, 'owner>(
call: executor::raw::Install<'app, 'owner, 'd, Self>,
) -> executor::raw::Install<'app, 'owner, 'd, Self> {
forward::install(call)
}
fn dispatch<'app, 'driver, 'turn>(
call: executor::raw::Dispatch<'app, 'driver, 'turn, 'd, Self>,
) -> ops::ControlFlow<io::Event<'d>> {
forward::dispatch(call)
}
fn shutdown<'app, 'turn, 'driver>(
call: executor::raw::Shutdown<'app, 'turn, 'driver, 'd, Self>,
) -> executor::raw::Shutdown<'app, 'turn, 'driver, 'd, Self> {
forward::shutdown(call)
}
fn finish<'app, 'finish, 'owner, 'epoch>(
call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
<Self as executor::raw::Finishes<'d>>::call(call)
}
fn progress(
app: pin::Pin<&Self>,
view: executor::raw::Progress<'_, '_, 'd>,
) -> schedule::Progress<'d> {
T::progress(lending::raw::Project::shared(app), view)
}
fn stopping(
app: pin::Pin<&Self>,
view: executor::raw::Progress<'_, '_, 'd>,
) -> schedule::Progress<'d> {
T::stopping(lending::raw::Project::shared(app), view)
}
}
impl<'d, T> executor::raw::Finishes<'d, Self> for lending::raw::Borrowed<'_, T>
where
T: executor::raw::App<'d>,
{
fn call<'app, 'finish, 'owner, 'epoch>(
call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
forward::finish(call)
}
}
impl<'d, T> executor::raw::Finishes<'d, Self> for Owner<mem::ManuallyDrop<T>, T>
where
T: executor::raw::App<'d>,
{
fn call<'app, 'finish, 'owner, 'epoch>(
call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
let (mut app, install, finish) = forward::finish(call).into_parts();
unsafe { mem::ManuallyDrop::drop(app.as_mut().project().stored.get_unchecked_mut()) };
executor::raw::Finish::new(app, install, finish)
}
}
unsafe impl<'d, S, T> executor::raw::Drain<'d> for Owner<S, T>
where
S: lending::raw::Project<App = T>,
T: executor::raw::Drain<'d>,
Self: executor::raw::Finishes<'d, Self>,
{
fn begin(
self: pin::Pin<&mut Self>,
turn: schedule::Turn<'_, 'd>,
driver: &mut driver::Context<'_, 'd>,
) {
executor::raw::Drain::begin(lending::raw::Project::exclusive(self), turn, driver);
}
fn progress(
self: pin::Pin<&Self>,
region: ®ion::Token<region::Identity<'d>>,
) -> schedule::Progress<'d> {
executor::raw::Drain::progress(lending::raw::Project::shared(self), region)
}
fn force(
self: pin::Pin<&mut Self>,
turn: schedule::Turn<'_, 'd>,
driver: &mut driver::Context<'_, 'd>,
) {
executor::raw::Drain::force(lending::raw::Project::exclusive(self), turn, driver);
}
}