diff --git a/src/lib.rs b/src/lib.rs index 927256b..4161e83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(feature = "alloc", feature(alloc))] +#![cfg_attr(feature = "collections", feature(collections))] #![no_std] //! The _smoltcp_ library is built in a layered structure, with the layers corresponding @@ -76,6 +77,9 @@ extern crate std; extern crate libc; #[cfg(feature = "alloc")] extern crate alloc; +#[allow(deprecated)] +#[cfg(feature = "collections")] +extern crate collections; #[cfg(any(test, feature = "log"))] #[macro_use(trace, log, log_enabled)] extern crate log; diff --git a/src/phy/loopback.rs b/src/phy/loopback.rs new file mode 100644 index 0000000..bce6598 --- /dev/null +++ b/src/phy/loopback.rs @@ -0,0 +1,72 @@ +use core::mem::swap; +use core::cell::RefCell; +#[cfg(feature = "std")] +use std::rc::Rc; +#[cfg(feature = "alloc")] +use alloc::rc::Rc; +#[cfg(feature = "std")] +use std::vec::Vec; +#[cfg(feature = "std")] +use std::collections::VecDeque; +#[cfg(feature = "collections")] +use collections::{Vec, VecDeque}; + +use Error; +use super::Device; + +/// A loopback interface. +#[derive(Debug)] +pub struct LoopbackInterface(Rc>>>); + +impl LoopbackInterface { + /// Creates a loopback interface. + /// + /// Every packet transmitted through this interface will be received through it + /// in FIFO order. + pub fn new() -> LoopbackInterface { + LoopbackInterface(Rc::new(RefCell::new(VecDeque::new()))) + } +} + +impl Device for LoopbackInterface { + type RxBuffer = Vec; + type TxBuffer = TxBuffer; + + fn receive(&mut self) -> Result { + match self.0.borrow_mut().pop_front() { + Some(packet) => Ok(packet), + None => Err(Error::Exhausted) + } + } + + fn transmit(&mut self, length: usize) -> Result { + let mut buffer = Vec::new(); + buffer.resize(length, 0); + Ok(TxBuffer { + queue: self.0.clone(), + buffer: buffer + }) + } +} + +#[doc(hidden)] +pub struct TxBuffer { + queue: Rc>>>, + buffer: Vec +} + +impl AsRef<[u8]> for TxBuffer { + fn as_ref(&self) -> &[u8] { self.buffer.as_ref() } +} + +impl AsMut<[u8]> for TxBuffer { + fn as_mut(&mut self) -> &mut [u8] { self.buffer.as_mut() } +} + +impl Drop for TxBuffer { + fn drop(&mut self) { + let mut buffer = Vec::new(); + swap(&mut buffer, &mut self.buffer); + self.queue.borrow_mut().push_back(buffer) + } +} diff --git a/src/phy/mod.rs b/src/phy/mod.rs index 26fa160..04ef6ef 100644 --- a/src/phy/mod.rs +++ b/src/phy/mod.rs @@ -103,11 +103,13 @@ impl Drop for EthernetTxBuffer { use Error; -#[cfg(any(feature = "raw_socket", feature="tap_interface"))] +#[cfg(any(feature = "raw_socket", feature = "tap_interface"))] mod sys; mod tracer; mod fault_injector; +#[cfg(any(feature = "std", feature = "collections"))] +mod loopback; #[cfg(feature = "raw_socket")] mod raw_socket; #[cfg(all(feature = "tap_interface", target_os = "linux"))] @@ -115,6 +117,8 @@ mod tap_interface; pub use self::tracer::Tracer; pub use self::fault_injector::FaultInjector; +#[cfg(any(feature = "std", feature = "collections"))] +pub use self::loopback::LoopbackInterface; #[cfg(any(feature = "raw_socket"))] pub use self::raw_socket::RawSocket; #[cfg(all(feature = "tap_interface", target_os = "linux"))] @@ -158,7 +162,9 @@ pub trait Device { type TxBuffer: AsRef<[u8]> + AsMut<[u8]>; /// Get a description of device limitations. - fn limits(&self) -> DeviceLimits; + fn limits(&self) -> DeviceLimits { + DeviceLimits::default() + } /// Receive a frame. ///