use dope_core::{
driver::{
route::{self, Identity},
schedule::app::batch::Bound,
},
io::{recv, transfer},
};
use o3::mem;
use receive::{batch, discard, mode, reserve};
use crate::{
link::{slot, slot::types},
wire::{
self, receive,
receive::{Chunk, mode::Disabled},
terminal,
},
};
pub(in crate::link) struct Prepared<
'a,
'w,
'd,
ID: Identity + 'w,
W: wire::Spec + 'w,
P: mode::Flag,
> where
'd: 'w,
{
pub(in crate::link::slot::recv) engine: &'a mut slot::Engine<'d, ID, W>,
pub(in crate::link::slot::recv) end: terminal::Both<'a, terminal::Error<'w, W>>,
pub(in crate::link::slot::recv) transaction: <<<W as wire::Spec>::Receive as receive::Policy<
W,
>>::Reserve as reserve::Kind<W>>::Transaction<'a, 'w, 'd, ID>,
pub(in crate::link::slot::recv) credit: P::Binding<'a, 'd, ID>,
pub(in crate::link::slot::recv) needs_rearm: bool,
}
impl<'a, 'w, 'd, ID: Identity + 'w, W: wire::Spec + 'w, P: mode::Flag>
Prepared<'a, 'w, 'd, ID, W, P>
where
'd: 'w,
{
pub(in crate::link) fn new(
conn: &'a mut types::Control<'w, 'd, ID, W>,
rt: &'a mut W::Runtime<'w, 'd, ID>,
credit: P::Binding<'a, 'd, ID>,
arm: bool,
) -> Result<Self, slot::Control>
where
<W::Receive as receive::Policy<W>>::Reserve: reserve::Immediate<W>,
{
let end = match conn.engine.both(&mut conn.terminal) {
terminal::Admission::Open(end) => end,
terminal::Admission::Closed => {
return Err(slot::Control::Discarded {
needs_rearm: arm,
finished: false,
});
}
};
Ok(Self {
engine: &mut conn.engine,
end,
transaction:
<<W::Receive as receive::Policy<W>>::Reserve as reserve::Immediate<W>>::reserve(
&mut conn.wire,
rt,
),
credit,
needs_rearm: arm,
})
}
pub(in crate::link::slot::recv) fn capture(
engine: &mut slot::Engine<'d, ID, W>,
rearm: &mut bool,
captured: terminal::Captured,
) {
engine.captured(captured);
if let terminal::Captured::Eof | terminal::Captured::Terminal = captured {
*rearm |= engine.operations.recv.has_cancel();
}
}
fn discard(&mut self, bytes: &mut recv::Lease<'d>) -> (transfer::Len, bool) {
<<W::Receive as receive::Policy<W>>::Discard as discard::Policy>::consume(
&mut self.engine.discard,
bytes,
)
}
pub(in crate::link) fn data<'bytes, 'id>(
mut self,
bytes: &'bytes mut recv::Lease<'d>,
cap: Bound<'id, batch::Capacity<'d, W>>,
) -> (
slot::Decision<batch::Items<'bytes, W>>,
mem::raw::Unused<'id>,
)
where
'w: 'bytes,
{
let (remaining, finished) = self.discard(bytes);
if remaining.is_zero() {
let unused = cap.empty();
return (
slot::Decision::Control(slot::Control::Discarded {
needs_rearm: self.needs_rearm,
finished,
}),
unused,
);
}
let slice = bytes.as_mut_slice();
let read = <W::Receive as receive::Policy<W>>::process::<ID>(
self.transaction,
slice,
batch::Grant::new(cap),
self.end,
);
let (produced, captured) = read.into_parts();
let (chunk, unused) = produced.into_parts();
Self::capture(self.engine, &mut self.needs_rearm, captured);
if receive::raw::Batch::is_empty(&chunk) {
return (
slot::Decision::Control(slot::Control::NoChunk {
needs_rearm: self.needs_rearm,
}),
unused,
);
}
(
slot::Decision::Chunk {
chunk: batch::Items::from_raw(chunk),
needs_rearm: self.needs_rearm,
},
unused,
)
}
pub(in crate::link) fn scoped(
mut self,
mut bytes: recv::Lease<'d>,
) -> slot::Decision<Chunk<'w, 'd, W, Disabled>> {
let (remaining, finished) = self.discard(&mut bytes);
if remaining.is_zero() {
return slot::Decision::Control(slot::Control::Discarded {
needs_rearm: self.needs_rearm,
finished,
});
}
let read =
<W::Receive as receive::Policy<W>>::read_lease::<ID>(self.transaction, bytes, self.end)
.map(|cursor| cursor.map(Chunk::from_raw));
let (item, captured) = read.into_parts();
Self::capture(self.engine, &mut self.needs_rearm, captured);
match item {
Some(chunk) => slot::Decision::Chunk {
chunk,
needs_rearm: self.needs_rearm,
},
None => slot::Decision::Control(slot::Control::NoChunk {
needs_rearm: self.needs_rearm,
}),
}
}
}
impl<'a, 'w, 'd, ID: Identity + 'w, W, P> Prepared<'a, 'w, 'd, ID, W, P>
where
'd: 'w,
W: wire::Spec + 'w,
W::Receive: receive::Policy<W, Credit = mode::Enabled>,
P: mode::Stored,
{
pub(in crate::link) fn retained(
mut self,
target: route::Operation<'d, ID>,
mut bytes: recv::Lease<'d>,
) -> slot::Decision<Chunk<'w, 'd, W>> {
let (remaining, finished) = self.discard(&mut bytes);
if remaining.is_zero() {
return slot::Decision::Control(slot::Control::Discarded {
needs_rearm: self.needs_rearm,
finished,
});
}
let credit = match P::arm(self.credit, target, self.engine.ready_handle().target()) {
Ok(credit) => credit,
Err(cause) => {
return slot::Decision::Control(slot::Control::Credit {
cause,
needs_rearm: self.needs_rearm,
});
}
};
let read =
<W::Receive as receive::Policy<W>>::read_lease::<ID>(self.transaction, bytes, self.end)
.map(|cursor| cursor.map(Chunk::from_raw));
let (item, captured) = read.into_parts();
Self::capture(self.engine, &mut self.needs_rearm, captured);
match item {
Some(cursor) => {
self.engine.operations.recv.pause();
self.needs_rearm |= self.engine.operations.recv.has_cancel();
let chunk = cursor.retain(credit.claim().into_return());
slot::Decision::Chunk {
chunk,
needs_rearm: self.needs_rearm,
}
}
None => {
credit.cancel();
slot::Decision::Control(slot::Control::NoChunk {
needs_rearm: self.needs_rearm,
})
}
}
}
}