synapto_interface/
sync.rs1#[cfg(not(debug_assertions))]
25pub use tokio::sync::*;
26
27#[cfg(debug_assertions)]
28pub mod mpsc {
29 use std::ops::Deref;
31 use tokio::sync::mpsc::error::{SendError, TrySendError};
32 pub use tokio::sync::mpsc::{Receiver, UnboundedReceiver, error};
33
34 #[track_caller]
39 pub fn channel<T: crate::sync::TypeChannelName>(buffer: usize) -> (Sender<T>, Receiver<T>) {
40 let (tx, rx) = tokio::sync::mpsc::channel(buffer);
41 (Sender(tx), rx)
42 }
43
44 #[track_caller]
45 pub fn unbounded_channel<T: crate::sync::TypeChannelName>()
46 -> (UnboundedSender<T>, UnboundedReceiver<T>) {
47 let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
48 (UnboundedSender(tx), rx)
49 }
50
51 #[derive(Debug)]
53 #[repr(transparent)]
54 pub struct Sender<T: crate::sync::TypeChannelName>(tokio::sync::mpsc::Sender<T>);
55
56 impl<T: crate::sync::TypeChannelName> Clone for Sender<T> {
57 fn clone(&self) -> Self {
58 Self(self.0.clone())
59 }
60 }
61
62 impl<T: crate::sync::TypeChannelName> Sender<T> {
63 #[allow(ungated_async_fn_track_caller)]
68 #[track_caller]
69 pub async fn send(&self, value: T) -> Result<(), SendError<T>> {
70 let res = self.0.send(value).await;
71 if res.is_ok() {
72 super::detail::trace_pulse::<T>("mpsc", std::panic::Location::caller());
73 }
74 res
75 }
76
77 #[track_caller]
81 pub fn blocking_send(&self, value: T) -> Result<(), SendError<T>> {
82 let res = self.0.blocking_send(value);
83 if res.is_ok() {
84 super::detail::trace_pulse::<T>("mpsc", std::panic::Location::caller());
85 }
86 res
87 }
88
89 #[track_caller]
93 pub fn try_send(&self, message: T) -> Result<(), TrySendError<T>> {
94 let res = self.0.try_send(message);
95 if res.is_ok() {
96 super::detail::trace_pulse::<T>("mpsc", std::panic::Location::caller());
97 }
98 res
99 }
100 }
101
102 impl<T: crate::sync::TypeChannelName> Deref for Sender<T> {
103 type Target = tokio::sync::mpsc::Sender<T>;
104 fn deref(&self) -> &Self::Target {
105 &self.0
106 }
107 }
108
109 impl<T: crate::sync::TypeChannelName> From<tokio::sync::mpsc::Sender<T>> for Sender<T> {
110 fn from(inner: tokio::sync::mpsc::Sender<T>) -> Self {
111 Self(inner)
112 }
113 }
114
115 impl<T: crate::sync::TypeChannelName> From<Sender<T>> for tokio::sync::mpsc::Sender<T> {
116 fn from(proxy: Sender<T>) -> Self {
117 proxy.0
118 }
119 }
120
121 #[derive(Debug)]
123 #[repr(transparent)]
124 pub struct UnboundedSender<T: crate::sync::TypeChannelName>(
125 tokio::sync::mpsc::UnboundedSender<T>,
126 );
127
128 impl<T: crate::sync::TypeChannelName> Clone for UnboundedSender<T> {
129 fn clone(&self) -> Self {
130 Self(self.0.clone())
131 }
132 }
133
134 impl<T: crate::sync::TypeChannelName> UnboundedSender<T> {
135 #[track_caller]
139 pub fn send(&self, message: T) -> Result<(), error::SendError<T>> {
140 let res = self.0.send(message);
141 if res.is_ok() {
142 super::detail::trace_pulse::<T>("unbounded", std::panic::Location::caller());
143 }
144 res
145 }
146 }
147
148 impl<T: crate::sync::TypeChannelName> Deref for UnboundedSender<T> {
149 type Target = tokio::sync::mpsc::UnboundedSender<T>;
150 fn deref(&self) -> &Self::Target {
151 &self.0
152 }
153 }
154
155 impl<T: crate::sync::TypeChannelName> From<tokio::sync::mpsc::UnboundedSender<T>>
156 for UnboundedSender<T>
157 {
158 fn from(inner: tokio::sync::mpsc::UnboundedSender<T>) -> Self {
159 Self(inner)
160 }
161 }
162
163 impl<T: crate::sync::TypeChannelName> From<UnboundedSender<T>>
164 for tokio::sync::mpsc::UnboundedSender<T>
165 {
166 fn from(proxy: UnboundedSender<T>) -> Self {
167 proxy.0
168 }
169 }
170}
171
172#[cfg(debug_assertions)]
173pub mod broadcast {
174 use std::ops::Deref;
176 use tokio::sync::broadcast::error::SendError;
177 pub use tokio::sync::broadcast::{Receiver, error};
178
179 #[track_caller]
184 pub fn channel<T: Clone + crate::sync::TypeChannelName>(
185 capacity: usize,
186 ) -> (Sender<T>, Receiver<T>) {
187 let (tx, rx) = tokio::sync::broadcast::channel(capacity);
188 (Sender(tx), rx)
189 }
190
191 #[derive(Debug)]
193 #[repr(transparent)]
194 pub struct Sender<T: Clone + crate::sync::TypeChannelName>(tokio::sync::broadcast::Sender<T>);
195
196 impl<T: Clone + crate::sync::TypeChannelName> Clone for Sender<T> {
197 fn clone(&self) -> Self {
198 Self(self.0.clone())
199 }
200 }
201
202 impl<T: Clone + crate::sync::TypeChannelName> Sender<T> {
203 #[track_caller]
207 pub fn send(&self, value: T) -> Result<usize, SendError<T>> {
208 let res = self.0.send(value);
209 if res.is_ok() {
210 super::detail::trace_pulse::<T>("broadcast", std::panic::Location::caller());
211 }
212 res
213 }
214
215 pub fn subscribe(&self) -> Receiver<T> {
217 self.0.subscribe()
218 }
219 }
220
221 impl<T: Clone + crate::sync::TypeChannelName> Deref for Sender<T> {
222 type Target = tokio::sync::broadcast::Sender<T>;
223 fn deref(&self) -> &Self::Target {
224 &self.0
225 }
226 }
227
228 impl<T: Clone + crate::sync::TypeChannelName> From<tokio::sync::broadcast::Sender<T>>
229 for Sender<T>
230 {
231 fn from(inner: tokio::sync::broadcast::Sender<T>) -> Self {
232 Self(inner)
233 }
234 }
235
236 impl<T: Clone + crate::sync::TypeChannelName> From<Sender<T>>
237 for tokio::sync::broadcast::Sender<T>
238 {
239 fn from(proxy: Sender<T>) -> Self {
240 proxy.0
241 }
242 }
243}
244
245#[cfg(debug_assertions)]
246pub use tokio::sync::{
247 Barrier, Mutex, Notify, OnceCell, OwnedRwLockReadGuard, OwnedRwLockWriteGuard,
248 OwnedSemaphorePermit, RwLock, RwLockReadGuard, RwLockWriteGuard, Semaphore, SemaphorePermit,
249 TryLockError, futures, oneshot, watch,
250};
251
252pub trait TypeChannelName {
257 const CHANNEL_NAME: &'static str;
259}
260
261#[macro_export]
273macro_rules! register_channel_name {
274 ($type_name:ty, $channel_name:expr) => {
275 #[cfg(debug_assertions)]
276 impl $crate::sync::TypeChannelName for $type_name {
277 const CHANNEL_NAME: &'static str = $channel_name;
278 }
279 };
280}
281
282#[cfg(debug_assertions)]
283mod detail {
284 use std::panic::Location;
285
286 #[inline(always)]
287 pub(super) fn trace_pulse<T: crate::sync::TypeChannelName>(
288 channel_type: &'static str,
289 location: &Location<'_>,
290 ) {
291 let type_name = std::any::type_name::<T>();
292 let short_type = type_name
293 .rsplit_once("::")
294 .map(|(_, s)| s)
295 .unwrap_or(type_name);
296
297 let file = location.file();
298 let filepath = if let Some((_, post_src)) = file.rsplit_once("src/") {
299 post_src
300 .strip_suffix(".rs")
301 .unwrap_or(post_src)
302 .strip_suffix("/mod")
303 .unwrap_or(post_src)
304 .replace(['/', '\\'], "::")
305 } else {
306 file.rsplit_once('/')
307 .or_else(|| file.rsplit_once('\\'))
308 .map(|(_, s)| s)
309 .unwrap_or(file)
310 .to_string()
311 };
312
313 let metric_name = format!(
314 "{}:{}:{}@{}",
315 T::CHANNEL_NAME,
316 channel_type,
317 short_type,
318 filepath
319 );
320 tracing::trace!(target: "telemetry", metric = %metric_name, value = 1.0);
321 }
322}
323
324#[cfg(test)]
325#[allow(clippy::disallowed_methods)]
326mod tests {
327 use super::*;
328
329 struct SemanticType;
330 register_channel_name!(SemanticType, "semantic_channel");
331
332 register_channel_name!(i32, "test_i32");
333
334 #[tokio::test]
335 async fn test_mpsc_proxy() {
336 let (tx, mut rx) = mpsc::channel::<i32>(1);
337 tx.send(42).await.unwrap();
338 assert_eq!(rx.recv().await.unwrap(), 42);
339
340 tx.try_send(43).unwrap();
341 assert_eq!(rx.recv().await.unwrap(), 43);
342
343 assert_eq!(tx.capacity(), 1);
345
346 let tokio_tx: tokio::sync::mpsc::Sender<i32> = tx.into();
348 tokio_tx.send(44).await.unwrap();
349 assert_eq!(rx.recv().await.unwrap(), 44);
350 }
351
352 #[tokio::test]
353 async fn test_unbounded_mpsc_proxy() {
354 let (tx, mut rx) = mpsc::unbounded_channel::<i32>();
355 tx.send(42).unwrap();
356 assert_eq!(rx.recv().await.unwrap(), 42);
357
358 assert!(!tx.is_closed());
360
361 let tokio_tx: tokio::sync::mpsc::UnboundedSender<i32> = tx.into();
363 tokio_tx.send(44).unwrap();
364 assert_eq!(rx.recv().await.unwrap(), 44);
365 }
366
367 #[tokio::test]
368 async fn test_broadcast_proxy() {
369 let (tx, mut rx1) = broadcast::channel::<i32>(10);
370 let mut rx2 = tx.subscribe();
371
372 tx.send(42).unwrap();
373 assert_eq!(rx1.recv().await.unwrap(), 42);
374 assert_eq!(rx2.recv().await.unwrap(), 42);
375
376 assert_eq!(tx.receiver_count(), 2);
378
379 let tokio_tx: tokio::sync::broadcast::Sender<i32> = tx.into();
381 tokio_tx.send(44).unwrap();
382 assert_eq!(rx1.recv().await.unwrap(), 44);
383 assert_eq!(rx2.recv().await.unwrap(), 44);
384 }
385
386 #[tokio::test]
387 async fn test_semantic_naming() {
388 let (tx, _rx) = mpsc::channel::<SemanticType>(1);
389 tx.send(SemanticType).await.unwrap();
390 }
393}