refactored and added helpers

This commit is contained in:
Monica Moniot
2023-07-28 12:44:44 -04:00
parent fce56bca8f
commit 829d8e5963
7 changed files with 125 additions and 34 deletions
Generated
+1 -1
View File
@@ -4,4 +4,4 @@ version = 3
[[package]]
name = "seq_ex"
version = "0.0.1"
version = "0.1.0"
+5 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "seq_ex"
version = "0.0.1"
version = "0.1.0"
authors = ["Monica Moniot"]
edition = "2021"
@@ -8,3 +8,7 @@ edition = "2021"
name = "seq_ex"
path = "src/lib.rs"
doc = true
[features]
default = ["std"]
std = []
+8 -1
View File
@@ -1,7 +1,14 @@
#![no_std]
//#![no_std]
//#![warn(missing_docs, rust_2018_idioms)]
mod transport_layer;
pub use transport_layer::*;
mod seq_queue;
pub use seq_queue::*;
mod single_thread;
pub use single_thread::*;
#[cfg(feature = "std")]
pub mod multi_thread;
+62
View File
@@ -0,0 +1,62 @@
use std::sync::{Mutex, MutexGuard};
use crate::{Error, SeqEx, SeqNo, TransportLayer};
pub struct SeqExLock<TL: TransportLayer>(pub Mutex<SeqEx<TL>>);
pub struct ReplyGuard<'a, TL: TransportLayer>(&'a SeqExLock<TL>, TL, SeqNo);
impl<'a, TL: TransportLayer> ReplyGuard<'a, TL> {
pub fn reply(self, packet_data: impl FnOnce(SeqNo, SeqNo) -> TL::SendData) {
let mut seq = self.0 .0.lock().unwrap();
let p = packet_data(seq.seq_no(), self.2);
seq.reply_raw(self.1.clone(), self.2, p);
core::mem::forget(self);
}
}
impl<'a, TL: TransportLayer> Drop for ReplyGuard<'a, TL> {
fn drop(&mut self) {
let mut seq = self.0 .0.lock().unwrap();
seq.reply_empty_raw(self.1.clone(), self.2);
}
}
impl<TL: TransportLayer> SeqExLock<TL> {
pub fn receive<P: Into<TL::RecvData>, T>(
&self,
app: TL,
seq_no: SeqNo,
reply_no: Option<SeqNo>,
packet: P,
) -> Result<(ReplyGuard<'_, TL>, P, Option<TL::SendData>), Error> {
let mut seq = self.lock();
seq.receive_raw(app.clone(), seq_no, reply_no, packet)
.map(|(reply_no, packet, data)| (ReplyGuard(self, app, reply_no), packet, data))
}
pub fn pump(&self, app: TL) -> Result<(ReplyGuard<'_, TL>, TL::RecvData, Option<TL::SendData>), Error> {
let mut seq = self.lock();
seq.pump_raw()
.map(|(reply_no, packet, data)| (ReplyGuard(self, app, reply_no), packet, data))
}
pub fn new(retry_interval: i64, initial_seq_no: SeqNo) -> Self {
Self(Mutex::new(SeqEx::new(retry_interval, initial_seq_no)))
}
pub fn send(&self, app: TL, packet_data: impl FnOnce(SeqNo) -> TL::SendData) -> bool {
let mut seq = self.lock();
let p = packet_data(seq.seq_no());
seq.send(app, p)
}
pub fn receive_ack(&self, reply_no: SeqNo) {
self.lock().receive_ack(reply_no)
}
pub fn receive_empty_reply(&self, reply_no: SeqNo) -> Option<TL::SendData> {
self.lock().receive_empty_reply(reply_no)
}
pub fn service(&self, app: TL) -> i64 {
self.lock().service(app)
}
pub fn lock(&self) -> MutexGuard<SeqEx<TL>> {
self.0.lock().unwrap()
}
}
+7 -24
View File
@@ -33,32 +33,15 @@
//!
//! ## Examples
//!
#![forbid(unsafe_code)]
//#![warn(missing_docs, rust_2018_idioms)]
const MAX_CONCURRENCY: usize = 24;
use crate::TransportLayer;
/// A 32-bit sequence number. Packets transported with SEP are expected to contain at least one
/// sequence number, and sometimes two.
/// All packets will either have a seq_no, a reply_no, or both.
pub type SeqNo = u32;
/// A trait for giving an instance of SeqEx access to the transport layer.
///
/// The implementor is free to choose how to define the generic types based on how they want to
/// manage memory.
/// It is possible through these generics to implement SeqEx to be no-alloc and zero-copy, but otherwise
/// a lot of them are most easily implemented as tuples of custom enums and Vec<u8>.
pub trait TransportLayer: Sized + Clone {
type RecvData;
type SendData;
fn time(&self) -> i64;
fn send(&self, data: &Self::SendData);
fn send_ack(&self, reply_no: SeqNo);
fn send_empty_reply(&self, reply_no: SeqNo);
}
const MAX_CONCURRENCY: usize = 24;
pub struct SeqEx<TL: TransportLayer, const SLEN: usize = 64, const RLEN: usize = 32> {
/// The interval at which packets will be resent if they have not yet been acknowledged by the
/// remote peer.
@@ -187,7 +170,7 @@ impl<TL: TransportLayer> SeqEx<TL> {
true
}
pub fn receive<P: Into<TL::RecvData>>(
pub fn receive_raw<P: Into<TL::RecvData>>(
&mut self,
app: TL,
seq_no: SeqNo,
@@ -287,7 +270,7 @@ impl<TL: TransportLayer> SeqEx<TL> {
None
}
}
pub fn pump(&mut self) -> Result<(SeqNo, TL::RecvData, Option<TL::SendData>), Error> {
pub fn pump_raw(&mut self) -> Result<(SeqNo, TL::RecvData, Option<TL::SendData>), Error> {
let next_seq_no = self.pre_recv_seq_no.wrapping_add(1);
let i = next_seq_no as usize % self.recv_window.len();
@@ -324,7 +307,7 @@ impl<TL: TransportLayer> SeqEx<TL> {
next_activity - current_time
}
pub fn reply(&mut self, app: TL, reply_no: SeqNo, packet_data: TL::SendData) {
pub fn reply_raw(&mut self, app: TL, reply_no: SeqNo, packet_data: TL::SendData) {
if self.remove_reservation(reply_no) {
let seq_no = self.next_send_seq_no;
self.next_send_seq_no = self.next_send_seq_no.wrapping_add(1);
@@ -341,7 +324,7 @@ impl<TL: TransportLayer> SeqEx<TL> {
app.send(&entry.data);
}
}
pub fn reply_empty(&mut self, app: TL, reply_no: SeqNo) {
pub fn reply_empty_raw(&mut self, app: TL, reply_no: SeqNo) {
if self.remove_reservation(reply_no) {
app.send_empty_reply(reply_no);
}
+24 -7
View File
@@ -1,20 +1,37 @@
use crate::{Error, SeqEx, SeqNo, TransportLayer};
pub struct ReplyGuard<'a, TL: TransportLayer>(&'a mut SeqEx<TL>, TL, SeqNo);
//impl<'a, TL: TransportLayer> ReplyGuard<'a, TL> {
// pub fn reply_no(&self) {
// }
//}
impl<'a, TL: TransportLayer> ReplyGuard<'a, TL> {
pub fn seq_no(&self) -> SeqNo {
self.0.seq_no()
}
pub fn reply_no(&self) -> SeqNo {
self.2
}
pub fn reply(self, packet_data: TL::SendData) {
self.0.reply_raw(self.1.clone(), self.2, packet_data);
core::mem::forget(self);
}
}
impl<'a, TL: TransportLayer> Drop for ReplyGuard<'a, TL> {
fn drop(&mut self) {
self.0.reply_empty_raw(self.1.clone(), self.2)
}
}
impl<TL: TransportLayer> SeqEx<TL> {
pub fn receive_guarded<P: Into<TL::RecvData>, T>(
pub fn receive<P: Into<TL::RecvData>, T>(
&mut self,
app: TL,
seq_no: SeqNo,
reply_no: Option<SeqNo>,
packet: P,
) -> Result<(ReplyGuard<'_, TL>, P, Option<TL::SendData>), Error> {
self.receive(app.clone(), seq_no, reply_no, packet).map(|(reply_no, packet, data)| (ReplyGuard(self, app, reply_no), packet, data))
self.receive_raw(app.clone(), seq_no, reply_no, packet)
.map(|(reply_no, packet, data)| (ReplyGuard(self, app, reply_no), packet, data))
}
pub fn pump(&mut self, app: TL) -> Result<(ReplyGuard<'_, TL>, TL::RecvData, Option<TL::SendData>), Error> {
self.pump_raw()
.map(|(reply_no, packet, data)| (ReplyGuard(self, app, reply_no), packet, data))
}
}
+18
View File
@@ -0,0 +1,18 @@
use crate::SeqNo;
/// A trait for giving an instance of SeqEx access to the transport layer.
///
/// The implementor is free to choose how to define the generic types based on how they want to
/// manage memory.
/// It is possible through these generics to implement SeqEx to be no-alloc and zero-copy, but otherwise
/// a lot of them are most easily implemented as tuples of custom enums and Vec<u8>.
pub trait TransportLayer: Sized + Clone {
type RecvData;
type SendData;
fn time(&self) -> i64;
fn send(&self, data: &Self::SendData);
fn send_ack(&self, reply_no: SeqNo);
fn send_empty_reply(&self, reply_no: SeqNo);
}