use crate::error::Error;
#[cfg(feature = "cglue-trait")]
use cglue::prelude::v1::*;
use core::cell::UnsafeCell;
use core::future::Future;
use core::marker::PhantomData;
use core::pin::Pin;
use core::task::{Context, Poll};
mod packet;
pub use packet::*;
mod opaque;
pub use opaque::*;
#[cfg_attr(feature = "cglue-trait", cglue_trait)]
pub trait PacketIo<Perms: PacketPerms, Param>: Sized {
fn send_io(&self, param: Param, view: BoundPacketView<Perms>);
}
pub trait PacketIoExt<Perms: PacketPerms, Param>: PacketIo<Perms, Param> {
fn io<'a, T: PacketStore<'a, Perms>>(
&'a self,
param: Param,
packet: T,
) -> IoFut<'a, Self, Perms, Param, T> {
IoFut {
pkt: UnsafeCell::new(Some(packet.stack())),
initial_state: UnsafeCell::new(Some((self, param))),
_phantom: PhantomData,
}
}
fn io_to<'a, T: PacketStore<'a, Perms>, O: OutputStore<'a, Perms>>(
&'a self,
param: Param,
packet: T,
output: O,
) -> IoToFut<'a, Self, Perms, Param, T, O> {
IoToFut {
pkt_out: UnsafeCell::new(Some((packet.stack(), output.stack()))),
initial_state: UnsafeCell::new(Some((self, param))),
_phantom: PhantomData,
}
}
fn io_to_stream<'a, T: PacketStore<'a, Perms> + 'a, O: PushPop<Output<'a, Perms>> + 'a>(
&'a self,
param: Param,
packet: T,
container: O,
) -> IoToFut<'a, Self, Perms, Param, T, PacketStream<O, Perms>> {
self.io_to(param, packet, PacketStream::new(container))
}
fn io_to_fn<
'a,
T: PacketStore<'a, Perms>,
F: Fn(PacketView<'a, Perms>, Option<Error>) + Send + Sync + 'a,
>(
&'a self,
param: Param,
packet: T,
func: F,
) -> IoToFut<'a, Self, Perms, Param, T, OutputFunction<F, Perms>> {
self.io_to(param, packet, OutputFunction::new(func))
}
}
impl<T: PacketIo<Perms, Param>, Perms: PacketPerms, Param> PacketIoExt<Perms, Param> for T {}
pub trait StreamIoExt<Perms: PacketPerms>: PacketIo<Perms, NoPos> {
fn stream_io<'a, T: PacketStore<'a, Perms>>(
&'a self,
packet: T,
) -> IoFut<'a, Self, Perms, NoPos, T> {
self.io(NoPos::new(), packet)
}
fn stream_io_to<'a, T: PacketStore<'a, Perms>, O: OutputStore<'a, Perms>>(
&'a self,
packet: T,
output: O,
) -> IoToFut<'a, Self, Perms, NoPos, T, O> {
self.io_to(NoPos::new(), packet, output)
}
}
impl<T: PacketIo<Perms, NoPos>, Perms: PacketPerms> StreamIoExt<Perms> for T {}
#[repr(transparent)]
#[derive(Clone)]
pub struct NoPos(core::marker::PhantomData<()>);
impl NoPos {
pub const fn new() -> Self {
Self(core::marker::PhantomData)
}
}
pub struct IoFut<'a, T: ?Sized, Perms: PacketPerms, Param, Packet: PacketStore<'a, Perms>> {
pkt: UnsafeCell<Option<Packet::StackReq<'a>>>,
initial_state: UnsafeCell<Option<(&'a T, Param)>>,
_phantom: PhantomData<Perms>,
}
impl<
'a,
T: PacketIo<Perms, Param> + ?Sized,
Perms: PacketPerms,
Param,
Pkt: PacketStore<'a, Perms>,
> Future for IoFut<'a, T, Perms, Param, Pkt>
{
type Output = Pkt::StackReq<'a>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let state = self.into_ref().get_ref();
loop {
match unsafe { (*state.initial_state.get()).take() } {
Some((io, param)) => {
let pkt: &'a Pkt::StackReq<'a> =
unsafe { (*state.pkt.get()).as_ref().unwrap() };
let view: PacketView<'a, Perms> = Pkt::stack_opaque(pkt);
let bound = unsafe { view.bind(None) };
io.send_io(param, bound)
}
None => {
let pkt: &'a Pkt::StackReq<'a> =
unsafe { (*state.pkt.get()).as_ref().unwrap() };
let mut pkt: &'a Packet<Perms> = Pkt::stack_hdr(pkt);
let pkt = Pin::new(&mut pkt);
break pkt
.poll(cx)
.map(|_| unsafe { (*state.pkt.get()).take().unwrap() });
}
}
}
}
}
pub struct IoToFut<
'a,
T: ?Sized,
Perms: PacketPerms,
Param,
Packet: PacketStore<'a, Perms>,
Output: OutputStore<'a, Perms>,
> {
pkt_out: UnsafeCell<Option<(Packet::StackReq<'a>, Output::StackReq<'a>)>>,
initial_state: UnsafeCell<Option<(&'a T, Param)>>,
_phantom: PhantomData<Perms>,
}
impl<
'a,
T: PacketIo<Perms, Param> + ?Sized,
Perms: PacketPerms,
Param,
Pkt: PacketStore<'a, Perms>,
Out: OutputStore<'a, Perms>,
> IoToFut<'a, T, Perms, Param, Pkt, Out>
{
pub fn submit(self: Pin<&mut Self>) -> &Out::StackReq<'a> {
let this = self.into_ref();
if let Some((io, param)) = unsafe { (*this.initial_state.get()).take() } {
let (pkt, out): &'a mut (Pkt::StackReq<'a>, Out::StackReq<'a>) =
unsafe { (*this.pkt_out.get()).as_mut().unwrap() };
let view: PacketView<'a, Perms> = Pkt::stack_opaque(pkt);
let bound = unsafe { view.bind(Some(Out::stack_opaque(out))) };
io.send_io(param, bound)
}
unsafe { (*this.pkt_out.get()).as_ref().map(|(_, out)| out).unwrap() }
}
}
impl<
'a,
T: PacketIo<Perms, Param>,
Perms: PacketPerms,
Param,
Pkt: PacketStore<'a, Perms>,
Out: OutputStore<'a, Perms>,
> Future for IoToFut<'a, T, Perms, Param, Pkt, Out>
{
type Output = (Pkt::StackReq<'a>, Out::StackReq<'a>);
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
self.as_mut().submit();
let state = self.into_ref();
let pkt: &'a Pkt::StackReq<'a> = unsafe { &(*state.pkt_out.get()).as_ref().unwrap().0 };
let mut pkt: &'a Packet<Perms> = Pkt::stack_hdr(pkt);
let pkt = Pin::new(&mut pkt);
pkt.poll(cx)
.map(|_| unsafe { (*state.pkt_out.get()).take().unwrap() })
}
}