use std::num::NonZero;
use o3::{buffer::resident, depot::queue::indexed::keyed};
use sark_core::{
body::{self, credit},
decode::{
request,
state::{self, open},
},
};
use crate::{
conn::{Error, event},
server::{
self, payload,
state::exchange,
task::{
Built,
ingress::{
Buffered, Data, Occupied, Receiving, Turn,
entry::{self, Entry},
errors,
},
},
},
stream::Key,
};
pub(in crate::server::task) unsafe fn try_buffer<'d, P, F, B, E>(
data: Data<'_, 'd, P, F, B>,
stream: Key,
request: Buffered<'d, P>,
evidence: E,
) -> Result<(), Error>
where
P: request::Prepared,
F: state::Family<P>,
B: body::Build<'d>,
E: credit::Evidence,
{
let vacant = match data.entries.try_vacant(stream) {
Ok(vacant) => vacant,
Err(error) => {
let release = data.credit.scope(|mut ledger| {
unsafe { exchange::raw::Closing::new(request.request, &mut ledger) }
.discard::<Receiving<'d>, _>(evidence)
});
return Err(errors::reject(error, release));
}
};
vacant.insert(Entry::Buffered(request));
Ok(())
}
pub(in crate::server::task) unsafe fn drive_entry<'a, 'd, P, F, B, E>(
occupied: Occupied<'a, 'd, P, F, B>,
queue: &'a mut keyed::Fifo<Key, entry::Build>,
credit: &mut credit::raw::Account,
budget: NonZero<usize>,
evidence: E,
) -> Built<'d, B>
where
P: request::Prepared,
F: state::Family<P>,
B: body::Build<'d>,
E: credit::Evidence,
{
let Some(member) = Turn::try_new(occupied, queue) else {
return body::BuildOutcome::Idle;
};
member.drive(credit, budget, evidence)
}
pub(super) struct Buffering<'a, 'ledger, 'd, P: request::Prepared, O: credit::Origin> {
buffered: &'a mut Buffered<'d, P>,
ledger: &'a mut credit::raw::Ledger<'ledger, O>,
}
impl<'a, 'ledger, 'd, P: request::Prepared, O: credit::Origin> Buffering<'a, 'ledger, 'd, P, O> {
pub(super) unsafe fn new(
buffered: &'a mut Buffered<'d, P>,
ledger: &'a mut credit::raw::Ledger<'ledger, O>,
) -> Self {
Self { buffered, ledger }
}
pub(super) fn try_push<E: credit::Evidence>(
self,
evidence: E,
data: event::DataPayload<resident::Shared<'d>>,
limits: server::Config,
) -> payload::Push<event::DataPayload<resident::Shared<'d>>> {
state::Flow::each_open(
&mut self.buffered.request,
Feed {
ledger: self.ledger,
evidence,
data,
limits,
},
)
}
}
struct Feed<'a, 'ledger, 'd, O: credit::Origin, E> {
ledger: &'a mut credit::raw::Ledger<'ledger, O>,
evidence: E,
data: event::DataPayload<resident::Shared<'d>>,
limits: server::Config,
}
impl<'d, O: credit::Origin, E: credit::Evidence> open::Each<Receiving<'d>>
for Feed<'_, '_, 'd, O, E>
{
type Output<'a> = payload::Push<event::DataPayload<resident::Shared<'d>>>;
fn apply<'a>(self, body: &'a mut payload::Buffer<'d>) -> Self::Output<'a> {
let mut body = unsafe { payload::raw::Loan::new(body, self.ledger) };
let request = self.limits.request(body.max_body());
body.try_push(
self.ledger,
self.evidence,
self.data,
request,
self.limits.connection(),
)
}
}