finished tokio support

This commit is contained in:
Monica Moniot
2023-08-21 11:10:42 -04:00
parent 9005ca760f
commit d2205fd8c1
11 changed files with 1246 additions and 915 deletions
Generated
+296
View File
@@ -2,6 +2,63 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "addr2line"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "backtrace"
version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
[[package]]
name = "cc"
version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -19,18 +76,114 @@ dependencies = [
"wasi",
]
[[package]]
name = "gimli"
version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hermit-abi"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
[[package]]
name = "libc"
version = "0.2.147"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
[[package]]
name = "lock_api"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [
"libc",
"wasi",
"windows-sys",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "object"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
dependencies = [
"memchr",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
name = "pin-project-lite"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
[[package]]
name = "proc-macro2"
version = "1.0.66"
@@ -58,6 +211,27 @@ dependencies = [
"getrandom",
]
[[package]]
name = "redox_syscall"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "seq_ex"
version = "0.1.0"
@@ -65,6 +239,7 @@ dependencies = [
"rand_core",
"serde",
"serde_cbor",
"tokio",
]
[[package]]
@@ -97,6 +272,31 @@ dependencies = [
"syn",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
[[package]]
name = "socket2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "syn"
version = "2.0.28"
@@ -108,6 +308,36 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "tokio"
version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [
"backtrace",
"bytes",
"libc",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.11"
@@ -119,3 +349,69 @@ name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058"
[[package]]
name = "windows_i686_gnu"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd"
[[package]]
name = "windows_i686_msvc"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9"
+4 -2
View File
@@ -10,13 +10,15 @@ path = "src/lib.rs"
doc = true
[features]
default = ["std", "serde"]
default = ["serde", "tokio"]
tokio = ["std", "dep:tokio"]
std = []
[dependencies]
serde = { version = "1.0.183", default-features = false, features = ["derive"], optional = true }
#tokio = { version = "1.31.0", default-features = false, features = ["sync", "rt", "time", "macros"], optional = true }
tokio = { version = "1.31.0", default-features = false, features = ["sync", "time"], optional = true }
[dev-dependencies]
rand_core = { version = "0.6.4", features = ["getrandom"]}
serde_cbor = { version = "0.11.2" }
tokio = { version = "1.31.0", default-features = false, features = ["full"] }
-250
View File
@@ -1,250 +0,0 @@
use std::{
collections::HashMap,
fs::{read_dir, File},
io::{Read, Write},
ops::Deref,
path::PathBuf,
sync::{
mpsc::{channel, Receiver, Sender},
Arc, RwLock,
},
thread,
time::{Duration, Instant},
};
use rand_core::{OsRng, RngCore};
use seq_ex::{SeqNo, TransportLayer, Packet};
use serde::{Deserialize, Serialize};
/// serde_cbor minimal format is both smaller and faster than default format.
/// The overhead is ~33% faster.
fn to_writer_minimal(value: &impl serde::Serialize, w: &mut impl serde_cbor::ser::Write) -> serde_cbor::Result<()> {
value.serialize(&mut serde_cbor::Serializer::new(w).packed_format().legacy_enums())?;
Ok(())
}
fn drop_packet() -> bool {
OsRng.next_u32() >= (u32::MAX / 4 * 3)
}
const FILE_CHUNK_SIZE: usize = 1000;
const DOWNLOAD_LIMIT: u64 = 1000000;
#[derive(Debug)]
enum SendData {
RequestFile { filename: String },
ConfirmFileSize { file: File },
ConfirmDownload,
FileDownload,
ReadDir { download_missing: bool },
DirContents,
}
#[derive(Serialize, Deserialize)]
enum Payload<'a> {
RequestFile { filename: &'a str },
ConfirmFileSize { filesize: u64 },
ConfirmDownload { fileid: u64 },
FileDownload { fileid: u64, file_chunk: &'a [u8] },
FileDownloadComplete { fileid: u64 },
ReadDir,
DirContents { filenames: Vec<&'a str> },
}
const PACKET_TYPE_PAYLOAD: u8 = 0;
const PACKET_TYPE_LOCK_PAYLOAD: u8 = 1;
const PACKET_TYPE_REPLY: u8 = 2;
const PACKET_TYPE_LOCK_REPLY: u8 = 3;
const PACKET_TYPE_ACK: u8 = 4;
fn create_payload(seq_no: SeqNo, packet: &Payload<'_>) -> Vec<u8> {
let mut p = vec![PACKET_TYPE_PAYLOAD];
p.extend(&seq_no.to_be_bytes());
to_writer_minimal(packet, &mut p);
p
}
fn create_reply(seq_no: SeqNo, reply_no: SeqNo, packet: &Payload<'_>) -> Vec<u8> {
let mut p = vec![PACKET_TYPE_REPLY];
p.extend(&seq_no.to_be_bytes());
p.extend(&reply_no.to_be_bytes());
to_writer_minimal(packet, &mut p);
p
}
macro_rules! reply {
($guard:expr, $send_data:expr, $packet: expr) => {
$guard.reply_with(|seq_no, reply_no| ($send_data, create_reply(seq_no, reply_no, &$packet)))
};
}
macro_rules! send {
($peer:expr, $trans:expr, $send_data:expr, $packet: expr) => {
$peer.seqex.send_with($trans, |seq_no| ($send_data, create_payload(seq_no, &$packet)))
};
}
type SeqEx = seq_ex::sync::SeqExSync<(SendData, Vec<u8>), Vec<u8>>;
type ReplyGuard<'a> = seq_ex::sync::ReplyGuard<'a, &'a Transport, (SendData, Vec<u8>), Vec<u8>>;
#[derive(Clone)]
struct Transport {
sender: Sender<Vec<u8>>,
time: Instant,
}
struct Peer {
downloads_in_progress: HashMap<u64, File>,
home_dir: PathBuf,
seqex: SeqEx,
}
impl TransportLayer<(SendData, Vec<u8>)> for &Transport {
fn time(&mut self) -> i64 {
self.time.elapsed().as_millis() as i64
}
fn send(&mut self, packet: Packet<&(SendData, Vec<u8>)>) {
let p = match packet.consume() {
Ok((_, packet)) => packet.clone(),
Err(reply_no) => {
let mut p = Vec::with_capacity(5);
p.push(PACKET_TYPE_ACK);
p.extend(&reply_no.to_be_bytes());
p
}
};
let _ = self.sender.send(p);
}
}
fn process(peer: &Arc<Peer>, transport: &Transport, guard: ReplyGuard<'_>, payload: Payload<'_>, data: Option<SendData>) -> Option<()> {
match (payload, data) {
(Payload::RequestFile { filename }, None) => {
let file = File::open(peer.home_dir.join(filename)).ok()?;
let metadata = file.metadata().ok()?;
let filesize = metadata.len();
reply!(
guard,
SendData::ConfirmFileSize { file },
Payload::ConfirmFileSize { filesize }
);
}
(Payload::ConfirmFileSize { filesize }, Some(SendData::RequestFile { filename })) => {
let path = peer.home_dir.join(filename);
if filesize > DOWNLOAD_LIMIT {
return None;
}
let file = File::create(&path).ok()?;
let fileid = OsRng.next_u64();
peer.downloads_in_progress.insert(fileid, file);
reply!(guard, SendData::ConfirmDownload, Payload::ConfirmDownload { fileid });
}
(Payload::ConfirmDownload { fileid }, Some(SendData::ConfirmFileSize { mut file })) => {
let peer = peer.clone();
let transport = transport.clone();
thread::spawn(move || {
const BUFFERED_CHUNKS: usize = 10;
let mut buffer = [0u8; BUFFERED_CHUNKS * FILE_CHUNK_SIZE];
while let Ok(n) = file.read(&mut buffer) {
if n == 0 {
break;
}
let mut i = 0;
while i < n {
let j = n.min(i + FILE_CHUNK_SIZE);
send!(
peer,
&transport,
SendData::FileDownload,
Payload::FileDownload { fileid, file_chunk: &buffer[i..j] }
);
i = j;
}
}
send!(
peer,
&transport,
SendData::FileDownload,
Payload::FileDownloadComplete { fileid }
);
});
}
(Payload::FileDownload { fileid, file_chunk }, None) => {
let mut file = peer.downloads_in_progress.get(&fileid)?;
let result = file.write_all(file_chunk);
}
(Payload::FileDownloadComplete { fileid }, None) => {
}
(Payload::ReadDir, None) => {
let dir = read_dir(&peer.home_dir).ok()?;
let mut filenames = Vec::new();
for entry in dir {
if let Ok(entry) = entry {
if entry.file_type().map_or(false, |f| f.is_file()) {
if let Ok(filename) = entry.file_name().into_string() {
filenames.push(filename)
}
}
} else {
return None;
}
}
let filenames: Vec<&str> = filenames.iter().map(|f| f.as_str()).collect();
reply!(guard, SendData::DirContents, Payload::DirContents { filenames });
}
(Payload::DirContents { filenames }, Some(SendData::ReadDir { download_missing: true })) => {
drop(guard);
for filename in filenames {}
}
_ => {}
}
Some(())
}
fn receive(peer: &Arc<Peer>, transport: &Transport, receiver: &Receiver<Vec<u8>>) -> Option<()> {
while let Ok(packet) = receiver.try_recv() {
if drop_packet() {
continue;
}
let pt = *packet.get(0)?;
let (mut parsed_packet, payload_offset) = match pt {
PACKET_TYPE_ACK => {
let reply_no = SeqNo::from_be_bytes(packet.get(1..5)?.try_into().ok()?);
(Packet::Ack(reply_no), 5)
}
PACKET_TYPE_PAYLOAD | PACKET_TYPE_LOCK_PAYLOAD => {
let seq_no = SeqNo::from_be_bytes(packet.get(1..5)?.try_into().ok()?);
(Packet::Payload(seq_no, packet), 5)
}
PACKET_TYPE_REPLY | PACKET_TYPE_LOCK_REPLY => {
let seq_no = SeqNo::from_be_bytes(packet.get(1..5)?.try_into().ok()?);
let reply_no = SeqNo::from_be_bytes(packet.get(5..9)?.try_into().ok()?);
(Packet::Reply(seq_no, reply_no, packet), 9)
}
_ => return None,
};
if pt == PACKET_TYPE_LOCK_PAYLOAD || pt == PACKET_TYPE_LOCK_REPLY {
parsed_packet.set_locking(true);
}
for recv_data in peer.seqex.receive_all(transport, parsed_packet) {
let recv_data = recv_data.map(|packet| serde_cbor::from_slice::<Payload>(&packet[payload_offset..]));
if let Ok(parsed_payload) = serde_cbor::from_slice::<Payload>(packet.get(payload_offset..)?) {
process(peer, transport, guard, parsed_packet, send_data.map(|d| d.0));
}
}
}
Some(())
}
fn main() {
let alice_root = std::path::Path::new("examples").join("alice_home");
let bob_root = std::path::Path::new("examples").join("bob_home");
let (s, r) = channel::<i32>();
thread::spawn(move || {
s.send(0);
});
}
#[test]
fn test() {
main()
}
+9 -9
View File
@@ -1,7 +1,7 @@
use std::{sync::mpsc::Receiver, thread, time::Duration};
use seq_ex::{
sync::{MpscSeqEx, MpscTransport},
sync::{MpscTransport, SeqExSync},
Packet,
};
@@ -19,7 +19,7 @@ fn drop_packet() -> bool {
rand_core::OsRng.next_u32() & 1 > 0
}
fn receive(recv: &Receiver<Packet<Payload>>, seq: &MpscSeqEx<Payload>, transport: &MpscTransport<Payload>, value: &mut f32) {
fn receive(recv: &Receiver<Packet<Payload>>, seq: &SeqExSync<Payload, Payload>, transport: &MpscTransport<Payload>, value: &mut f32) {
while let Ok(packet) = recv.try_recv() {
if drop_packet() {
continue;
@@ -42,20 +42,20 @@ fn receive(recv: &Receiver<Packet<Payload>>, seq: &MpscSeqEx<Payload>, transport
fn main() {
let (transport1, recv2) = MpscTransport::new();
let (transport2, recv1) = MpscTransport::new();
let seq1 = MpscSeqEx::new(5, 1);
let seq2 = MpscSeqEx::new(5, 1);
let seq1 = SeqExSync::new(5, 1);
let seq2 = SeqExSync::new(5, 1);
let mut value = 0.0;
let mut remote_value = value;
seq1.send(&transport1, Payload::Add(1.0));
seq1.send(&transport1, true, Payload::Add(1.0));
value += 1.0;
seq1.send(&transport1, Payload::Sub(2.0));
seq1.send(&transport1, true, Payload::Sub(2.0));
value -= 2.0;
seq1.send(&transport1, Payload::Mul(3.0));
seq1.send(&transport1, true, Payload::Mul(3.0));
value *= 3.0;
seq1.send(&transport1, Payload::Div(4.0));
seq1.send(&transport1, true, Payload::Div(4.0));
value /= 4.0;
seq1.send(&transport1, Payload::Mod(5.0));
seq1.send(&transport1, true, Payload::Mod(5.0));
value %= 5.0;
for _ in 0..16 {
+15 -10
View File
@@ -60,7 +60,7 @@ fn process(peer: &Peer, recv_data: RecvOk<'_, &Transport, Payload, Payload, Payl
let transport = peer.transport.clone();
let seqex = peer.seqex.clone();
if let Some(file) = filesystem.read().unwrap().get(&filename) {
guard.reply(ConfirmRequestFile { filesize: file.len() as u64 });
guard.reply(true, ConfirmRequestFile { filesize: file.len() as u64 });
}
thread::spawn(move || {
let filesystem = filesystem.read().unwrap();
@@ -70,18 +70,22 @@ fn process(peer: &Peer, recv_data: RecvOk<'_, &Transport, Payload, Payload, Payl
let mut i = 0;
while i < file.len() {
let j = file.len().min(i + FILE_CHUNK_SIZE);
seqex.send_locked(&transport, FileDownload { filename: filename.clone(), file_chunk: file[i..j].to_vec() });
seqex.send(
&transport,
true,
FileDownload { filename: filename.clone(), file_chunk: file[i..j].to_vec() },
);
i = j;
}
}
});
}
(Some((_, ConfirmRequestFile { filesize })), Some(RequestFile { filename })) => {
(Some((_g, ConfirmRequestFile { filesize })), Some(RequestFile { filename })) => {
let mut filesystem = peer.filesystem.write().unwrap();
let file = Vec::with_capacity(filesize as usize);
filesystem.insert(filename, file);
}
(Some((_, FileDownload { filename, file_chunk })), None) => {
(Some((_g, FileDownload { filename, file_chunk })), None) => {
let mut filesystem = peer.filesystem.write().unwrap();
if let Some(file) = filesystem.get_mut(&filename) {
if file.len() + file_chunk.len() <= file.capacity() {
@@ -102,7 +106,7 @@ fn receive(peer: &Peer) {
continue;
}
if let Ok(parsed_packet) = serde_cbor::from_slice::<Packet<Payload>>(&packet) {
for recv_data in peer.seqex.receive_all(&peer.transport, parsed_packet) {
for recv_data in peer.seqex.try_receive_all(&peer.transport, parsed_packet) {
process(peer, recv_data);
}
}
@@ -137,14 +141,15 @@ fn main() {
receiver: recv2,
};
peer1.seqex.send(&peer1.transport, Payload::RequestFile { filename: "File1".to_string() });
peer1.seqex.send(&peer1.transport, Payload::RequestFile { filename: "File3".to_string() });
peer1.seqex.send(&peer1.transport, Payload::RequestFile { filename: "File2".to_string() });
let tl = &peer1.transport;
peer1.seqex.send(tl, false, Payload::RequestFile { filename: "File1".to_string() });
peer1.seqex.send(tl, false, Payload::RequestFile { filename: "File3".to_string() });
peer1.seqex.send(tl, false, Payload::RequestFile { filename: "File2".to_string() });
for _ in 0..500 {
for _ in 0..400 {
receive(&peer1);
receive(&peer2);
thread::sleep(Duration::from_millis(1));
thread::sleep(Duration::from_millis(2));
peer1.seqex.service(&peer1.transport);
peer2.seqex.service(&peer2.transport);
}
+9 -9
View File
@@ -1,7 +1,7 @@
use std::sync::mpsc::Receiver;
use seq_ex::{
sync::{MpscSeqEx, MpscTransport, RecvOk},
sync::{MpscTransport, RecvOk, SeqExSync},
Packet,
};
@@ -14,23 +14,23 @@ enum Payload {
}
use Payload::*;
fn receive(recv: &Receiver<Packet<Payload>>, seq: &MpscSeqEx<Payload>, transport: &MpscTransport<Payload>) {
fn receive(recv: &Receiver<Packet<Payload>>, seq: &SeqExSync<Payload, Payload>, transport: &MpscTransport<Payload>) {
let packet = recv.recv().unwrap();
for recv_data in seq.receive_all(transport, packet) {
match recv_data.consume() {
(Some((guard, Hello)), None) => {
print!("Hello");
guard.reply(Space);
guard.reply(false, Space);
}
(Some((guard, Space)), Some(Hello)) => {
print!(" ");
guard.reply(World);
guard.reply(false, World);
}
(Some((guard, World)), Some(Space)) => {
print!("World");
guard.reply(Exclamation);
guard.reply(false, Exclamation);
}
(Some((_, Exclamation)), Some(World)) => {
(Some((_g, Exclamation)), Some(World)) => {
print!("!");
}
(None, Some(Exclamation)) => {
@@ -48,11 +48,11 @@ fn receive(recv: &Receiver<Packet<Payload>>, seq: &MpscSeqEx<Payload>, transport
fn main() {
let (transport1, recv2) = MpscTransport::new();
let (transport2, recv1) = MpscTransport::new();
let seq1 = MpscSeqEx::default();
let seq2 = MpscSeqEx::default();
let seq1 = SeqExSync::default();
let seq2 = SeqExSync::default();
// We begin a "Hello World" exchange right here.
seq1.send(&transport1, Payload::Hello);
seq1.send(&transport1, false, Payload::Hello);
receive(&recv2, &seq2, &transport2);
receive(&recv1, &seq1, &transport1);
+118
View File
@@ -0,0 +1,118 @@
use std::sync::Arc;
use tokio::{sync::mpsc, task};
use seq_ex::{
tokio::{AsyncRecvError, MpscTransport, ReplyGuard, SeqExTokio},
Packet,
};
#[derive(Clone, Debug, PartialEq, Eq)]
enum Payload {
Hello,
Space,
World,
Exclamation,
NewLine,
}
use Payload::*;
async fn receive(reply_guard: ReplyGuard<'_, &MpscTransport<Payload>, Payload>, payload: Payload) -> Option<()> {
match payload {
Hello => {
print!("Hello");
let (reply_guard, payload) = reply_guard.reply(false, Space).await.ok()?;
if payload != World {
return None;
}
print!("World");
let (reply_guard, payload) = reply_guard.reply(false, Exclamation).await.ok()?;
if payload != NewLine {
return None;
}
print!("\n");
drop(reply_guard);
}
_ => {
assert!(false, "Unsolicited payload received: {:?}", payload);
}
}
Some(())
}
async fn say_hello(seq: &SeqExTokio<Payload>, transport: &MpscTransport<Payload>) -> Option<()> {
let (reply_guard, payload) = seq.send(transport, false, Hello).await.ok()?;
if payload != Space {
return None;
}
print!(" ");
let (reply_guard, payload) = reply_guard.reply(false, World).await.ok()?;
if payload != Exclamation {
return None;
}
print!("!");
let _ = reply_guard.reply(false, NewLine).await;
Some(())
}
async fn pump_all(peer: Arc<SeqExTokio<Payload>>, transport: MpscTransport<Payload>) {
if let Some((g, payload)) = peer.pump(&transport).await {
spawn_pump(peer.clone(), transport.clone());
receive(g, payload).await;
}
}
fn spawn_pump(peer: Arc<SeqExTokio<Payload>>, transport: MpscTransport<Payload>) {
task::spawn(async move {
pump_all(peer, transport).await;
});
}
fn peer_main(transport: MpscTransport<Payload>, mut recv: mpsc::Receiver<Packet<Payload>>) -> Arc<SeqExTokio<Payload>> {
let (seq, mut service) = SeqExTokio::<Payload>::new_default();
let peer = Arc::new(seq);
let peer_weak = Arc::downgrade(&peer);
let tl = transport.clone();
task::spawn(async move {
while let Some(peer) = peer_weak.upgrade() {
peer.service_task(&tl, &mut service).await;
}
});
let peer_weak = Arc::downgrade(&peer);
task::spawn(async move {
while let Some(packet) = recv.recv().await {
if let Some(peer) = peer_weak.upgrade() {
let tl = transport.clone();
task::spawn(async move {
let result = peer.receive(&tl, packet);
if matches!(&result, Ok(_) | Err(AsyncRecvError::AsyncReply)) {
spawn_pump(peer.clone(), tl.clone());
}
if let Ok((g, payload)) = result {
receive(g, payload).await;
}
});
} else {
break;
}
}
});
peer
}
#[tokio::main]
async fn main() {
let (transport2, recv1) = MpscTransport::new(32);
let (transport1, recv2) = MpscTransport::new(32);
let peer1 = peer_main(transport1.clone(), recv1);
let _peer2 = peer_main(transport2, recv2);
say_hello(&peer1, &transport1).await;
}
#[test]
fn test() {
main()
}
+217 -164
View File
File diff suppressed because it is too large Load Diff
+79 -67
View File
@@ -1,10 +1,10 @@
use crate::{DirectError, Packet, PumpError, RecvOkRaw, SeqEx, SeqNo, TransportLayer, DEFAULT_WINDOW_CAP};
use crate::{DirectRecvError, Packet, PumpError, RecvOkRaw, SeqEx, SeqNo, TransportLayer, DEFAULT_WINDOW_CAP};
pub struct ReplyGuard<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
seq: &'a mut SeqEx<SendData, RecvData, CAP>,
app: Option<TL>,
reply_no: SeqNo,
locked: bool,
is_holding_lock: bool,
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> ReplyGuard<'a, TL, SendData, RecvData, CAP> {
/// If you need to reply more than once, say to fragment a large file, then include in your
@@ -12,31 +12,25 @@ impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> Rep
/// The identifier will tell the remote peer which packets contain fragments of the file,
/// and since each fragment will be received in order it will be trivial for them to reconstruct
/// the original file.
pub fn reply(self, packet_data: SendData) {
self.reply_inner(false, |_, _| packet_data)
pub fn reply(self, seq_cst: bool, packet_data: SendData) {
self.reply_with(seq_cst, |_, _| packet_data)
}
pub fn reply_locked(self, packet_data: SendData) {
self.reply_inner(true, |_, _| packet_data)
}
pub fn reply_with(self, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
self.reply_inner(false, packet_data)
}
pub fn reply_locked_with(self, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
self.reply_inner(true, packet_data)
}
fn reply_inner(mut self, locked: bool, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
let mut app = None;
core::mem::swap(&mut app, &mut self.app);
fn reply_with(mut self, seq_cst: bool, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
let app = self.app.take();
let seq_no = self.seq.seq_no();
self.seq
.reply_raw(app.unwrap(), self.reply_no, self.locked, locked, packet_data(seq_no, self.reply_no));
core::mem::forget(self);
self.seq.reply_raw(
app.unwrap(),
self.reply_no,
self.is_holding_lock,
seq_cst,
packet_data(seq_no, self.reply_no),
);
}
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> Drop for ReplyGuard<'a, TL, SendData, RecvData, CAP> {
fn drop(&mut self) {
if let Some(app) = &mut self.app {
if let Some(p) = self.seq.ack_raw_and_direct(self.reply_no, self.locked) {
if let Some(p) = self.seq.ack_raw_and_direct(self.reply_no, self.is_holding_lock) {
app.send(p)
}
}
@@ -44,20 +38,33 @@ impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> Dro
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> std::fmt::Debug for ReplyGuard<'a, TL, SendData, RecvData, CAP> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReplyGuard").field("reply_no", &self.reply_no).finish()
f.debug_struct("ReplyGuard")
.field("reply_no", &self.reply_no)
.field("is_holding_lock", &self.is_holding_lock)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error<RecvData> {
/// The packet is out-of-sequence. It was either received too soon or too late and so it would be
/// invalid to process it right now. No action needs to be taken by the caller.
OutOfSequence,
/// The Send Window is currently full. The received packet cannot be processed right now because
/// it could cause the send window to overflow.
WindowIsFull(Packet<RecvData>),
WindowIsLocked(Packet<RecvData>),
pub enum RecvError {
DroppedTooEarly,
DroppedDuplicate,
WaitingForRecv,
WaitingForReply,
}
#[cfg(feature = "std")]
impl std::fmt::Display for RecvError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
RecvError::DroppedTooEarly => write!(f, "packet arrived too early"),
RecvError::DroppedDuplicate => write!(f, "packet was a duplicate"),
RecvError::WaitingForRecv => write!(f, "can't process until another packet is received"),
RecvError::WaitingForReply => write!(f, "can't process until a reply is finished"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for RecvError {}
pub enum RecvOk<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
Payload {
@@ -97,14 +104,14 @@ macro_rules! impl_recvok {
}
}
impl<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const CAP: usize> $recv<'a, TL, P, SendData, RecvData, CAP> {
pub fn from_raw(seq: $seq_ex, app: TL, value: RecvOkRaw<SendData, P>) -> Self {
fn from_raw(seq: $seq_ex, app: TL, value: RecvOkRaw<SendData, P>) -> Self {
match value {
RecvOkRaw::Payload { reply_no, locked, recv_data } => Self::Payload {
reply_guard: ReplyGuard { seq, app: Some(app), reply_no, locked },
RecvOkRaw::Payload { reply_no, seq_cst, recv_data } => Self::Payload {
reply_guard: ReplyGuard { seq, app: Some(app), reply_no, is_holding_lock: seq_cst },
recv_data,
},
RecvOkRaw::Reply { reply_no, locked, recv_data, send_data } => Self::Reply {
reply_guard: ReplyGuard { seq, app: Some(app), reply_no, locked },
RecvOkRaw::Reply { reply_no, seq_cst, recv_data, send_data } => Self::Reply {
reply_guard: ReplyGuard { seq, app: Some(app), reply_no, is_holding_lock: seq_cst },
recv_data,
send_data,
},
@@ -126,13 +133,6 @@ macro_rules! impl_recvok {
(None, None) => None,
}
}
pub fn map<R>(self, f: impl FnOnce(P) -> R) -> $recv<'a, TL, R, SendData, RecvData, CAP> {
match self {
Self::Payload { reply_guard, recv_data } => $recv::Payload { reply_guard, recv_data: f(recv_data) },
Self::Reply { reply_guard, recv_data, send_data } => $recv::Reply { reply_guard, recv_data: f(recv_data), send_data },
Self::Ack { send_data } => $recv::Ack { send_data },
}
}
}
impl<'a, TL: TransportLayer<SendData>, P: Into<RecvData>, SendData, RecvData, const CAP: usize> $recv<'a, TL, P, SendData, RecvData, CAP> {
pub fn into(self) -> $recv<'a, TL, RecvData, SendData, RecvData, CAP> {
@@ -149,25 +149,25 @@ impl_recvok!(RecvOk, &'a mut SeqEx<SendData, RecvData, CAP>);
pub(crate) use impl_recvok;
impl<SendData, RecvData, const CAP: usize> SeqEx<SendData, RecvData, CAP> {
pub fn try_send(&mut self, mut app: impl TransportLayer<SendData>, locked: bool, packet_data: SendData) -> Result<(), SendData> {
match self.try_send_direct(packet_data, app.time()) {
Ok(mut p) => {
p.set_locking(locked);
/// Can mutate `next_service_timestamp`.
pub fn try_send(&mut self, mut app: impl TransportLayer<SendData>, seq_cst: bool, packet_data: SendData) -> Result<(), SendData> {
match self.try_send_direct(app.time(), seq_cst, packet_data) {
Ok(p) => {
app.send(p);
Ok(())
}
Err(e) => Err(e),
}
}
pub fn try_send_with(
/// Can mutate `next_service_timestamp`.
pub fn try_send_with<F: FnOnce(SeqNo) -> SendData>(
&mut self,
mut app: impl TransportLayer<SendData>,
locked: bool,
packet_data: impl FnOnce(SeqNo) -> SendData,
) -> Result<(), ()> {
match self.try_send_direct_with(packet_data, app.time()) {
Ok(mut p) => {
p.set_locking(locked);
seq_cst: bool,
packet_data: F,
) -> Result<(), F> {
match self.try_send_direct_with(app.time(), seq_cst, packet_data) {
Ok(p) => {
app.send(p);
Ok(())
}
@@ -179,29 +179,41 @@ impl<SendData, RecvData, const CAP: usize> SeqEx<SendData, RecvData, CAP> {
&mut self,
mut app: impl TransportLayer<SendData>,
packet: Packet<P>,
) -> Result<crate::seq_queue::RecvOkRaw<SendData, P>, Error<P>> {
) -> Result<crate::seq_queue::RecvOkRaw<SendData, P>, RecvError> {
match self.receive_raw_and_direct(packet) {
Ok(a) => Ok(a),
Err(DirectError::ResendAck(reply_no)) => {
Err(DirectRecvError::DroppedDuplicateResendAck(reply_no)) => {
app.send(Packet::Ack(reply_no));
Err(Error::OutOfSequence)
Err(RecvError::DroppedDuplicate)
}
Err(DirectError::OutOfSequence) => Err(Error::OutOfSequence),
Err(DirectError::WindowIsFull(p)) => Err(Error::WindowIsFull(p)),
Err(DirectError::WindowIsLocked(p)) => Err(Error::WindowIsLocked(p)),
Err(DirectRecvError::DroppedTooEarly) => Err(RecvError::DroppedTooEarly),
Err(DirectRecvError::DroppedDuplicate) => Err(RecvError::DroppedDuplicate),
Err(DirectRecvError::WaitingForRecv) => Err(RecvError::WaitingForRecv),
Err(DirectRecvError::WaitingForReply) => Err(RecvError::WaitingForReply),
}
}
pub fn reply_raw(&mut self, mut app: impl TransportLayer<SendData>, reply_no: SeqNo, unlock: bool, locked_packet: bool, packet_data: SendData) {
if let Some(mut p) = self.reply_raw_and_direct(reply_no, unlock, packet_data, app.time()) {
p.set_locking(locked_packet);
app.send(p)
/// Can mutate `next_service_timestamp`.
/// If `unlock` is true and the return value is true pump may return new values.
///
/// Only returns false if the reply number was incorrect or used twice.
pub fn reply_raw(&mut self, mut app: impl TransportLayer<SendData>, reply_no: SeqNo, unlock: bool, seq_cst: bool, packet_data: SendData) -> bool {
if let Some(p) = self.reply_raw_and_direct(app.time(), reply_no, unlock, seq_cst, packet_data) {
app.send(p);
true
} else {
false
}
}
pub fn ack_raw(&mut self, mut app: impl TransportLayer<SendData>, reply_no: SeqNo, unlock: bool) {
/// If `unlock` is true and the return value is true pump may return new values.
pub fn ack_raw(&mut self, mut app: impl TransportLayer<SendData>, reply_no: SeqNo, unlock: bool) -> bool {
if let Some(p) = self.ack_raw_and_direct(reply_no, unlock) {
app.send(p)
app.send(p);
true
} else {
false
}
}
/// Can mutate `next_service_timestamp`.
pub fn service(&mut self, mut app: impl TransportLayer<SendData>) -> i64 {
let current_time = app.time();
let mut iter = None;
@@ -214,10 +226,10 @@ impl<SendData, RecvData, const CAP: usize> SeqEx<SendData, RecvData, CAP> {
&mut self,
app: TL,
packet: Packet<P>,
) -> Result<RecvOk<'_, TL, P, SendData, RecvData, CAP>, Error<P>> {
) -> Result<RecvOk<'_, TL, P, SendData, RecvData, CAP>, RecvError> {
self.receive_raw(app.clone(), packet).map(|r| RecvOk::from_raw(self, app, r))
}
pub fn pump<TL: TransportLayer<SendData>>(&mut self, app: TL) -> Result<RecvOk<'_, TL, RecvData, SendData, RecvData, CAP>, PumpError> {
self.pump_raw().map(|r| RecvOk::from_raw(self, app, r))
pub fn try_pump<TL: TransportLayer<SendData>>(&mut self, app: TL) -> Result<RecvOk<'_, TL, RecvData, SendData, RecvData, CAP>, PumpError> {
self.try_pump_raw().map(|r| RecvOk::from_raw(self, app, r))
}
}
+127 -134
View File
@@ -1,83 +1,71 @@
use std::{
ops::{Deref, DerefMut},
sync::{
mpsc::{channel, Receiver, Sender},
Condvar, Mutex, MutexGuard,
Condvar, Mutex,
},
time::Instant,
};
use crate::{Packet, PumpError, RecvOkRaw, SeqEx, SeqNo, TransportLayer, DEFAULT_INITIAL_SEQ_NO, DEFAULT_RESEND_INTERVAL_MS, DEFAULT_WINDOW_CAP};
use crate::{
Packet, PumpError, RecvError, RecvOkRaw, SeqEx, SeqNo, TransportLayer, DEFAULT_INITIAL_SEQ_NO, DEFAULT_RESEND_INTERVAL_MS, DEFAULT_WINDOW_CAP,
};
pub struct SeqExSync<SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
seq_ex: Mutex<(SeqEx<SendData, RecvData, CAP>, usize)>,
seq_ex: Mutex<(SeqEx<SendData, RecvData, CAP>, usize, bool)>,
send_block: Condvar,
recv_lock: Condvar,
reply_block: Condvar,
}
pub struct ReplyGuard<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
seq: &'a SeqExSync<SendData, RecvData, CAP>,
app: Option<TL>,
reply_no: SeqNo,
locked: bool,
is_holding_lock: bool,
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> ReplyGuard<'a, TL, SendData, RecvData, CAP> {
fn reply_with(mut self, seq_cst: bool, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
let app = self.app.take().unwrap();
let mut seq = self.seq.seq_ex.lock().unwrap();
let seq_no = seq.0.seq_no();
seq.0
.reply_raw(app, self.reply_no, self.is_holding_lock, seq_cst, packet_data(seq_no, self.reply_no));
if seq.2 {
seq.2 = false;
drop(seq);
self.seq.reply_block.notify_all();
}
}
/// If you need to reply more than once, say to fragment a large file, then include in your
/// first reply some identifier, and then `send` all fragments with the same included identifier.
/// The identifier will tell the remote peer which packets contain fragments of the file,
/// and since each fragment will be received in order it will be trivial for them to reconstruct
/// the original file.
pub fn reply(self, packet_data: SendData) {
self.reply_inner(false, |_, _| packet_data)
}
pub fn reply_locked(self, packet_data: SendData) {
self.reply_inner(true, |_, _| packet_data)
}
pub fn reply_with(self, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
self.reply_inner(false, packet_data)
}
pub fn reply_locked_with(self, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
self.reply_inner(true, packet_data)
}
fn reply_inner(mut self, locked: bool, packet_data: impl FnOnce(SeqNo, SeqNo) -> SendData) {
let mut app = None;
core::mem::swap(&mut app, &mut self.app);
let mut seq = self.seq.lock();
let seq_no = seq.seq_no();
seq.reply_raw(app.unwrap(), self.reply_no, self.locked, locked, packet_data(seq_no, self.reply_no));
drop(seq);
if self.locked {
self.seq.recv_lock.notify_all();
}
core::mem::forget(self);
pub fn reply(self, seq_cst: bool, packet_data: SendData) {
self.reply_with(seq_cst, |_, _| packet_data)
}
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> Drop for ReplyGuard<'a, TL, SendData, RecvData, CAP> {
fn drop(&mut self) {
if let Some(app) = self.app.as_mut() {
let mut seq = self.seq.lock();
if let Some(p) = seq.ack_raw_and_direct(self.reply_no, self.locked) {
app.send(p)
if let Some(app) = self.app.take() {
let mut seq = self.seq.seq_ex.lock().unwrap();
seq.0.ack_raw(app, self.reply_no, self.is_holding_lock);
if seq.2 {
seq.2 = false;
drop(seq);
self.seq.reply_block.notify_all();
}
}
}
}
impl<'a, TL: TransportLayer<SendData>, SendData, RecvData, const CAP: usize> std::fmt::Debug for ReplyGuard<'a, TL, SendData, RecvData, CAP> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReplyGuard").field("reply_no", &self.reply_no).finish()
f.debug_struct("ReplyGuard")
.field("reply_no", &self.reply_no)
.field("is_holding_lock", &self.is_holding_lock)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// The packet is out-of-sequence. It was either received too soon or too late and so it would be
/// invalid to process it right now. No action needs to be taken by the caller.
OutOfSequence,
/// The Send Window is currently full. The received packet cannot be processed right now because
/// it could cause the send window to overflow. No action needs to be taken by the caller.
WindowIsFull,
}
pub enum RecvOk<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
Payload {
reply_guard: ReplyGuard<'a, TL, SendData, RecvData, CAP>,
@@ -94,135 +82,138 @@ pub enum RecvOk<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const C
}
crate::impl_recvok!(RecvOk, &'a SeqExSync<SendData, RecvData, CAP>);
pub struct ReplyIter<'a, TL: TransportLayer<SendData>, P: Into<RecvData>, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
pub struct RecvIter<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const CAP: usize = DEFAULT_WINDOW_CAP> {
seq: Option<&'a SeqExSync<SendData, RecvData, CAP>>,
app: TL,
first: Option<RecvOk<'a, TL, P, SendData, RecvData, CAP>>,
}
pub struct SeqExGuard<'a, SendData, RecvData, const CAP: usize>(MutexGuard<'a, (SeqEx<SendData, RecvData, CAP>, usize)>);
impl<'a, SendData, RecvData, const CAP: usize> Deref for SeqExGuard<'a, SendData, RecvData, CAP> {
type Target = SeqEx<SendData, RecvData, CAP>;
fn deref(&self) -> &Self::Target {
&self.0 .0
}
}
impl<'a, SendData, RecvData, const CAP: usize> DerefMut for SeqExGuard<'a, SendData, RecvData, CAP> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0 .0
}
blocking: bool,
}
impl<SendData, RecvData, const CAP: usize> SeqExSync<SendData, RecvData, CAP> {
pub fn new(retry_interval: i64, initial_seq_no: SeqNo) -> Self {
Self {
seq_ex: Mutex::new((SeqEx::new(retry_interval, initial_seq_no), 0)),
seq_ex: Mutex::new((SeqEx::new(retry_interval, initial_seq_no), 0, false)),
send_block: Condvar::default(),
recv_lock: Condvar::default(),
reply_block: Condvar::default(),
}
}
pub fn receive<TL: TransportLayer<SendData>, P: Into<RecvData>>(
&self,
app: TL,
mut packet: Packet<P>,
) -> Result<RecvOk<'_, TL, P, SendData, RecvData, CAP>, Error> {
packet: Packet<P>,
) -> Result<RecvOk<'_, TL, P, SendData, RecvData, CAP>, RecvError> {
let mut seq = self.seq_ex.lock().unwrap();
match seq.0.receive_raw(app.clone(), packet) {
Ok(r) => {
if seq.1 > 0 {
seq.1 -= 1;
drop(seq);
self.send_block.notify_one();
}
Ok(RecvOk::from_raw(self, app, r))
}
Err(e) => Err(e),
}
}
pub fn try_pump<TL: TransportLayer<SendData>>(&self, app: TL) -> Result<RecvOk<'_, TL, RecvData, SendData, RecvData, CAP>, PumpError> {
let mut seq = self.seq_ex.lock().unwrap();
// Enforce that only one thread may pump at a time.
if seq.2 {
return Err(PumpError::WaitingForReply);
}
match seq.0.try_pump_raw() {
Ok(r) => {
if seq.1 > 0 {
seq.1 -= 1;
drop(seq);
self.send_block.notify_one();
}
Ok(RecvOk::from_raw(self, app, r))
}
Err(e) => Err(e),
}
}
pub fn pump<TL: TransportLayer<SendData>>(&self, app: TL) -> Option<RecvOk<'_, TL, RecvData, SendData, RecvData, CAP>> {
let mut seq = self.seq_ex.lock().unwrap();
// Enforce that only one thread may pump at a time.
if seq.2 {
return None;
}
loop {
match seq.0.receive_raw(app.clone(), packet) {
match seq.0.try_pump_raw() {
Ok(r) => {
if seq.1 > 0 {
seq.1 -= 1;
drop(seq);
self.send_block.notify_one();
}
return Ok(RecvOk::from_raw(self, app, r));
return Some(RecvOk::from_raw(self, app, r));
}
Err(crate::Error::OutOfSequence) => return Err(Error::OutOfSequence),
Err(crate::Error::WindowIsFull(_)) => return Err(Error::WindowIsFull),
Err(crate::Error::WindowIsLocked(p)) => {
seq = self.recv_lock.wait(seq).unwrap();
packet = p;
Err(PumpError::WaitingForRecv) => return None,
Err(PumpError::WaitingForReply) => {
seq.2 = true;
seq = self.reply_block.wait(seq).unwrap();
}
}
}
}
pub fn pump<TL: TransportLayer<SendData>>(&self, app: TL) -> Result<RecvOk<'_, TL, RecvData, SendData, RecvData, CAP>, Error> {
let mut seq = self.seq_ex.lock().unwrap();
loop {
match seq.0.pump_raw() {
Ok(r) => {
if seq.1 > 0 {
self.send_block.notify_one();
}
return Ok(RecvOk::from_raw(self, app, r));
}
Err(PumpError::OutOfSequence) => return Err(Error::OutOfSequence),
Err(PumpError::WindowIsFull) => return Err(Error::WindowIsFull),
Err(PumpError::WindowIsLocked) => {
seq = self.recv_lock.wait(seq).unwrap();
}
}
fn receive_all_inner<TL: TransportLayer<SendData>, P: Into<RecvData>>(
&self,
app: TL,
blocking: bool,
packet: Packet<P>,
) -> RecvIter<'_, TL, P, SendData, RecvData, CAP> {
match self.receive(app.clone(), packet) {
Ok(r) => RecvIter { seq: Some(self), app, first: Some(r), blocking },
Err(RecvError::WaitingForReply) if blocking => RecvIter { seq: Some(self), app, first: None, blocking },
Err(_) => RecvIter { seq: None, app, first: None, blocking },
}
}
pub fn receive_all<TL: TransportLayer<SendData>, P: Into<RecvData>>(
&self,
app: TL,
packet: Packet<P>,
) -> ReplyIter<'_, TL, P, SendData, RecvData, CAP> {
if let Ok(r) = self.receive(app.clone(), packet) {
ReplyIter { seq: Some(self), app, first: Some(r) }
} else {
ReplyIter { seq: None, app, first: None }
}
) -> RecvIter<'_, TL, P, SendData, RecvData, CAP> {
self.receive_all_inner(app, true, packet)
}
pub fn try_send<TL: TransportLayer<SendData>>(&self, app: TL, locked: bool, packet_data: SendData) -> Result<(), SendData> {
self.try_send_with(app, locked, |_| packet_data)
pub fn try_receive_all<TL: TransportLayer<SendData>, P: Into<RecvData>>(
&self,
app: TL,
packet: Packet<P>,
) -> RecvIter<'_, TL, P, SendData, RecvData, CAP> {
self.receive_all_inner(app, false, packet)
}
fn send_with_inner<TL: TransportLayer<SendData>>(&self, app: TL, locked: bool, mut packet_data: impl FnMut(SeqNo) -> SendData) {
pub fn try_send_with<TL: TransportLayer<SendData>, F: FnOnce(SeqNo) -> SendData>(&self, app: TL, seq_cst: bool, packet_data: F) -> Result<(), F> {
let mut seq = self.seq_ex.lock().unwrap();
while let Err(()) = seq.0.try_send_with(app.clone(), locked, &mut packet_data) {
seq.1 += 1;
seq = self.send_block.wait(seq).unwrap();
seq.1 -= 1;
}
seq.0.try_send_with(app, seq_cst, packet_data)
}
fn send_inner<TL: TransportLayer<SendData>>(&self, app: TL, locked: bool, mut packet_data: SendData) {
pub fn try_send<TL: TransportLayer<SendData>>(&self, app: TL, seq_cst: bool, packet_data: SendData) -> Result<(), SendData> {
let mut seq = self.seq_ex.lock().unwrap();
while let Err(p) = seq.0.try_send(app.clone(), locked, packet_data) {
seq.0.try_send(app, seq_cst, packet_data)
}
pub fn send_with<TL: TransportLayer<SendData>>(&self, app: TL, seq_cst: bool, mut packet_data: impl FnOnce(SeqNo) -> SendData) {
let mut seq = self.seq_ex.lock().unwrap();
while let Err(p) = seq.0.try_send_with(app.clone(), seq_cst, packet_data) {
packet_data = p;
seq.1 += 1;
seq = self.send_block.wait(seq).unwrap();
seq.1 -= 1;
}
}
pub fn send(&self, app: impl TransportLayer<SendData>, packet_data: SendData) {
self.send_inner(app, false, packet_data)
}
pub fn send_locked(&self, app: impl TransportLayer<SendData>, packet_data: SendData) {
self.send_inner(app, true, packet_data)
}
pub fn send_with(&self, app: impl TransportLayer<SendData>, packet_data: impl FnMut(SeqNo) -> SendData) {
self.send_with_inner(app, false, packet_data)
}
pub fn send_locked_with(&self, app: impl TransportLayer<SendData>, packet_data: impl FnMut(SeqNo) -> SendData) {
self.send_with_inner(app, true, packet_data)
}
pub fn try_send_with<TL: TransportLayer<SendData>>(
&self,
app: TL,
locked: bool,
packet_data: impl FnOnce(SeqNo) -> SendData,
) -> Result<(), SendData> {
let mut seq = self.lock();
let seq_no = seq.seq_no();
seq.try_send(app, locked, packet_data(seq_no))
}
pub fn service<TL: TransportLayer<SendData>>(&self, app: TL) -> i64 {
self.lock().service(app)
pub fn send<TL: TransportLayer<SendData>>(&self, app: TL, seq_cst: bool, mut packet_data: SendData) {
let mut seq = self.seq_ex.lock().unwrap();
while let Err(p) = seq.0.try_send(app.clone(), seq_cst, packet_data) {
packet_data = p;
seq.1 += 1;
seq = self.send_block.wait(seq).unwrap();
}
}
pub fn lock(&self) -> SeqExGuard<'_, SendData, RecvData, CAP> {
SeqExGuard(self.seq_ex.lock().unwrap())
pub fn service<TL: TransportLayer<SendData>>(&self, app: TL) -> i64 {
self.seq_ex.lock().unwrap().0.service(app)
}
}
impl<SendData, RecvData, const CAP: usize> Default for SeqExSync<SendData, RecvData, CAP> {
@@ -231,20 +222,24 @@ impl<SendData, RecvData, const CAP: usize> Default for SeqExSync<SendData, RecvD
}
}
impl<'a, TL: TransportLayer<SendData>, P: Into<RecvData>, SendData, RecvData, const CAP: usize> ReplyIter<'a, TL, P, SendData, RecvData, CAP> {
impl<'a, TL: TransportLayer<SendData>, P, SendData, RecvData, const CAP: usize> RecvIter<'a, TL, P, SendData, RecvData, CAP> {
pub fn take_first(&mut self) -> Option<RecvOk<'a, TL, P, SendData, RecvData, CAP>> {
self.first.take()
}
}
impl<'a, TL: TransportLayer<SendData>, P: Into<RecvData>, SendData, RecvData, const CAP: usize> Iterator
for ReplyIter<'a, TL, P, SendData, RecvData, CAP>
for RecvIter<'a, TL, P, SendData, RecvData, CAP>
{
type Item = RecvOk<'a, TL, RecvData, SendData, RecvData, CAP>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(g) = self.first.take() {
Some(g.into())
} else if let Some(origin) = self.seq {
origin.pump(self.app.clone()).ok()
if self.blocking {
origin.pump(self.app.clone())
} else {
origin.try_pump(self.app.clone()).ok()
}
} else {
None
}
@@ -256,8 +251,6 @@ pub struct MpscTransport<Payload: Clone> {
pub channel: Sender<Packet<Payload>>,
pub time: Instant,
}
pub type MpscGuard<'a, Packet> = ReplyGuard<'a, &'a MpscTransport<Packet>, Packet, Packet>;
pub type MpscSeqEx<Packet> = SeqExSync<Packet, Packet>;
impl<Payload: Clone> MpscTransport<Payload> {
pub fn new() -> (Self, Receiver<Packet<Payload>>) {
+372 -270
View File
File diff suppressed because it is too large Load Diff