Skip to main content

dope_core/io/fd/
outbound.rs

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