| use alloc::collections::VecDeque; |
| use alloc::vec::Vec; |
| |
| use crate::phy::{self, Device, DeviceCapabilities, Medium}; |
| use crate::time::Instant; |
| |
| /// A loopback device. |
| #[derive(Debug)] |
| pub struct Loopback { |
| pub(crate) queue: VecDeque<Vec<u8>>, |
| medium: Medium, |
| } |
| |
| #[allow(clippy::new_without_default)] |
| impl Loopback { |
| /// Creates a loopback device. |
| /// |
| /// Every packet transmitted through this device will be received through it |
| /// in FIFO order. |
| pub fn new(medium: Medium) -> Loopback { |
| Loopback { |
| queue: VecDeque::new(), |
| medium, |
| } |
| } |
| } |
| |
| impl Device for Loopback { |
| type RxToken<'a> = RxToken; |
| type TxToken<'a> = TxToken<'a>; |
| |
| fn capabilities(&self) -> DeviceCapabilities { |
| DeviceCapabilities { |
| max_transmission_unit: 65535, |
| medium: self.medium, |
| ..DeviceCapabilities::default() |
| } |
| } |
| |
| fn receive(&mut self, _timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { |
| self.queue.pop_front().map(move |buffer| { |
| let rx = RxToken { buffer }; |
| let tx = TxToken { |
| queue: &mut self.queue, |
| }; |
| (rx, tx) |
| }) |
| } |
| |
| fn transmit(&mut self, _timestamp: Instant) -> Option<Self::TxToken<'_>> { |
| Some(TxToken { |
| queue: &mut self.queue, |
| }) |
| } |
| } |
| |
| #[doc(hidden)] |
| pub struct RxToken { |
| buffer: Vec<u8>, |
| } |
| |
| impl phy::RxToken for RxToken { |
| fn consume<R, F>(mut self, f: F) -> R |
| where |
| F: FnOnce(&mut [u8]) -> R, |
| { |
| f(&mut self.buffer) |
| } |
| } |
| |
| #[doc(hidden)] |
| #[derive(Debug)] |
| pub struct TxToken<'a> { |
| queue: &'a mut VecDeque<Vec<u8>>, |
| } |
| |
| impl<'a> phy::TxToken for TxToken<'a> { |
| fn consume<R, F>(self, len: usize, f: F) -> R |
| where |
| F: FnOnce(&mut [u8]) -> R, |
| { |
| let mut buffer = Vec::new(); |
| buffer.resize(len, 0); |
| let result = f(&mut buffer); |
| self.queue.push_back(buffer); |
| result |
| } |
| } |