use dope_core::driver::route::{Identity, KeyTag};
use o3::{
base::num::bounded,
depot::{self, arena::slab, array},
};
use crate::client::attempt::{
self,
queue::{
self, Held,
entry::Entry,
storage::{self, Node, Occupied},
table::Table,
},
};
#[must_use = "dropping an attempt reserve releases its generation"]
pub struct Reserve<'source, 'd, T: dope_net::Transport, ID: Identity = KeyTag<0>> {
table: &'source Table<'d, T, ID>,
free: slab::Reserved<'source, Node<'d, T, ID>, attempt::Tag<'d, ID>>,
}
impl<'source, 'd, T: dope_net::Transport, ID: Identity> Reserve<'source, 'd, T, ID> {
pub(super) fn try_new(table: &'source Table<'d, T, ID>) -> Result<Self, slab::Vacancy> {
Ok(Self {
table,
free: table.nodes.try_vacancy()?.reserve(),
})
}
pub fn id(&self) -> attempt::Id<'d, ID> {
attempt::Id {
handle: storage::Key::new(
bounded::U32::from_one(self.free.position()),
self.free.key().generation(),
),
}
}
pub fn start(self, target: attempt::StreamTarget<T>) -> queue::Lease<'source, 'd, T, ID> {
let key = self.id();
let node = Node::new(
key.handle.index().into(),
Entry::queued(attempt::Plan::from_target(target)),
);
let entry = Occupied::new(self.table, self.free.occupy(node), key);
unsafe { depot::raw::TagEntry::vacant(entry) }
.select(array::Index::at::<0>())
.push::<false>();
queue::Lease::new(unsafe { Held::new((self.table, key)) })
}
}