Factor out the `RingBuffer` container.
parent
59fc0c0358
commit
c1c4ed68c5
|
@ -101,6 +101,7 @@ macro_rules! net_trace_enabled {
|
|||
|
||||
use core::fmt;
|
||||
|
||||
pub mod storage;
|
||||
pub mod phy;
|
||||
pub mod wire;
|
||||
pub mod iface;
|
||||
|
|
|
@ -5,6 +5,7 @@ use phy::DeviceLimits;
|
|||
use wire::{IpProtocol, IpEndpoint};
|
||||
use wire::{UdpPacket, UdpRepr};
|
||||
use socket::{Socket, IpRepr, IpPayload};
|
||||
use storage::{Resettable, RingBuffer};
|
||||
|
||||
/// A buffered UDP packet.
|
||||
#[derive(Debug)]
|
||||
|
@ -14,6 +15,13 @@ pub struct PacketBuffer<'a> {
|
|||
payload: Managed<'a, [u8]>
|
||||
}
|
||||
|
||||
impl<'a> Resettable for PacketBuffer<'a> {
|
||||
fn reset(&mut self) {
|
||||
self.endpoint = Default::default();
|
||||
self.size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PacketBuffer<'a> {
|
||||
/// Create a buffered packet.
|
||||
pub fn new<T>(payload: T) -> PacketBuffer<'a>
|
||||
|
@ -35,74 +43,7 @@ impl<'a> PacketBuffer<'a> {
|
|||
}
|
||||
|
||||
/// An UDP packet ring buffer.
|
||||
#[derive(Debug)]
|
||||
pub struct SocketBuffer<'a, 'b: 'a> {
|
||||
storage: Managed<'a, [PacketBuffer<'b>]>,
|
||||
read_at: usize,
|
||||
length: usize
|
||||
}
|
||||
|
||||
impl<'a, 'b> SocketBuffer<'a, 'b> {
|
||||
/// Create a packet buffer with the given storage.
|
||||
pub fn new<T>(storage: T) -> SocketBuffer<'a, 'b>
|
||||
where T: Into<Managed<'a, [PacketBuffer<'b>]>> {
|
||||
let mut storage = storage.into();
|
||||
for elem in storage.iter_mut() {
|
||||
elem.endpoint = Default::default();
|
||||
elem.size = 0;
|
||||
}
|
||||
|
||||
SocketBuffer {
|
||||
storage: storage,
|
||||
read_at: 0,
|
||||
length: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn mask(&self, index: usize) -> usize {
|
||||
index % self.storage.len()
|
||||
}
|
||||
|
||||
fn incr(&self, index: usize) -> usize {
|
||||
self.mask(index + 1)
|
||||
}
|
||||
|
||||
/// Query whether the buffer is empty.
|
||||
pub fn empty(&self) -> bool {
|
||||
self.length == 0
|
||||
}
|
||||
|
||||
/// Query whether the buffer is full.
|
||||
pub fn full(&self) -> bool {
|
||||
self.length == self.storage.len()
|
||||
}
|
||||
|
||||
/// Enqueue an element into the buffer, and return a pointer to it, or return
|
||||
/// `Err(())` if the buffer is full.
|
||||
pub fn enqueue(&mut self) -> Result<&mut PacketBuffer<'b>, ()> {
|
||||
if self.full() {
|
||||
Err(())
|
||||
} else {
|
||||
let index = self.mask(self.read_at + self.length);
|
||||
let result = &mut self.storage[index];
|
||||
self.length += 1;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeue an element from the buffer, and return a pointer to it, or return
|
||||
/// `Err(())` if the buffer is empty.
|
||||
pub fn dequeue(&mut self) -> Result<&PacketBuffer<'b>, ()> {
|
||||
if self.empty() {
|
||||
Err(())
|
||||
} else {
|
||||
self.length -= 1;
|
||||
let result = &self.storage[self.read_at];
|
||||
self.read_at = self.incr(self.read_at);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type SocketBuffer<'a, 'b : 'a> = RingBuffer<'a, PacketBuffer<'b>>;
|
||||
|
||||
/// An User Datagram Protocol socket.
|
||||
///
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
//! Specialized containers.
|
||||
//!
|
||||
//! The `storage` module provides containers for use in other modules.
|
||||
//! The containers support both pre-allocated memory, without the `std`
|
||||
//! and `collections` crates being available, and heap-allocated memory.
|
||||
|
||||
mod ring_buffer;
|
||||
|
||||
pub use self::ring_buffer::RingBuffer;
|
||||
|
||||
/// A trait for setting a value to a known state.
|
||||
///
|
||||
/// In-place analog of Default.
|
||||
pub trait Resettable {
|
||||
fn reset(&mut self);
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
use managed::Managed;
|
||||
use storage::Resettable;
|
||||
|
||||
/// A ring buffer.
|
||||
#[derive(Debug)]
|
||||
pub struct RingBuffer<'a, T: 'a> {
|
||||
storage: Managed<'a, [T]>,
|
||||
read_at: usize,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: 'a> RingBuffer<'a, T> {
|
||||
/// Create a ring buffer with the given storage.
|
||||
///
|
||||
/// During creation, every element in `storage` is reset.
|
||||
pub fn new<S>(storage: S) -> RingBuffer<'a, T>
|
||||
where S: Into<Managed<'a, [T]>>, T: Resettable,
|
||||
{
|
||||
let mut storage = storage.into();
|
||||
for elem in storage.iter_mut() {
|
||||
elem.reset();
|
||||
}
|
||||
|
||||
RingBuffer {
|
||||
storage: storage,
|
||||
read_at: 0,
|
||||
length: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn mask(&self, index: usize) -> usize {
|
||||
index % self.storage.len()
|
||||
}
|
||||
|
||||
fn incr(&self, index: usize) -> usize {
|
||||
self.mask(index + 1)
|
||||
}
|
||||
|
||||
/// Query whether the buffer is empty.
|
||||
pub fn empty(&self) -> bool {
|
||||
self.length == 0
|
||||
}
|
||||
|
||||
/// Query whether the buffer is full.
|
||||
pub fn full(&self) -> bool {
|
||||
self.length == self.storage.len()
|
||||
}
|
||||
|
||||
/// Enqueue an element into the buffer, and return a pointer to it, or return
|
||||
/// `Err(())` if the buffer is full.
|
||||
pub fn enqueue(&mut self) -> Result<&mut T, ()> {
|
||||
if self.full() {
|
||||
Err(())
|
||||
} else {
|
||||
let index = self.mask(self.read_at + self.length);
|
||||
let result = &mut self.storage[index];
|
||||
self.length += 1;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeue an element from the buffer, and return a pointer to it, or return
|
||||
/// `Err(())` if the buffer is empty.
|
||||
pub fn dequeue(&mut self) -> Result<&T, ()> {
|
||||
if self.empty() {
|
||||
Err(())
|
||||
} else {
|
||||
self.length -= 1;
|
||||
let result = &self.storage[self.read_at];
|
||||
self.read_at = self.incr(self.read_at);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dequeue an element from the buffer, and return a mutable reference to it, or return
|
||||
/// `Err(())` if the buffer is empty.
|
||||
pub fn dequeue_mut(&mut self) -> Result<&mut T, ()> {
|
||||
if self.empty() {
|
||||
Err(())
|
||||
} else {
|
||||
self.length -= 1;
|
||||
let read_at = self.read_at;
|
||||
self.read_at = self.incr(self.read_at);
|
||||
let result = &mut self.storage[read_at];
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
impl Resettable for usize {
|
||||
fn reset(&mut self) {
|
||||
*self = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_buffer() {
|
||||
const TEST_BUFFER_SIZE: usize = 5;
|
||||
let mut storage = vec![];
|
||||
for i in 0..TEST_BUFFER_SIZE {
|
||||
storage.push(i + 10);
|
||||
}
|
||||
|
||||
let mut ring_buffer = RingBuffer::new(&mut storage[..]);
|
||||
assert!(ring_buffer.empty());
|
||||
assert!(!ring_buffer.full());
|
||||
assert_eq!(ring_buffer.dequeue(), Err(()));
|
||||
ring_buffer.enqueue().unwrap();
|
||||
assert!(!ring_buffer.empty());
|
||||
assert!(!ring_buffer.full());
|
||||
for i in 1..TEST_BUFFER_SIZE {
|
||||
*ring_buffer.enqueue().unwrap() = i;
|
||||
assert!(!ring_buffer.empty());
|
||||
}
|
||||
assert!(ring_buffer.full());
|
||||
assert_eq!(ring_buffer.enqueue(), Err(()));
|
||||
|
||||
for i in 0..TEST_BUFFER_SIZE {
|
||||
assert_eq!(*ring_buffer.dequeue().unwrap(), i);
|
||||
assert!(!ring_buffer.full());
|
||||
}
|
||||
assert_eq!(ring_buffer.dequeue(), Err(()));
|
||||
assert!(ring_buffer.empty());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue