Skip to main content

dope_core/driver/storage/
mod.rs

1use std::{mem, pin};
2
3use o3::{
4    alloc,
5    base::cell::region,
6    buffer::{
7        hold::limits,
8        resident::{Budget, Reuse},
9    },
10};
11
12use crate::{
13    BranchError, driver,
14    driver::{
15        life,
16        retained::flight,
17        route::{App, lease, queues},
18        schedule::{clock, clock::timer},
19        settings,
20        settings::{claim, errors},
21    },
22};
23
24mod cleanup;
25mod failure;
26mod mapping;
27pub mod path;
28mod release;
29mod removal;
30pub mod resident;
31mod scope;
32
33pub use cleanup::Cleanup;
34pub use failure::Failure;
35pub use mapping::Mapping;
36pub use release::Release;
37pub use removal::Removal;
38pub use scope::Scope;
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41#[repr(transparent)]
42pub struct Address(*mut core::ffi::c_void);
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45#[repr(transparent)]
46pub struct Bytes(usize);
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49#[repr(transparent)]
50pub struct Count(usize);
51
52impl Address {
53    pub(crate) const fn new(address: *mut core::ffi::c_void) -> Self {
54        Self(address)
55    }
56}
57
58impl Bytes {
59    pub(crate) const fn new(bytes: usize) -> Self {
60        Self(bytes)
61    }
62}
63
64impl Count {
65    pub(crate) const fn new(count: usize) -> Self {
66        Self(count)
67    }
68}
69
70/// Resident bytes requested for one driver-lifetime accounting domain.
71#[derive(Clone, Copy, Eq, PartialEq)]
72#[repr(transparent)]
73pub struct Resident(usize);
74
75/// Failure to issue one resident domain from a bounded allocator.
76#[derive(Clone, Copy, Debug, Eq, PartialEq)]
77pub enum Exhausted {
78    Domains { capacity: usize },
79    Retained { index: usize, cause: Reuse },
80}
81
82const _: () = assert!(size_of::<Exhausted>() == size_of::<usize>() * 4);
83
84impl Resident {
85    pub const fn bytes(bytes: usize) -> Self {
86        Self(bytes)
87    }
88
89    pub const fn from_limit(limit: limits::Bound) -> Self {
90        Self(limit.bytes())
91    }
92
93    const fn get(self) -> usize {
94        self.0
95    }
96}
97
98/// Projects one exact leaf from a generative storage build output.
99pub trait Path<Root, Leaf>: Copy
100where
101    Root: Plan,
102    Leaf: Plan,
103{
104    fn get<'life, 'p, 'd>(self, root: &'life Root::Output<'p, 'd>) -> &'life Leaf::Output<'p, 'd>
105    where
106        'd: 'p,
107        'p: 'life,
108        'd: 'life,
109        Self: 'd,
110        Root: 'd,
111        Leaf: 'd;
112}
113
114/// Restricted construction context for driver-domain storage.
115///
116/// Exposes stable identities and route reservation without operation submission.
117/// A build cannot publish into its output before the runtime pins that output.
118///
119#[repr(transparent)]
120pub struct Context<'a, 'd>(pub(in crate::driver) &'a mut life::Local<'d>);
121
122impl<'a, 'd> Context<'a, 'd> {
123    pub(super) fn new(local: &'a mut life::Local<'d>) -> Self {
124        Self(local)
125    }
126
127    pub fn driver(&self) -> driver::Reference<'d> {
128        self.0.driver
129    }
130
131    /// Exact receive-pool geometry of this driver generation.
132    pub fn receive(&self) -> settings::Receive {
133        self.0.driver.receive().layout()
134    }
135
136    pub fn region(&self) -> &region::Token<region::Identity<'d>> {
137        &self.0.region.0
138    }
139
140    pub fn state(&self) -> &region::Token<region::Identity<'d, 1>> {
141        &self.0.region.1
142    }
143
144    pub fn timer(&self) -> timer::Timer<'d> {
145        self.0.driver.timer()
146    }
147
148    pub fn clock(&self) -> clock::Clock<'_, 'd> {
149        self.0.driver.scheduler().clock()
150    }
151
152    /// Copies the resident-domain authority for this exact driver generation.
153    pub fn allocator(&self) -> resident::Alloc<'d> {
154        self.0.resident
155    }
156
157    /// Claims a lifetime-branded resident accounting domain for storage owned
158    /// by the build output.
159    pub fn budget(&self, cap: Resident) -> Result<Budget<'d>, Exhausted> {
160        self.0.resident.try_budget(cap.get())
161    }
162
163    /// Lends one affine construction step while retaining this outer authority.
164    pub fn reborrow(&mut self) -> Context<'_, 'd> {
165        Context(&mut *self.0)
166    }
167
168    /// Stages fixed submission groups without changing the live flight arena.
169    pub fn try_flights<Tags, const GROUPS: usize>(
170        self,
171        need: flight::Need<Tags, GROUPS>,
172    ) -> Result<flight::Prepared<'a, 'd, Tags, GROUPS>, alloc::Error> {
173        let Self(local) = self;
174        local.flights.try_prepare(need, local.driver)
175    }
176
177    pub fn try_reserve<B: App>(self) -> Result<lease::Claim<'d, B>, lease::Error> {
178        let Self(local) = self;
179        lease::Claim::try_new(local)
180    }
181
182    pub(in crate::driver) fn release(&mut self, retired: queues::Retired<'d>) {
183        lease::Registry::release(self.0, retired);
184    }
185}
186
187/// One generative storage output family.
188///
189/// A plan may borrow from its enclosing owner. Its output is available only
190/// for driver generations which the consumed plan itself outlives.
191pub trait Plan {
192    type Output<'p, 'd>: 'p
193    where
194        Self: 'd,
195        'd: 'p;
196}
197
198/// Pinned storage retaining its plan, backing loan, and driver generation.
199#[repr(transparent)]
200pub struct Loan<'a, 'p: 'a, 'd: 'p, S: Plan + 'd> {
201    value: pin::Pin<&'a S::Output<'p, 'd>>,
202}
203
204impl<'a, 'p: 'a, 'd: 'p, S: Plan + 'd> Loan<'a, 'p, 'd, S> {
205    pub(in crate::driver) fn new(value: pin::Pin<&'a S::Output<'p, 'd>>) -> Self {
206        Self { value }
207    }
208
209    /// Preserves the source borrow when this temporary view is consumed.
210    ///
211    ///
212    pub fn pinned(&self) -> pin::Pin<&'a S::Output<'p, 'd>> {
213        self.value
214    }
215}
216
217const _: () = {
218    assert!(mem::size_of::<Loan<'static, 'static, 'static, ()>>() == mem::size_of::<usize>());
219    assert!(mem::align_of::<Loan<'static, 'static, 'static, ()>>() == mem::align_of::<usize>());
220};
221
222/// Fallibly constructs driver-domain storage through the non-submitting [`Context`].
223pub trait Build: Plan {
224    type Error;
225
226    type Store<'d>
227    where
228        Self: 'd;
229
230    fn try_store<'d>(&self) -> Result<Self::Store<'d>, Self::Error>
231    where
232        Self: 'd;
233
234    fn try_build<'p, 'd>(
235        self,
236        store: &'p mut Self::Store<'d>,
237        ctx: Context<'_, 'd>,
238    ) -> Result<Self::Output<'p, 'd>, Self::Error>
239    where
240        Self: 'd,
241        'd: 'p;
242}
243
244/// Constructs driver-domain storage that owns all of its backing.
245pub trait Create: Plan {
246    type Error;
247
248    fn try_build<'p, 'd>(self, ctx: Context<'_, 'd>) -> Result<Self::Output<'p, 'd>, Self::Error>
249    where
250        Self: 'd,
251        'd: 'p;
252}
253
254/// Builds storage without contributing driver-resource claims.
255pub trait Claimless: Plan {}
256
257/// Constructs storage without introducing a recoverable failure path.
258pub trait Direct: Plan {
259    fn build<'p, 'd>(self) -> Self::Output<'p, 'd>
260    where
261        Self: 'd,
262        'd: 'p;
263}
264
265#[repr(transparent)]
266pub struct Value<T>(T);
267
268impl<T> Value<T> {
269    pub const fn new(value: T) -> Self {
270        Self(value)
271    }
272}
273
274impl<T> Plan for Value<T> {
275    type Output<'p, 'd>
276        = T
277    where
278        'd: 'p,
279        Self: 'd;
280}
281
282impl<T> Claimless for Value<T> {}
283
284impl<T> Direct for Value<T> {
285    fn build<'p, 'd>(self) -> Self::Output<'p, 'd>
286    where
287        'd: 'p,
288        Self: 'd,
289    {
290        self.0
291    }
292}
293
294impl Plan for () {
295    type Output<'p, 'd>
296        = ()
297    where
298        'd: 'p,
299        Self: 'd;
300}
301
302impl Claimless for () {}
303
304impl Direct for () {
305    fn build<'p, 'd>(self) -> Self::Output<'p, 'd>
306    where
307        'd: 'p,
308        Self: 'd,
309    {
310        self
311    }
312}
313
314impl<A: Plan, B: Plan> Plan for (A, B) {
315    type Output<'p, 'd>
316        = (A::Output<'p, 'd>, B::Output<'p, 'd>)
317    where
318        'd: 'p,
319        Self: 'd;
320}
321
322impl<A: Build, B: Build> Build for (A, B) {
323    type Error = BranchError<A::Error, B::Error>;
324    type Store<'d>
325        = (A::Store<'d>, B::Store<'d>)
326    where
327        Self: 'd;
328
329    fn try_store<'d>(&self) -> Result<Self::Store<'d>, Self::Error>
330    where
331        Self: 'd,
332    {
333        let first = self.0.try_store().map_err(BranchError::First)?;
334        let second = self.1.try_store().map_err(BranchError::Second)?;
335        Ok((first, second))
336    }
337
338    fn try_build<'p, 'd>(
339        self,
340        store: &'p mut Self::Store<'d>,
341        mut ctx: Context<'_, 'd>,
342    ) -> Result<Self::Output<'p, 'd>, Self::Error>
343    where
344        'd: 'p,
345        Self: 'd,
346    {
347        let (first, second) = self;
348        let first = first
349            .try_build(&mut store.0, ctx.reborrow())
350            .map_err(BranchError::First)?;
351        let second = second
352            .try_build(&mut store.1, ctx)
353            .map_err(BranchError::Second)?;
354        Ok((first, second))
355    }
356}
357
358impl<A: Claimless, B: Claimless> Claimless for (A, B) {}
359
360impl<A: Direct, B: Direct> Direct for (A, B) {
361    fn build<'p, 'd>(self) -> Self::Output<'p, 'd>
362    where
363        'd: 'p,
364        Self: 'd,
365    {
366        let first = Direct::build(self.0);
367        let second = Direct::build(self.1);
368        (first, second)
369    }
370}
371
372const _: () = {
373    assert!(std::mem::size_of::<Context<'static, 'static>>() == std::mem::size_of::<usize>());
374    assert!(std::mem::align_of::<Context<'static, 'static>>() == std::mem::align_of::<usize>());
375    assert!(std::mem::size_of::<Value<usize>>() == std::mem::size_of::<usize>());
376    assert!(std::mem::align_of::<Value<usize>>() == std::mem::align_of::<usize>());
377    assert!(std::mem::needs_drop::<Value<String>>() == std::mem::needs_drop::<String>());
378};
379
380/// Builds one storage plan while carrying an adjacent owned value.
381#[repr(transparent)]
382pub struct With<F, T>((F, T));
383
384impl<F, T> With<F, T> {
385    pub const fn new(plan: F, value: T) -> Self {
386        Self((plan, value))
387    }
388}
389
390impl<F, T> settings::Resource for With<F, T>
391where
392    F: settings::Resource,
393{
394    fn include_in(&self, needs: claim::Needs) -> Result<claim::Needs, errors::Claim> {
395        self.0.0.include_in(needs)
396    }
397}
398
399impl<F, T> Plan for With<F, T>
400where
401    F: Plan,
402{
403    type Output<'p, 'd>
404        = (F::Output<'p, 'd>, T)
405    where
406        'd: 'p,
407        Self: 'd;
408}
409
410impl<F, T> Build for With<F, T>
411where
412    F: Build,
413{
414    type Error = F::Error;
415    type Store<'d>
416        = F::Store<'d>
417    where
418        Self: 'd;
419
420    fn try_store<'d>(&self) -> Result<Self::Store<'d>, Self::Error>
421    where
422        Self: 'd,
423    {
424        self.0.0.try_store()
425    }
426
427    fn try_build<'p, 'd>(
428        self,
429        store: &'p mut Self::Store<'d>,
430        ctx: Context<'_, 'd>,
431    ) -> Result<Self::Output<'p, 'd>, Self::Error>
432    where
433        'd: 'p,
434        Self: 'd,
435    {
436        let (plan, value) = self.0;
437        Ok((plan.try_build(store, ctx)?, value))
438    }
439}
440
441impl<F: Direct, T> Direct for With<F, T> {
442    fn build<'p, 'd>(self) -> Self::Output<'p, 'd>
443    where
444        'd: 'p,
445        Self: 'd,
446    {
447        let (plan, value) = self.0;
448        (plan.build(), value)
449    }
450}
451
452impl<F: Claimless, T> Claimless for With<F, T> {}
453
454const _: () = {
455    assert!(mem::size_of::<With<usize, u8>>() == mem::size_of::<(usize, u8)>());
456    assert!(mem::align_of::<With<usize, u8>>() == mem::align_of::<(usize, u8)>());
457    assert!(mem::needs_drop::<With<String, ()>>() == mem::needs_drop::<String>());
458};