add return channel with passing test

This commit is contained in:
2025-06-14 19:20:45 -04:00
parent 4684a36089
commit 28a7a8bcfa
2 changed files with 84 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
mod args;
pub use args::Args;
mod hashes;
mod return_channel;
pub use return_channel::ReturnChannel;

78
src/return_channel.rs Normal file
View File

@@ -0,0 +1,78 @@
use std::sync::{Arc, Condvar, Mutex};
pub struct ReturnChannel<T> {
value: Mutex<Option<T>>,
condvar: Condvar,
}
impl<T> ReturnChannel<T> {
pub fn new() -> (ReturnChannelSender<T>, ReturnChannelReceiver<T>) {
let inner = ReturnChannel {
value: Mutex::new(None),
condvar: Condvar::new(),
};
let arc = Arc::new(inner);
let ret_tx = ReturnChannelSender(arc.clone());
let ret_rx = ReturnChannelReceiver(arc);
(ret_tx, ret_rx)
}
}
struct ReturnChannelReceiver<T>(Arc<ReturnChannel<T>>);
struct ReturnChannelSender<T>(Arc<ReturnChannel<T>>);
impl<T> ReturnChannelReceiver<T> {
pub fn receive(self) -> T {
let mut val = self.0.value.lock().unwrap();
while val.is_none() {
val = self.0.condvar.wait(val).unwrap()
}
let replace = val.take();
replace.unwrap()
}
}
impl<T> ReturnChannelSender<T> {
pub fn send(self, val: T) {
let mut lock = self.0.value.lock().unwrap();
*lock = Some(val);
self.0.condvar.notify_all();
}
}
#[cfg(test)]
mod test {
pub use super::*;
#[test]
fn test_channel_single_thread() {
let (tx, rx) = ReturnChannel::new();
tx.send(42);
let rx = rx.receive();
assert_eq!(rx, 42);
}
#[test]
fn test_channel_multi_thread() {
let (tx, rx) = ReturnChannel::new();
std::thread::spawn(|| {
tx.send(42);
});
let rx = rx.receive();
assert_eq!(rx, 42);
}
}