Skip to main content

dope_runtime/topology/lending/raw/
owner.rs

1use std::{marker, mem, ops, pin};
2
3use dope_core::{
4    driver::{self, schedule, settings},
5    io,
6};
7use o3::base::cell::region;
8
9use super::forward;
10use crate::{executor, topology::lending};
11
12#[pin_project::pin_project]
13#[repr(transparent)]
14pub struct Owner<S, T> {
15    #[pin]
16    stored: S,
17    app: marker::PhantomData<T>,
18}
19
20impl<S, T> Owner<S, T> {
21    pub(super) const fn new(stored: S) -> Self {
22        Self {
23            stored,
24            app: marker::PhantomData,
25        }
26    }
27}
28
29// SAFETY: the pinned stored projection remains unchanged for the entire lifecycle.
30unsafe impl<S: lending::raw::Project<App = T>, T> lending::raw::Project for Owner<S, T> {
31    type App = T;
32
33    fn shared(self: pin::Pin<&Self>) -> pin::Pin<&Self::App> {
34        self.project_ref().stored.shared()
35    }
36
37    fn exclusive(self: pin::Pin<&mut Self>) -> pin::Pin<&mut Self::App> {
38        self.project().stored.exclusive()
39    }
40}
41
42impl<'d, S, T> executor::raw::Layout<'d> for Owner<S, T>
43where
44    T: executor::raw::Layout<'d>,
45{
46    type ParkPlan = <T as executor::raw::Layout<'d>>::ParkPlan;
47}
48
49// SAFETY: lifecycle traversal retains one exact pinned application. Its storage
50// is released once after final traversal, before its enclosing owner is finished.
51unsafe impl<'d, S, T> executor::raw::App<'d> for Owner<S, T>
52where
53    S: lending::raw::Project<App = T>,
54    T: executor::raw::App<'d>,
55    Self: executor::raw::Finishes<'d, Self>,
56{
57    const ROUTES: settings::Routes = T::ROUTES;
58    const WAKE_ROUTES: settings::Routes = T::WAKE_ROUTES;
59    const COORDS: usize = <T as executor::raw::App<'d>>::COORDS;
60
61    fn select_park() -> Option<Self::ParkPlan> {
62        <T as executor::raw::App<'d>>::select_park()
63    }
64
65    fn prepare_park(
66        app: pin::Pin<&Self>,
67        plan: &mut Self::ParkPlan,
68    ) -> Option<executor::raw::Count> {
69        <T as executor::raw::App<'d>>::prepare_park(lending::raw::Project::shared(app), plan)
70    }
71
72    unsafe fn park<'app, 'driver, 'turn>(
73        app: pin::Pin<&'app mut Self>,
74        plan: &mut Self::ParkPlan,
75        park: executor::raw::Park<'driver, 'turn, 'd>,
76    ) where
77        'd: 'driver + 'turn,
78    {
79        // SAFETY: this owner preserves the same prepared plan and pinned projection.
80        unsafe { forward::park(app, plan, park) }
81    }
82
83    unsafe fn activate<'app, 'driver, 'turn>(
84        app: pin::Pin<&'app mut Self>,
85        activate: executor::raw::Activate<'driver, 'turn, 'd>,
86    ) -> bool
87    where
88        'd: 'driver + 'turn,
89    {
90        // SAFETY: this owner retains the installed application and its wake routes.
91        unsafe { forward::activate(app, activate) }
92    }
93
94    fn admit(
95        app: pin::Pin<&Self>,
96        needs: &mut settings::claim::Needs,
97    ) -> Result<(), settings::errors::Claim> {
98        T::admit(lending::raw::Project::shared(app), needs)
99    }
100
101    fn released(released: executor::raw::Released<'_, Self>) -> executor::raw::Released<'_, Self> {
102        // SAFETY: this wrapper retains the exact original pinned application.
103        unsafe { released.visit(lending::raw::Project::exclusive) }
104    }
105
106    fn install<'app, 'owner>(
107        call: executor::raw::Install<'app, 'owner, 'd, Self>,
108    ) -> executor::raw::Install<'app, 'owner, 'd, Self> {
109        forward::install(call)
110    }
111
112    fn dispatch<'app, 'driver, 'turn>(
113        call: executor::raw::Dispatch<'app, 'driver, 'turn, 'd, Self>,
114    ) -> ops::ControlFlow<io::Event<'d>> {
115        forward::dispatch(call)
116    }
117
118    fn shutdown<'app, 'turn, 'driver>(
119        call: executor::raw::Shutdown<'app, 'turn, 'driver, 'd, Self>,
120    ) -> executor::raw::Shutdown<'app, 'turn, 'driver, 'd, Self> {
121        forward::shutdown(call)
122    }
123
124    fn finish<'app, 'finish, 'owner, 'epoch>(
125        call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
126    ) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
127        <Self as executor::raw::Finishes<'d>>::call(call)
128    }
129
130    fn progress(
131        app: pin::Pin<&Self>,
132        view: executor::raw::Progress<'_, '_, 'd>,
133    ) -> schedule::Progress<'d> {
134        T::progress(lending::raw::Project::shared(app), view)
135    }
136
137    fn stopping(
138        app: pin::Pin<&Self>,
139        view: executor::raw::Progress<'_, '_, 'd>,
140    ) -> schedule::Progress<'d> {
141        T::stopping(lending::raw::Project::shared(app), view)
142    }
143}
144
145impl<'d, T> executor::raw::Finishes<'d, Self> for lending::raw::Borrowed<'_, T>
146where
147    T: executor::raw::App<'d>,
148{
149    fn call<'app, 'finish, 'owner, 'epoch>(
150        call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
151    ) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
152        forward::finish(call)
153    }
154}
155
156impl<'d, T> executor::raw::Finishes<'d, Self> for Owner<mem::ManuallyDrop<T>, T>
157where
158    T: executor::raw::App<'d>,
159{
160    fn call<'app, 'finish, 'owner, 'epoch>(
161        call: executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self>,
162    ) -> executor::raw::Finish<'app, 'finish, 'owner, 'epoch, 'd, Self> {
163        let (mut app, install, finish) = forward::finish(call).into_parts();
164        // SAFETY: final traversal completed and this private lifecycle wrapper
165        // is never projected again before its enclosing application is destroyed.
166        unsafe { mem::ManuallyDrop::drop(app.as_mut().project().stored.get_unchecked_mut()) };
167        executor::raw::Finish::new(app, install, finish)
168    }
169}
170
171// SAFETY: every drain call projects the same pinned application; its Drain
172// contract preserves the admitted owners and route claims.
173unsafe impl<'d, S, T> executor::raw::Drain<'d> for Owner<S, T>
174where
175    S: lending::raw::Project<App = T>,
176    T: executor::raw::Drain<'d>,
177    Self: executor::raw::Finishes<'d, Self>,
178{
179    fn begin(
180        self: pin::Pin<&mut Self>,
181        turn: schedule::Turn<'_, 'd>,
182        driver: &mut driver::Context<'_, 'd>,
183    ) {
184        executor::raw::Drain::begin(lending::raw::Project::exclusive(self), turn, driver);
185    }
186
187    fn progress(
188        self: pin::Pin<&Self>,
189        region: &region::Token<region::Identity<'d>>,
190    ) -> schedule::Progress<'d> {
191        executor::raw::Drain::progress(lending::raw::Project::shared(self), region)
192    }
193
194    fn force(
195        self: pin::Pin<&mut Self>,
196        turn: schedule::Turn<'_, 'd>,
197        driver: &mut driver::Context<'_, 'd>,
198    ) {
199        executor::raw::Drain::force(lending::raw::Project::exclusive(self), turn, driver);
200    }
201}