use bytes::{Bytes, BytesMut};
use smoltcp::{
phy::{ChecksumCapabilities, DeviceCapabilities, Medium},
time::Instant,
};
pub struct Pipe {
pub tx: flume::Sender<Bytes>,
pub rx: flume::Receiver<Bytes>,
}
impl Pipe {
pub fn unbounded() -> (Pipe, Pipe) {
let (tx1, rx1) = flume::unbounded();
let (tx2, rx2) = flume::unbounded();
(Pipe { tx: tx1, rx: rx2 }, Pipe { tx: tx2, rx: rx1 })
}
pub fn bounded(limit: usize) -> (Pipe, Pipe) {
let (tx1, rx1) = flume::bounded(limit);
let (tx2, rx2) = flume::bounded(limit);
(Pipe { tx: tx1, rx: rx2 }, Pipe { tx: tx2, rx: rx1 })
}
}
pub struct TxToken(flume::Sender<Bytes>);
impl smoltcp::phy::TxToken for TxToken {
fn consume<R, F>(self, len: usize, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
let mut b = BytesMut::zeroed(len);
let ret = f(&mut b);
if self.0.send(b.freeze()).is_err() {
tracing::warn!("remote end of dropped on send");
}
ret
}
}
pub struct RxToken(Bytes);
impl smoltcp::phy::RxToken for RxToken {
fn consume<R, F>(self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(&self.0)
}
}
pub struct PipeDev {
pub pipe: Pipe,
pub medium: Medium,
pub mtu: usize,
}
impl smoltcp::phy::Device for PipeDev {
type RxToken<'a>
= RxToken
where
Self: 'a;
type TxToken<'a>
= TxToken
where
Self: 'a;
fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
let tx = self.transmit(timestamp)?;
let b = self.pipe.rx.try_recv().ok()?;
Some((RxToken(b), tx))
}
fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> {
let sender = (!self.pipe.tx.is_disconnected()).then(|| self.pipe.tx.clone())?;
Some(TxToken(sender))
}
fn capabilities(&self) -> DeviceCapabilities {
let mut caps = DeviceCapabilities::default();
caps.max_transmission_unit = self.mtu;
caps.medium = self.medium;
caps.checksum = ChecksumCapabilities::ignored();
caps
}
}