Skip to main content

dope_runtime/topology/lending/raw/
bound.rs

1use std::{mem, ops, pin, ptr};
2
3use dope_core::{
4    driver::{retained, schedule, settings},
5    io,
6};
7use o3::base::cell::region;
8
9use super::forward;
10use crate::{executor, topology::lending};
11
12/// A dependent application retained by its pinned provider owner.
13#[pin_project::pin_project]
14#[repr(transparent)]
15pub struct Bound<'app, 'd, H, T> {
16    #[pin]
17    pub(super) inner: lending::raw::Pair<'app, 'd, H, T>,
18}
19
20impl<'app, 'd, H, T> Bound<'app, 'd, H, T> {
21    pub(crate) const fn new(head: pin::Pin<&'app mut H>, tail: T) -> Self {
22        const {
23            assert!(mem::size_of::<Self>() == mem::size_of::<(pin::Pin<&'app mut H>, T)>());
24            assert!(mem::align_of::<Self>() == mem::align_of::<(pin::Pin<&'app mut H>, T)>());
25            assert!(!mem::needs_drop::<Self>());
26        }
27        Self {
28            inner: lending::raw::Pair::new(head, tail),
29        }
30    }
31
32    pub fn tail(self: pin::Pin<&Self>) -> pin::Pin<&T> {
33        self.project_ref().inner.tail()
34    }
35}
36
37// SAFETY: Bound retains this exact pinned Pair for its complete lifecycle.
38unsafe impl<'app, 'd, H, T> lending::raw::Project for Bound<'app, 'd, H, T> {
39    type App = lending::raw::Pair<'app, 'd, H, T>;
40
41    fn shared(self: pin::Pin<&Self>) -> pin::Pin<&Self::App> {
42        self.project_ref().inner
43    }
44
45    fn exclusive(self: pin::Pin<&mut Self>) -> pin::Pin<&mut Self::App> {
46        self.project().inner
47    }
48}
49
50impl<'app, 'd, H, T> executor::raw::Layout<'d> for Bound<'app, 'd, H, T>
51where
52    H: executor::raw::Layout<'d>,
53    T: executor::raw::Layout<'d>,
54{
55    type ParkPlan = <lending::raw::Pair<'app, 'd, H, T> as executor::raw::Layout<'d>>::ParkPlan;
56}
57
58// SAFETY: one exclusive execution owns both projected applications through
59// finish. Stop preserves borrowed storage. Finish destroys the dependent tail
60// before the provider's destructive traversal, with no subsequent tail access.
61unsafe impl<'app, 'd, H, T> executor::raw::App<'d> for Bound<'app, 'd, H, T>
62where
63    H: executor::raw::App<'d>,
64    T: executor::raw::App<'d>,
65{
66    const ROUTES: settings::Routes =
67        <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::ROUTES;
68    const WAKE_ROUTES: settings::Routes =
69        <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::WAKE_ROUTES;
70    const COORDS: usize = <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::COORDS;
71
72    fn select_park() -> Option<Self::ParkPlan> {
73        <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::select_park()
74    }
75
76    fn prepare_park(
77        app: pin::Pin<&Self>,
78        plan: &mut Self::ParkPlan,
79    ) -> Option<executor::raw::Count> {
80        <lending::raw::Pair<'app, 'd, H, T> as executor::raw::App<'d>>::prepare_park(
81            lending::raw::Project::shared(app),
82            plan,
83        )
84    }
85
86    unsafe fn park<'call, 'driver, 'turn, 'root>(
87        app: pin::Pin<&'call mut Self>,
88        plan: &mut Self::ParkPlan,
89        park: executor::raw::Park<'driver, 'turn, 'root, 'd>,
90    ) where
91        'd: 'driver + 'turn + 'root,
92    {
93        // SAFETY: this bound retains the same prepared plan and pinned pair.
94        unsafe { forward::park(app, plan, park) }
95    }
96
97    unsafe fn activate<'call, 'driver, 'turn, 'root>(
98        app: pin::Pin<&'call mut Self>,
99        activate: executor::raw::Activate<'driver, 'turn, 'root, 'd>,
100    ) -> bool
101    where
102        'd: 'driver + 'turn + 'root,
103    {
104        // SAFETY: this bound retains the installed pair and its wake routes.
105        unsafe { forward::activate(app, activate) }
106    }
107
108    fn admit(
109        app: pin::Pin<&Self>,
110        needs: &mut settings::claim::Needs,
111    ) -> Result<(), settings::errors::Claim> {
112        <lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::admit(
113            lending::raw::Project::shared(app),
114            needs,
115        )
116    }
117
118    fn released(released: executor::raw::Released<'_, Self>) -> executor::raw::Released<'_, Self> {
119        // SAFETY: only the owned tail has ended external client access. Its
120        // provider remains borrowed until the tail and all construction state drop.
121        unsafe { released.visit(|app| app.project().inner.project().tail) }
122    }
123
124    fn install<'call, 'owner>(
125        call: executor::raw::Install<'call, 'owner, 'd, Self>,
126    ) -> executor::raw::Install<'call, 'owner, 'd, Self> {
127        forward::install(call)
128    }
129
130    fn dispatch<'call, 'driver, 'turn, 'root>(
131        call: executor::raw::Dispatch<'call, 'driver, 'turn, 'root, 'd, Self>,
132    ) -> ops::ControlFlow<io::Event<'d>>
133    where
134        'd: 'root,
135        Self: 'root,
136    {
137        forward::dispatch(call)
138    }
139
140    fn progress(
141        app: pin::Pin<&Self>,
142        view: executor::raw::Progress<'_, '_, 'd>,
143    ) -> schedule::Progress<'d> {
144        <lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::progress(
145            lending::raw::Project::shared(app),
146            view,
147        )
148    }
149
150    fn stopping(
151        app: pin::Pin<&Self>,
152        view: executor::raw::Progress<'_, '_, 'd>,
153    ) -> schedule::Progress<'d> {
154        <lending::raw::Pair<'_, 'd, H, T> as executor::raw::App<'d>>::stopping(
155            lending::raw::Project::shared(app),
156            view,
157        )
158    }
159
160    fn shutdown<'call, 'turn, 'driver, 'owner>(
161        call: executor::raw::Shutdown<'call, 'turn, 'driver, 'owner, 'd, Self>,
162    ) -> executor::raw::Shutdown<'call, 'turn, 'driver, 'owner, 'd, Self>
163    where
164        'd: 'owner,
165    {
166        let (mut app, turn, driver) = call.into_parts();
167        let tail = app.as_mut().project().inner.project().tail;
168        let call = executor::raw::Shutdown::new(tail, turn, driver);
169        let (turn, driver) = forward::shutdown(call).into_drive();
170        let head = app.as_mut().project().inner.project().head;
171        let call = executor::raw::Shutdown::new(head, turn, driver);
172        let (turn, driver) = forward::shutdown(call).into_drive();
173        executor::raw::Shutdown::new(app, turn, driver)
174    }
175
176    fn finish<'call, 'finish, 'owner, 'epoch>(
177        call: executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self>,
178    ) -> executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self> {
179        let (mut app, install, finish) = call.into_parts();
180        let tail = app.as_mut().project().inner.project().tail;
181        let call = executor::raw::Finish::new(tail, install, finish);
182        let (install, finish) =
183            <lending::raw::Owner<mem::ManuallyDrop<T>, T> as executor::raw::Finishes<'d>>::call(
184                call,
185            )
186            .into_finish();
187        let mut head = app.as_mut().project().inner.project().head;
188        let _ = <lending::raw::Borrowed<'_, H> as executor::raw::App<'d>>::released(
189            executor::raw::Released::new(head.as_mut()),
190        );
191        let call = executor::raw::Finish::new(head, install, finish);
192        let (install, finish) =
193            <lending::raw::Borrowed<'_, H> as executor::raw::Finishes<'d>>::call(call)
194                .into_finish();
195        executor::raw::Finish::new(app, install, finish)
196    }
197}
198
199impl<'parent, 'd, H, T> Bound<'parent, 'd, H, T>
200where
201    H: executor::raw::App<'d>,
202    T: executor::raw::App<'d>,
203{
204    /// # Safety
205    /// Consume this exact native-quiesced owner; never project or finish its backing again.
206    pub(crate) unsafe fn finish_tail<'call, 'finish, 'owner, 'epoch>(
207        call: executor::raw::Finish<'call, 'finish, 'owner, 'epoch, 'd, Self>,
208        plan: Option<<Self as executor::raw::Layout<'d>>::ParkPlan>,
209    ) -> (
210        lending::raw::Borrowed<'parent, H>,
211        Option<<H as executor::raw::Layout<'d>>::ParkPlan>,
212    ) {
213        let (mut app, install, finish) = call.into_parts();
214        let tail = app.as_mut().project().inner.project().tail;
215        let call = executor::raw::Finish::new(tail, install, finish);
216        let _ = <lending::raw::Owner<mem::ManuallyDrop<T>, T> as executor::raw::Finishes<'d>>::call(
217            call,
218        );
219        let head = app.as_mut().project().inner.project().head;
220        // SAFETY: the consumed owner makes its old backing inaccessible. Moving
221        // this Pin handle preserves the actual provider's address and full loan.
222        let head = unsafe { ptr::read(head.get_unchecked_mut()) };
223        (head, plan.and_then(|plan| plan.3))
224    }
225}
226
227// SAFETY: drain forwards through the same pinned Pair; its designated tail
228// preserves every admitted owner while the borrowed provider stays installed.
229unsafe impl<'d, H, T> executor::raw::Drain<'d> for Bound<'_, 'd, H, T>
230where
231    H: executor::raw::App<'d>,
232    T: executor::raw::Drain<'d>,
233{
234    fn begin(
235        self: pin::Pin<&mut Self>,
236        turn: schedule::Turn<'_, 'd>,
237        driver: &mut retained::Context<'_, '_, 'd>,
238    ) {
239        executor::raw::Drain::begin(self.project().inner, turn, driver);
240    }
241
242    fn progress(
243        self: pin::Pin<&Self>,
244        region: &region::Token<region::Identity<'d>>,
245    ) -> schedule::Progress<'d> {
246        executor::raw::Drain::progress(self.project_ref().inner, region)
247    }
248
249    fn force(
250        self: pin::Pin<&mut Self>,
251        turn: schedule::Turn<'_, 'd>,
252        driver: &mut retained::Context<'_, '_, 'd>,
253    ) {
254        executor::raw::Drain::force(self.project().inner, turn, driver);
255    }
256}
257
258const _: () = {
259    assert!(mem::size_of::<Bound<'_, '_, (), ()>>() == mem::size_of::<&mut ()>());
260    assert!(mem::align_of::<Bound<'_, '_, (), ()>>() == mem::align_of::<&mut ()>());
261    assert!(!mem::needs_drop::<Bound<'_, '_, (), ()>>());
262};