Skip to content

Commit 6e2e207

Browse files
committed
feature: add a super simple oneshot channel
1 parent 155cc95 commit 6e2e207

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

Cargo.lock

+7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ edition = "2021"
77

88
[dependencies]
99
anyhow = "1.0.83"
10+
arc-swap = "1.7.1"
1011
crossbeam-channel = "0.5.12"

examples/oneshot.rs

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
use anyhow::Result;
2+
use arc_swap::ArcSwapOption;
3+
use std::thread;
4+
use std::{
5+
ops::Deref,
6+
sync::{
7+
atomic::{AtomicBool, Ordering},
8+
Arc,
9+
},
10+
};
11+
12+
struct Oneshot<T> {
13+
data: ArcSwapOption<T>,
14+
is_filled: AtomicBool,
15+
}
16+
17+
struct Sender<T>(Arc<Oneshot<T>>);
18+
19+
struct Receiver<T>(Arc<Oneshot<T>>);
20+
21+
impl<T> Oneshot<T> {
22+
fn channel() -> (Sender<T>, Receiver<T>) {
23+
let oneshot = Arc::new(Oneshot {
24+
data: ArcSwapOption::from(None),
25+
is_filled: AtomicBool::new(false),
26+
});
27+
(Sender(oneshot.clone()), Receiver(oneshot))
28+
}
29+
}
30+
31+
impl<T> Sender<T> {
32+
fn send(&self, value: T) -> Result<(), T> {
33+
if self
34+
.is_filled
35+
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
36+
.is_ok()
37+
{
38+
self.data.store(Some(Arc::new(value)));
39+
Ok(())
40+
} else {
41+
Err(value)
42+
}
43+
}
44+
}
45+
46+
impl<T> Receiver<T> {
47+
fn recv(&self) -> Result<T> {
48+
if self
49+
.is_filled
50+
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
51+
.is_ok()
52+
{
53+
let v = self.data.swap(None);
54+
55+
v.ok_or_else(|| anyhow::anyhow!("No value"))
56+
.and_then(|v| Arc::try_unwrap(v).map_err(|_| anyhow::anyhow!("Multiple receivers")))
57+
} else {
58+
Err(anyhow::anyhow!("Sender has not sent a value yet"))
59+
}
60+
}
61+
}
62+
63+
impl<T> Deref for Receiver<T> {
64+
type Target = Arc<Oneshot<T>>;
65+
66+
fn deref(&self) -> &Self::Target {
67+
&self.0
68+
}
69+
}
70+
71+
impl<T> Deref for Sender<T> {
72+
type Target = Arc<Oneshot<T>>;
73+
74+
fn deref(&self) -> &Self::Target {
75+
&self.0
76+
}
77+
}
78+
79+
fn main() -> Result<()> {
80+
let (tx, rx) = Oneshot::channel();
81+
82+
let sender_thread = thread::spawn(move || {
83+
tx.send(42).unwrap();
84+
});
85+
86+
let receiver_thread = thread::spawn(move || {
87+
let Ok(v) = rx.recv() else {
88+
eprintln!("Failed to receive value");
89+
return;
90+
};
91+
92+
println!("Received: {}", v);
93+
});
94+
95+
sender_thread.join().unwrap();
96+
receiver_thread.join().unwrap();
97+
98+
Ok(())
99+
}

0 commit comments

Comments
 (0)