-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
770 additions
and
634 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
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::*; | ||
|
||
#[cglue_trait] | ||
pub trait PacketIo<Perms: PacketPerms, Param>: Sized { | ||
// TODO: make this a sink | ||
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::NewId(self, param, packet.stack()) | ||
IoFut { | ||
pkt: UnsafeCell::new(Some(packet.stack())), | ||
initial_state: 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> { | ||
//IoFut::NewId(self, param, packet.stack()) | ||
IoToFut { | ||
pkt_out: UnsafeCell::new(Some((packet.stack(), output.stack()))), | ||
initial_state: Some((self, param)), | ||
_phantom: PhantomData, | ||
} | ||
} | ||
} | ||
|
||
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, Perms: PacketPerms, Param, Packet: PacketStore<'a, Perms>> { | ||
pkt: UnsafeCell<Option<Packet::StackReq<'a>>>, | ||
initial_state: Option<(&'a T, Param)>, | ||
_phantom: PhantomData<Perms>, | ||
} | ||
|
||
impl<'a, T: PacketIo<Perms, Param>, 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 = unsafe { self.get_unchecked_mut() }; | ||
|
||
loop { | ||
match state.initial_state.take() { | ||
Some((io, param)) => { | ||
// SAFETY: this packet's existence is tied to 'a lifetime, meaning it will be valid | ||
// throughout 'a. | ||
let pkt: &'a mut Pkt::StackReq<'a> = | ||
unsafe { (*state.pkt.get()).as_mut().unwrap() }; | ||
let view: PacketView<'a, Perms> = Pkt::stack_opaque(pkt); | ||
// SAFETY: PacketView's lifetime is a marker, and we are using the marker lifetime to guide | ||
// assumptions about type's validity. A sound implementation would put a 'static object | ||
// here regardless, making the object 'static, while non-'static implementations are out of | ||
// our hand, therefore we assume the caller is giving us correct info. | ||
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, | ||
Perms: PacketPerms, | ||
Param, | ||
Packet: PacketStore<'a, Perms>, | ||
Output: OutputStore<'a, Perms>, | ||
> { | ||
pkt_out: UnsafeCell<Option<(Packet::StackReq<'a>, Output::StackReq<'a>)>>, | ||
initial_state: Option<(&'a T, Param)>, | ||
_phantom: PhantomData<Perms>, | ||
} | ||
|
||
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(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { | ||
let state = unsafe { self.get_unchecked_mut() }; | ||
|
||
loop { | ||
match state.initial_state.take() { | ||
Some((io, param)) => { | ||
// SAFETY: this packet's existence is tied to 'a lifetime, meaning it will be valid | ||
// throughout 'a. | ||
let (pkt, out): &'a mut (Pkt::StackReq<'a>, Out::StackReq<'a>) = | ||
unsafe { (*state.pkt_out.get()).as_mut().unwrap() }; | ||
let view: PacketView<'a, Perms> = Pkt::stack_opaque(pkt); | ||
// SAFETY: PacketView's lifetime is a marker, and we are using the marker lifetime to guide | ||
// assumptions about type's validity. A sound implementation would put a 'static object | ||
// here regardless, making the object 'static, while non-'static implementations are out of | ||
// our hand, therefore we assume the caller is giving us correct info. | ||
let bound = unsafe { view.bind(Some(Out::stack_opaque(out))) }; | ||
io.send_io(param, bound) | ||
} | ||
None => { | ||
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); | ||
break pkt | ||
.poll(cx) | ||
.map(|_| unsafe { (*state.pkt_out.get()).take().unwrap() }); | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.