#![doc=concat!("```\n",include_str!("net/net_doc_example.rs"),"```\n`")]
use crate::{
id::Id,
node_id::NodeId,
simulator::{Simulator, SimulatorHandle},
time::sleep_until,
};
use either::Either::{self, Left};
use futures::future::ready;
use futures_intrusive::channel::LocalChannel;
use std::{
any::{Any, type_name},
collections::{HashMap, hash_map::Entry},
fmt::Display,
io::Error,
pin::Pin,
rc::Rc,
time::Instant,
};
use std::{marker::PhantomData, time::Duration};
use typeid::ConstTypeId;
pub trait Packet: Any {
#[doc(hidden)]
fn packet_type_id(&self) -> ConstTypeId {
ConstTypeId::of::<Self>()
}
#[allow(unused_variables)]
fn service_level(&self, src: Addr, dst: Addr) -> ServiceLevel {
ServiceLevel {
ordering: None,
allow_drop: true,
allow_multiple: false,
}
}
fn clone_packet(&self) -> Self
where
Self: Sized,
{
unimplemented!()
}
}
pub struct ServiceLevel {
pub ordering: Option<OrderingKey>,
pub allow_drop: bool,
pub allow_multiple: bool,
}
#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct OrderingKey {
ty: Option<ConstTypeId>,
dst_addr: Option<Addr>,
}
impl OrderingKey {
pub fn empty() -> Self {
OrderingKey {
ty: None,
dst_addr: None,
}
}
pub fn with_dst_addr(mut self, addr: Addr) -> Self {
assert!(self.dst_addr.replace(addr).is_none());
self
}
pub fn with_type<P: Packet>(mut self) -> Self {
assert!(self.ty.replace(ConstTypeId::of::<P>()).is_none());
self
}
}
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Addr {
pub node: NodeId,
pub port: Id,
}
pub type SendFunction = Box<dyn FnMut(&mut Inboxes, PacketRc) -> SendFunctionOutput>;
#[doc(hidden)]
pub type SendFunctionOutput =
Either<Result<(), Error>, Pin<Box<dyn Future<Output = Result<(), Error>>>>>;
pub fn perfect_connectivity(latency: Duration) -> SendFunction {
Box::new(move |queues, packet| {
queues.enqueue_packet(Instant::now() + latency, packet);
Left(Ok(()))
})
}
pub struct PacketHeader {
src: Addr,
dst: Addr,
ty: ConstTypeId,
service_level: ServiceLevel,
}
struct WrappedPacketImpl<T> {
pub header: PacketHeader,
packet: T,
}
#[derive(Clone)]
pub struct PacketRc(Rc<dyn WrappedPacketTrait>);
impl PacketRc {
pub fn new<T: Packet>(src: Addr, dst: Addr, packet: T) -> Self {
PacketRc(Rc::new(WrappedPacketImpl {
header: PacketHeader {
src,
dst,
ty: packet.packet_type_id(),
service_level: packet.service_level(src, dst),
},
packet,
}))
}
pub fn header(&self) -> &PacketHeader {
self.0.project().0
}
pub fn packet(&self) -> &dyn Packet {
self.0.project().1
}
}
trait WrappedPacketTrait: Any {
fn project(&self) -> (&PacketHeader, &dyn Packet);
}
impl<T: Packet> WrappedPacketTrait for WrappedPacketImpl<T> {
fn project(&self) -> (&PacketHeader, &dyn Packet) {
(&self.header, &self.packet)
}
}
impl PacketHeader {
pub fn src(&self) -> Addr {
self.src
}
pub fn dst(&self) -> Addr {
self.dst
}
pub fn service_level(&self) -> &ServiceLevel {
&self.service_level
}
}
pub struct Net {
send_function: SendFunction,
inboxes: Inboxes,
}
type Inbox = LocalChannel<Result<PacketRc, Error>, [Result<PacketRc, Error>; 8]>;
impl Simulator for Net {
fn start_node(&mut self) {
let node = NodeId::current();
for (key, inbox) in &self.inboxes.0 {
if key.0.node == node {
while inbox.try_receive().is_ok() {}
}
}
}
fn create_node(&mut self) {
self.start_node();
}
}
pub struct Socket<T> {
simulator: SimulatorHandle<Net>,
inbox: Rc<Inbox>,
local_addr: Addr,
_p: PhantomData<fn(T) -> T>,
}
pub type SocketReceiveFuture<T: Packet> = impl Future<Output = Result<(T, Addr), Error>>;
pub type SocketSendFuture = impl Future<Output = Result<(), Error>>;
pub type SendFuture = impl Future<Output = Result<(), Error>>;
#[derive(Debug)]
pub struct AddrInUseError {
addr: Addr,
ty: &'static str,
}
impl Display for AddrInUseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let AddrInUseError { addr, ty } = self;
write!(f, "socket exists for address {addr:?}, type {ty:?}")
}
}
impl std::error::Error for AddrInUseError {}
impl From<AddrInUseError> for Error {
fn from(value: AddrInUseError) -> Self {
Error::new(std::io::ErrorKind::AddrInUse, value)
}
}
impl<T: Packet> Socket<T> {
pub fn open(port: Id) -> Result<Self, AddrInUseError> {
let addr = Addr {
port,
node: NodeId::current(),
};
let simulator = SimulatorHandle::<Net>::get();
let ret =
simulator.with(
|net| match net.inboxes.0.entry((addr, ConstTypeId::of::<T>())) {
Entry::Occupied(_) => Err(AddrInUseError {
addr,
ty: type_name::<T>(),
}),
Entry::Vacant(x) => {
let inbox = Rc::new(Inbox::new());
x.insert(inbox.clone());
Ok(Socket {
inbox,
_p: PhantomData,
simulator: simulator.clone(),
local_addr: addr,
})
}
},
)?;
Ok(ret)
}
pub fn local_port(&self) -> Id {
self.local_addr.port
}
#[define_opaque(SocketSendFuture)]
pub fn send<U: Packet>(&self, dst: Addr, packet: U) -> SocketSendFuture {
self.simulator
.with(|net| net.send_wrapped(PacketRc::new(self.local_addr, dst, packet)))
}
#[define_opaque(SocketReceiveFuture)]
pub fn receive(&self) -> SocketReceiveFuture<T> {
let inbox = self.inbox.clone();
async move {
inbox.receive().await.unwrap().map(|wrapped| {
let wrapped = (wrapped.0 as Rc<dyn Any>)
.downcast::<WrappedPacketImpl<T>>()
.unwrap();
let addr = wrapped.header.src;
(
match Rc::try_unwrap(wrapped) {
Ok(x) => x.packet,
Err(x) => x.packet.clone_packet(),
},
addr,
)
})
}
}
}
impl<T> Drop for Socket<T> {
fn drop(&mut self) {
self.simulator.with(|net| {
let removed = net
.inboxes
.0
.remove(&(self.local_addr, ConstTypeId::of::<T>()));
debug_assert!(removed.is_some_and(|x| Rc::ptr_eq(&x, &self.inbox)));
})
}
}
impl Net {
pub fn new(send_function: SendFunction) -> Self {
Self {
send_function,
inboxes: Inboxes(HashMap::new()),
}
}
#[define_opaque(SendFuture)]
fn send_wrapped(&mut self, packet: PacketRc) -> SendFuture {
assert!(packet.header().src.node == NodeId::current());
(self.send_function)(&mut self.inboxes, packet).map_left(ready)
}
pub fn send<T: Packet>(&mut self, src_port: Id, dst: Addr, packet: T) -> SendFuture {
self.send_wrapped(PacketRc::new(
Addr {
port: src_port,
node: NodeId::current(),
},
dst,
packet,
))
}
pub fn inboxes(&mut self) -> &mut Inboxes {
&mut self.inboxes
}
}
pub struct Inboxes(HashMap<(Addr, ConstTypeId), Rc<Inbox>>);
impl Inboxes {
pub fn enqueue_packet(&mut self, at: Instant, msg: PacketRc) {
let header = msg.header();
let key = (header.dst, header.ty);
Self::enqueue(at, key, Ok(msg));
}
pub fn enqueue_error(&mut self, at: Instant, dst: Addr, ty: ConstTypeId, error: Error) {
Self::enqueue(at, (dst, ty), Err(error));
}
fn enqueue(at: Instant, key: (Addr, ConstTypeId), msg: Result<PacketRc, Error>) {
NodeId::INIT.spawn(async move {
sleep_until(at).await;
SimulatorHandle::<Net>::get().with(|net| {
if let Some(inbox) = net.inboxes.0.get(&key) {
inbox.try_send(msg).ok();
}
})
});
}
}