use core::marker::PhantomData;
pub trait Participant {
type In<'message>;
type Out<'message>;
}
pub enum NoInput {}
pub enum NoOutput {}
pub trait TransportTo<Destination: Participant> {
type Outcome<'transport, 'message>
where
Self: 'transport;
#[must_use = "transport outcomes must be routed or settled"]
fn send<'transport, 'message>(
&'transport mut self,
input: Destination::In<'message>,
) -> Self::Outcome<'transport, 'message>;
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use = "received outputs, quiescence, backpressure, and failures must be handled"]
pub enum ReceiveFromOutcome<Output, Rejected, Failure> {
Received { output: Output },
Progressed,
Quiescent,
Backpressured { rejected: Rejected },
Failed { failure: Failure },
}
pub trait TransportFrom<Source: Participant> {
type IncomingMessage<'message>
where
Self: 'message;
type Failure;
fn receive_from<'message>(
&'message mut self,
incoming_message: Self::IncomingMessage<'message>,
) -> ReceiveFromOutcome<Source::Out<'message>, Self::IncomingMessage<'message>, Self::Failure>;
}
pub trait DuplexFitting<ConnectedParticipant: Participant> {
type Incoming<'fitting>: TransportFrom<ConnectedParticipant>
where
Self: 'fitting;
type Outgoing<'fitting>: TransportTo<ConnectedParticipant>
where
Self: 'fitting;
fn split<'fitting>(&'fitting mut self) -> (Self::Incoming<'fitting>, Self::Outgoing<'fitting>);
}
pub trait MessageFamily {
type Message<'message>;
}
pub struct ParticipantIn<Selected: Participant>(PhantomData<fn() -> Selected>);
impl<Selected: Participant> MessageFamily for ParticipantIn<Selected> {
type Message<'message> = Selected::In<'message>;
}
pub struct ParticipantOut<Selected: Participant>(PhantomData<fn() -> Selected>);
impl<Selected: Participant> MessageFamily for ParticipantOut<Selected> {
type Message<'message> = Selected::Out<'message>;
}
pub struct OwnedMessage<Message>(PhantomData<fn() -> Message>);
impl<Message> MessageFamily for OwnedMessage<Message> {
type Message<'message> = Message;
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct EncodedByteCount(usize);
impl EncodedByteCount {
pub const fn new(value: usize) -> Self {
Self(value)
}
pub const fn get(self) -> usize {
self.0
}
}
pub trait MessageEncoder {
type Message<'message>: ?Sized;
type Error;
fn encode<'message>(
&self,
message: &Self::Message<'message>,
destination: &mut [u8],
) -> Result<EncodedByteCount, Self::Error>;
}
pub trait MessageDecoder {
type Message<'frame>;
type Error;
fn decode<'frame>(&self, frame: &'frame mut [u8])
-> Result<Self::Message<'frame>, Self::Error>;
}
#[cfg(test)]
mod tests {
use super::*;
struct Participant;
impl super::Participant for Participant {
type In<'message> = &'message str;
type Out<'message> = &'message [u8];
}
struct Source;
impl super::Participant for Source {
type In<'message> = NoInput;
type Out<'message> = &'message str;
}
struct Sink;
impl super::Participant for Sink {
type In<'message> = &'message str;
type Out<'message> = NoOutput;
}
struct BorrowedInline;
impl TransportTo<Participant> for BorrowedInline {
type Outcome<'transport, 'message>
= &'message str
where
Self: 'transport;
fn send<'transport, 'message>(
&'transport mut self,
input: <Participant as super::Participant>::In<'message>,
) -> Self::Outcome<'transport, 'message> {
input
}
}
#[test]
fn participant_message_families_include_uninhabited_directions() {
fn assert_message_families<Selected>()
where
Selected: super::Participant,
for<'message> ParticipantIn<Selected>:
MessageFamily<Message<'message> = Selected::In<'message>>,
for<'message> ParticipantOut<Selected>:
MessageFamily<Message<'message> = Selected::Out<'message>>,
{
}
assert_message_families::<Participant>();
assert_message_families::<Source>();
assert_message_families::<Sink>();
}
#[test]
fn encoded_byte_counts_preserve_their_value() {
assert_eq!(EncodedByteCount::new(7).get(), 7);
}
#[test]
fn transports_without_internal_steps_preserve_borrowed_delivery() {
let mut transport = BorrowedInline;
assert_eq!(
TransportTo::<Participant>::send(&mut transport, "borrowed"),
"borrowed"
);
}
}