Skip to main content

dope_core/io/fd/
outbound.rs

1use core::marker::PhantomData;
2use std::mem;
3
4use o3::mem::{Lease, Return};
5
6use crate::{
7    driver,
8    driver::{
9        route,
10        route::{indices, kind, table},
11    },
12    io::fd::{domain, handles},
13};
14
15fn descriptors(driver: driver::Reference<'_>) -> &domain::Domain {
16    driver.ready().arena().descriptors()
17}
18
19#[derive(Clone, Copy)]
20#[repr(transparent)]
21pub(crate) struct Context<'d>(driver::Reference<'d>);
22
23impl<'d> Context<'d> {
24    pub(crate) const fn new(driver: driver::Reference<'d>) -> Self {
25        Self(driver)
26    }
27
28    pub(crate) fn try_reserve<B: route::Tag>(
29        &self,
30        count: table::Capacity,
31    ) -> Result<Reserved<'d, B>, Error> {
32        domain::Outbound::try_map::<B>(self.0, count)
33    }
34
35    pub(crate) fn acquire(
36        self,
37        key: route::OutboundKey,
38        local: indices::SlotIndex,
39    ) -> Option<handles::SocketSlot<'d>> {
40        let id = domain::Outbound::from(descriptors(self.0)).acquire(key, local)?;
41        Some(handles::SocketSlot::from_claim(id, self.0))
42    }
43
44    pub(crate) fn creation(
45        self,
46        target: route::Erased<'d, kind::Socket>,
47    ) -> Option<domain::Creation> {
48        let key = route::OutboundKey::from_raw(u32::from(target.route().app()?.raw()))?;
49        domain::Outbound::from(descriptors(self.0)).creation(key, target.slot())
50    }
51
52    pub(crate) fn begin_create(self, slot: handles::OutboundSlot) {
53        domain::Outbound::from(descriptors(self.0)).begin_create(slot);
54    }
55
56    pub(crate) fn complete(self, creation: domain::Creation) -> domain::Create {
57        domain::Outbound::from(descriptors(self.0)).created(creation)
58    }
59
60    pub(crate) fn fail_create(self, creation: domain::Creation) {
61        domain::Outbound::from(descriptors(self.0)).failed(creation);
62    }
63
64    pub(crate) fn activate(self, slot: handles::OutboundSlot) {
65        domain::Outbound::from(descriptors(self.0)).activate(slot);
66    }
67
68    pub(crate) fn retire(self, key: route::OutboundKey) {
69        domain::Outbound::from(descriptors(self.0)).retire(key);
70    }
71}
72
73const _: () = {
74    assert!(std::mem::size_of::<Context<'_>>() == std::mem::size_of::<driver::Reference<'_>>());
75    assert!(std::mem::align_of::<Context<'_>>() == std::mem::align_of::<driver::Reference<'_>>());
76    assert!(std::mem::size_of::<domain::Create>() == std::mem::size_of::<u8>());
77    assert!(std::mem::align_of::<domain::Create>() == std::mem::align_of::<u8>());
78};
79
80/// Exact reason a driver-local outbound descriptor range was not reserved.
81#[derive(Clone, Copy, Debug, PartialEq, Eq)]
82pub enum Error {
83    Empty,
84    Occupied,
85    Capacity { requested: usize, available: usize },
86    Retiring { requested: usize, available: usize },
87}
88
89/// Linear authority over one route's driver-local descriptor range.
90pub struct Reserved<'d, B: route::Tag> {
91    inner: Lease<Release<'d, B>>,
92}
93
94struct Release<'d, B: route::Tag> {
95    brand: PhantomData<B>,
96    driver: driver::Reference<'d>,
97}
98
99impl<B: route::Tag> Return for Release<'_, B> {
100    type Item = ();
101
102    fn return_item(self, (): Self::Item) {
103        self.driver
104            .outbound()
105            .retire(route::OutboundKey::for_tag::<B>());
106    }
107}
108
109impl<'d, B: route::Tag> Reserved<'d, B> {
110    /// The framework route cannot reserve an application descriptor range.
111    pub fn try_new(
112        driver: &driver::Context<'_, 'd>,
113        count: table::Capacity,
114    ) -> Result<Self, Error> {
115        driver.driver_ref().outbound().try_reserve::<B>(count)
116    }
117
118    pub(crate) fn new(driver: driver::Reference<'d>) -> Self {
119        Self {
120            inner: Lease::new(
121                Release {
122                    driver,
123                    brand: PhantomData,
124                },
125                (),
126            ),
127        }
128    }
129
130    /// Binds one local pool target to its physical descriptor slot.
131    ///
132    /// A target from another route cannot acquire this reservation:
133    ///
134    pub fn bind(
135        &self,
136        target: route::Target<'d, B>,
137    ) -> Option<route::Bound<'d, B, handles::SocketSlot<'d>>> {
138        let release = self.inner.sink();
139        let key = route::OutboundKey::for_tag::<B>();
140        let slot = release.driver.outbound().acquire(key, target.slot())?;
141        Some(target.bind(slot))
142    }
143}
144
145const _: () = {
146    assert!(
147        mem::size_of::<Reserved<'_, route::KeyTag<0>>>() == mem::size_of::<driver::Reference<'_>>()
148    );
149    assert!(
150        mem::align_of::<Reserved<'_, route::KeyTag<0>>>()
151            == mem::align_of::<driver::Reference<'_>>()
152    );
153};