use std::{cell::Cell, collections::VecDeque};
use dope_test::harness::observe::VecCellExt as _;
use o3::{
buffer::{resident, storage},
mem::Rejected,
};
use sark_core::duplex::{self, admit, input};
use sark_http::payload::owned;
pub struct Buf(pub VecDeque<storage::Shared>);
pub trait Admit<'d>: duplex::Session<'d> + Sized {
fn admit<'turn>(
emission: admit::Emission<'turn, 'd, Self>,
) -> admit::Admission<'turn, 'd, Self, (), ()> {
match emission.into_parts().0 {
admit::Payload::Vacant(permit) => permit.commit(()),
admit::Payload::Present { output, permit } => permit.returned((), output),
}
}
}
impl<'d, D: duplex::Session<'d>> Admit<'d> for D {}
impl<'d> input::Buf<'d> for Buf {
type Input = &'d [u8];
type Error = storage::AllocError;
type Receipt = usize;
fn state(&self) -> input::Buffer {
if self.0.is_empty() {
input::Buffer::Empty
} else {
input::Buffer::Queued
}
}
fn push(&mut self, input: Self::Input) -> Result<(), Rejected<Self::Input, Self::Error>> {
if !input.is_empty() {
let owned =
storage::Shared::try_copy(input).map_err(|error| Rejected::new(input, error))?;
self.0.push_back(owned);
}
Ok(())
}
fn take(&mut self) -> input::Take<'d, Self::Receipt> {
let Some(input) = self.0.pop_front() else {
return input::Take::Empty;
};
let receipt = input.len();
input::Take::Item {
input: input.into(),
receipt,
}
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum Event {
First,
Second,
Bad,
Activate,
Finished,
}
pub struct Session<'a>(pub &'a Cell<Vec<Event>>);
pub struct Idle<'a>(pub &'a Cell<Vec<Event>>);
pub struct Terminal;
pub struct Ending<'a>(pub &'a Cell<Vec<Event>>);
impl<'d> duplex::Session<'d> for Ending<'_> {
fn receive(
&mut self,
_: owned::Segments<'d>,
_: &mut [u8],
_: &mut Vec<u8>,
) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::idle())
}
fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::idle().activate())
}
fn finish(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Finished);
(
0,
duplex::Action::send_end(resident::Shared::from(b"end".as_slice())),
)
}
}
impl<'d> duplex::Session<'d> for Session<'_> {
fn receive(
&mut self,
input: owned::Segments<'d>,
_: &mut [u8],
_: &mut Vec<u8>,
) -> (usize, duplex::Action<'d>) {
let event = match input.contiguous() {
Some(b"first") => Event::First,
Some(b"second") => Event::Second,
_ => Event::Bad,
};
self.0.push(event);
(0, duplex::Action::idle())
}
fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Activate);
(0, duplex::Action::idle().activate())
}
fn finish(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Finished);
(0, duplex::Action::close())
}
}
impl<'d> duplex::Session<'d> for Terminal {
fn receive(
&mut self,
_: owned::Segments<'d>,
_: &mut [u8],
_: &mut Vec<u8>,
) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::close())
}
fn finish(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::end())
}
fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::close())
}
}
impl<'d> duplex::Session<'d> for Idle<'_> {
fn receive(
&mut self,
_: owned::Segments<'d>,
_: &mut [u8],
_: &mut Vec<u8>,
) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Bad);
(0, duplex::Action::idle())
}
fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Activate);
(0, duplex::Action::idle())
}
fn finish(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.0.push(Event::Finished);
(0, duplex::Action::idle())
}
}
pub struct Prefix<'a> {
pub calls: &'a Cell<usize>,
pub written: usize,
pub body: bool,
}
impl<'d> duplex::Session<'d> for Prefix<'_> {
fn receive(
&mut self,
_: owned::Segments<'d>,
output: &mut [u8],
scratch: &mut Vec<u8>,
) -> (usize, duplex::Action<'d>) {
self.finish(output, scratch)
}
fn finish(&mut self, output: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
self.calls.set(self.calls.get() + 1);
output.fill(b'p');
(
self.written,
if self.body {
duplex::Action::send_end(resident::Shared::from(b"end".as_slice()))
} else {
duplex::Action::end()
},
)
}
fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, duplex::Action<'d>) {
(0, duplex::Action::end())
}
}