use alloc::boxed::Box;
use core::marker::PhantomData;
use crate::nexus::effect::EffectMarker;
use crate::nexus::row::Row;
pub const SESSION_BIT: u128 = 1 << 33;
#[derive(Copy, Clone, Debug)]
pub struct SessionEffect;
impl EffectMarker for SessionEffect {
const BIT: u128 = SESSION_BIT;
const NAME: &'static str = "Session";
}
pub type SessionRow = Row<SESSION_BIT>;
#[derive(Debug)]
pub struct Send<T, P> {
_value: PhantomData<T>,
_cont: PhantomData<P>,
}
#[derive(Debug)]
pub struct Receive<T, P> {
_value: PhantomData<T>,
_cont: PhantomData<P>,
}
#[derive(Debug)]
pub struct Offer<P1, P2> {
_left: PhantomData<P1>,
_right: PhantomData<P2>,
}
#[derive(Debug)]
pub struct Select<P1, P2> {
_left: PhantomData<P1>,
_right: PhantomData<P2>,
}
#[derive(Debug)]
pub struct End;
pub trait Protocol: Sized {
type Dual: Protocol;
}
impl<T, P: Protocol> Protocol for Send<T, P> {
type Dual = Receive<T, P::Dual>;
}
impl<T, P: Protocol> Protocol for Receive<T, P> {
type Dual = Send<T, P::Dual>;
}
impl<P1: Protocol, P2: Protocol> Protocol for Offer<P1, P2> {
type Dual = Select<P1::Dual, P2::Dual>;
}
impl<P1: Protocol, P2: Protocol> Protocol for Select<P1, P2> {
type Dual = Offer<P1::Dual, P2::Dual>;
}
impl Protocol for End {
type Dual = End;
}
pub struct Session<P: Protocol> {
_protocol: PhantomData<P>,
}
impl<P: Protocol> Session<P> {
#[inline]
pub fn new() -> Self {
Session {
_protocol: PhantomData,
}
}
}
impl<P: Protocol> Default for Session<P> {
fn default() -> Self {
Self::new()
}
}
impl<T, P: Protocol> Session<Send<T, P>> {
pub fn send(self, _value: T) -> Session<P> {
Session {
_protocol: PhantomData,
}
}
}
impl<T, P: Protocol> Session<Receive<T, P>> {
pub fn receive(self) -> (T, Session<P>)
where
T: Default,
{
let value = T::default();
(
value,
Session {
_protocol: PhantomData,
},
)
}
pub fn receive_with(self, value: T) -> (T, Session<P>) {
(
value,
Session {
_protocol: PhantomData,
},
)
}
}
impl<P1: Protocol, P2: Protocol> Session<Offer<P1, P2>> {
pub fn offer(self) -> Either<Session<P1>, Session<P2>> {
Either::Left(Session {
_protocol: PhantomData,
})
}
pub fn offer_left(self) -> Session<P1> {
Session {
_protocol: PhantomData,
}
}
pub fn offer_right(self) -> Session<P2> {
Session {
_protocol: PhantomData,
}
}
}
impl<P1: Protocol, P2: Protocol> Session<Select<P1, P2>> {
pub fn select_left(self) -> Session<P1> {
Session {
_protocol: PhantomData,
}
}
pub fn select_right(self) -> Session<P2> {
Session {
_protocol: PhantomData,
}
}
}
impl Session<End> {
pub fn close(self) {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Either<L, R> {
Left(L),
Right(R),
}
impl<L, R> Either<L, R> {
pub fn is_left(&self) -> bool {
matches!(self, Either::Left(_))
}
pub fn is_right(&self) -> bool {
matches!(self, Either::Right(_))
}
pub fn unwrap_left(self) -> L {
match self {
Either::Left(l) => l,
Either::Right(_) => crate::cold_panic!("called unwrap_left on Right"),
}
}
pub fn unwrap_right(self) -> R {
match self {
Either::Right(r) => r,
Either::Left(_) => crate::cold_panic!("called unwrap_right on Left"),
}
}
}
pub fn assert_dual<P1: Protocol, P2: Protocol>()
where
P1::Dual: SameType<P2>,
{
}
pub trait SameType<T> {}
impl<T> SameType<T> for T {}
pub type RequestResponse<Req, Resp> = Receive<Req, Send<Resp, End>>;
pub type RequestResponseClient<Req, Resp> = Send<Req, Receive<Resp, End>>;
pub type Stream3<T> = Send<T, Send<T, Send<T, End>>>;
pub type Notify<T> = Send<T, End>;
pub type NotifyReceive<T> = Receive<T, End>;
type SessionRun<P, A> = Box<dyn FnOnce(Session<P>) -> (A, Session<End>)>;
pub struct SessionComputation<P: Protocol, A> {
run: SessionRun<P, A>,
}
impl<P: Protocol, A: 'static> SessionComputation<P, A> {
#[inline]
pub fn new<F>(f: F) -> Self
where
F: FnOnce(Session<P>) -> (A, Session<End>) + 'static,
{
SessionComputation { run: Box::new(f) }
}
#[inline]
pub fn run(self, session: Session<P>) -> (A, Session<End>) {
(self.run)(session)
}
pub fn pure(value: A) -> SessionComputation<End, A>
where
A: Clone,
{
SessionComputation::new(move |session| (value, session))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Clone, Debug, Default, PartialEq)]
struct Request {
id: u32,
}
#[derive(Clone, Debug, Default, PartialEq)]
struct Response {
data: u32,
}
#[test]
fn test_send_receive_protocol() {
type ClientProto = Send<Request, Receive<Response, End>>;
let session: Session<ClientProto> = Session::new();
let session = session.send(Request { id: 42 });
let (response, session) = session.receive_with(Response { data: 100 });
assert_eq!(response.data, 100);
session.close();
}
#[test]
fn test_server_protocol() {
type ServerProto = Receive<Request, Send<Response, End>>;
let session: Session<ServerProto> = Session::new();
let (request, session) = session.receive_with(Request { id: 42 });
let response = Response {
data: request.id * 2,
};
let session = session.send(response);
session.close();
}
#[test]
fn test_duality() {
type Client = Send<Request, Receive<Response, End>>;
type Server = Receive<Request, Send<Response, End>>;
assert_dual::<Client, Server>();
assert_dual::<Server, Client>();
}
#[test]
fn test_offer_select() {
type ServerOffer = Offer<Send<i32, End>, Send<bool, End>>;
let session: Session<ServerOffer> = Session::new();
let session_left = session.offer_left();
let session_end = session_left.send(42);
session_end.close();
}
#[test]
fn test_select() {
type ClientSelect = Select<Receive<i32, End>, Receive<bool, End>>;
let session: Session<ClientSelect> = Session::new();
let session_left = session.select_left();
let (value, session_end) = session_left.receive_with(42);
assert_eq!(value, 42);
session_end.close();
}
#[test]
fn test_either() {
let left: Either<i32, &str> = Either::Left(42);
let right: Either<i32, &str> = Either::Right("hello");
assert!(left.is_left());
assert!(!left.is_right());
assert!(right.is_right());
assert!(!right.is_left());
assert_eq!(left.unwrap_left(), 42);
assert_eq!(right.unwrap_right(), "hello");
}
#[test]
fn test_protocol_patterns() {
type Server = RequestResponse<Request, Response>;
type Client = RequestResponseClient<Request, Response>;
assert_dual::<Server, Client>();
}
#[test]
fn test_notify_pattern() {
type Sender = Notify<i32>;
type Receiver = NotifyReceive<i32>;
assert_dual::<Sender, Receiver>();
let session: Session<Sender> = Session::new();
let session = session.send(42);
session.close();
}
#[test]
fn test_multi_step_protocol() {
type Proto = Send<i32, Send<i32, Receive<i32, End>>>;
let session: Session<Proto> = Session::new();
let session = session.send(1);
let session = session.send(2);
let (sum, session) = session.receive_with(3);
assert_eq!(sum, 3);
session.close();
}
#[test]
fn test_type_safety_demo() {
type Proto = Send<i32, Receive<bool, End>>;
let session: Session<Proto> = Session::new();
let session = session.send(42);
let (_value, session) = session.receive_with(true);
session.close();
}
#[test]
fn test_session_computation() {
let comp = SessionComputation::<End, i32>::pure(42);
let session = Session::<End>::new();
let (result, _session): (i32, Session<End>) = comp.run(session);
assert_eq!(result, 42);
}
#[test]
fn test_calculator_protocol() {
type CalcClient = Send<i32, Send<i32, Receive<i32, End>>>;
type CalcServer = Receive<i32, Receive<i32, Send<i32, End>>>;
assert_dual::<CalcClient, CalcServer>();
fn run_client(session: Session<CalcClient>, a: i32, b: i32) -> i32 {
let session = session.send(a);
let session = session.send(b);
let (sum, session) = session.receive_with(a + b); session.close();
sum
}
fn run_server(session: Session<CalcServer>) {
let (a, session) = session.receive_with(10);
let (b, session) = session.receive_with(20);
let session = session.send(a + b);
session.close();
}
let client_session = Session::new();
let result = run_client(client_session, 10, 20);
assert_eq!(result, 30);
let server_session = Session::new();
run_server(server_session);
}
}