mirror of
https://github.com/zerotier/sequential-exchange.git
synced 2026-05-22 16:28:28 -07:00
refactored and added helpers
This commit is contained in:
Generated
+1
-1
@@ -4,4 +4,4 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "seq_ex"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
|
||||
+5
-1
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user