1use std::fmt::Display;
8use std::marker::PhantomData;
9use std::panic::Location;
10#[cfg(feature = "multiprocess")]
11use std::sync::OnceLock;
12use std::time::Duration;
13use std::{fmt, io};
14
15use crossbeam_channel::RecvTimeoutError;
16use ipc_channel::router::ROUTER;
17use ipc_channel::{IpcError, SerDeError};
18use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
19use malloc_size_of_derive::MallocSizeOf;
20use serde::de::VariantAccess;
21use serde::{Deserialize, Deserializer, Serialize, Serializer};
22
23mod callback;
24pub use callback::GenericCallback;
25mod lazy_callback;
26pub use lazy_callback::{CallbackSetter, LazyCallback, lazy_callback};
27mod oneshot;
28mod shared_memory;
29pub use oneshot::{GenericOneshotReceiver, GenericOneshotSender, oneshot};
30pub use shared_memory::GenericSharedMemory;
31mod generic_channelset;
32pub use generic_channelset::{GenericReceiverSet, GenericSelectionResult};
33mod buffered;
34pub use buffered::GenericBufferedSender;
35
36#[cfg(feature = "multiprocess")]
38static USE_IPC: OnceLock<bool> = OnceLock::new();
39
40#[cfg(feature = "multiprocess")]
42fn use_ipc() -> bool {
43 *USE_IPC.get_or_init(|| {
44 servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc
45 })
46}
47
48#[cfg(not(feature = "multiprocess"))]
49fn use_ipc() -> bool {
50 false
51}
52
53pub trait GenericSend<T>
56where
57 T: serde::Serialize + for<'de> serde::Deserialize<'de>,
58{
59 fn send(&self, _: T) -> SendResult;
61
62 #[track_caller]
67 fn send_or_warn(&self, message: T) {
68 if let Err(error) = self.send(message) {
69 let location = Location::caller();
70 log::warn!("Failed to send msg due to `{error}` at {location:?}");
71 }
72 }
73
74 fn send_or_ignore(&self, message: T) {
80 let _ = self.send(message);
81 }
82
83 fn sender(&self) -> GenericSender<T>;
85}
86
87pub struct GenericSender<T: Serialize>(GenericSenderVariants<T>);
91
92enum GenericSenderVariants<T: Serialize> {
97 Ipc(ipc_channel::ipc::IpcSender<T>),
98 Crossbeam(crossbeam_channel::Sender<Result<T, SendError>>),
106}
107
108fn serialize_generic_sender_variants<T: Serialize, S: Serializer>(
109 value: &GenericSenderVariants<T>,
110 s: S,
111) -> Result<S::Ok, S::Error> {
112 match value {
113 GenericSenderVariants::Ipc(sender) => {
114 s.serialize_newtype_variant("GenericSender", 0, "Ipc", sender)
115 },
116 GenericSenderVariants::Crossbeam(sender) => {
127 if use_ipc() {
128 return Err(serde::ser::Error::custom(
129 "Crossbeam channel found in multiprocess mode!",
130 ));
131 } let sender_clone_addr = Box::leak(Box::new(sender.clone())) as *mut _ as usize;
134 s.serialize_newtype_variant("GenericSender", 1, "Crossbeam", &sender_clone_addr)
135 },
136 }
137}
138
139impl<T: Serialize> Serialize for GenericSender<T> {
140 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
141 serialize_generic_sender_variants(&self.0, s)
142 }
143}
144
145struct GenericSenderVisitor<T> {
146 marker: PhantomData<T>,
147}
148
149impl<'de, T: Serialize + Deserialize<'de>> serde::de::Visitor<'de> for GenericSenderVisitor<T> {
150 type Value = GenericSenderVariants<T>;
151
152 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
153 formatter.write_str("a GenericSender variant")
154 }
155
156 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
157 where
158 A: serde::de::EnumAccess<'de>,
159 {
160 #[derive(Deserialize)]
161 enum GenericSenderVariantNames {
162 Ipc,
163 Crossbeam,
164 }
165
166 let (variant_name, variant_data): (GenericSenderVariantNames, _) = data.variant()?;
167
168 match variant_name {
169 GenericSenderVariantNames::Ipc => variant_data
170 .newtype_variant::<ipc_channel::ipc::IpcSender<T>>()
171 .map(|sender| GenericSenderVariants::Ipc(sender)),
172 GenericSenderVariantNames::Crossbeam => {
173 if use_ipc() {
174 return Err(serde::de::Error::custom(
175 "Crossbeam channel found in multiprocess mode!",
176 ));
177 }
178 let addr = variant_data.newtype_variant::<usize>()?;
179 let ptr = addr as *mut crossbeam_channel::Sender<Result<T, SendError>>;
180 #[expect(unsafe_code)]
183 let sender = unsafe { Box::from_raw(ptr) };
184 Ok(GenericSenderVariants::Crossbeam(*sender))
185 },
186 }
187 }
188}
189
190impl<'a, T: Serialize + Deserialize<'a>> Deserialize<'a> for GenericSender<T> {
191 fn deserialize<D>(d: D) -> Result<GenericSender<T>, D::Error>
192 where
193 D: Deserializer<'a>,
194 {
195 d.deserialize_enum(
196 "GenericSender",
197 &["Ipc", "Crossbeam"],
198 GenericSenderVisitor {
199 marker: PhantomData,
200 },
201 )
202 .map(|variant| GenericSender(variant))
203 }
204}
205
206impl<T> Clone for GenericSender<T>
207where
208 T: Serialize,
209{
210 fn clone(&self) -> Self {
211 match &self.0 {
212 GenericSenderVariants::Ipc(chan) => {
213 GenericSender(GenericSenderVariants::Ipc(chan.clone()))
214 },
215 GenericSenderVariants::Crossbeam(chan) => {
216 GenericSender(GenericSenderVariants::Crossbeam(chan.clone()))
217 },
218 }
219 }
220}
221
222impl<T: Serialize> fmt::Debug for GenericSender<T> {
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 write!(f, "Sender(..)")
225 }
226}
227
228impl<T: Serialize> GenericSender<T> {
229 #[inline]
230 pub fn send(&self, msg: T) -> SendResult {
231 match &self.0 {
232 GenericSenderVariants::Ipc(sender) => sender
233 .send(msg)
234 .map_err(|e| SendError::SerializationError(e.to_string())),
235 GenericSenderVariants::Crossbeam(sender) => {
236 sender.send(Ok(msg)).map_err(|_| SendError::Disconnected)
237 },
238 }
239 }
240
241 #[inline]
246 pub fn send_or_warn(&self, msg: T) {
247 if let Err(error) = self.send(msg) {
248 let location = Location::caller();
249 log::warn!("Failed to send msg due to `{error}` at {location:?}");
250 }
251 }
252
253 #[inline]
259 pub fn send_or_ignore(&self, msg: T) {
260 let _ = self.send(msg);
261 }
262}
263
264impl<T: Serialize> MallocSizeOf for GenericSender<T> {
265 fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
266 match &self.0 {
267 GenericSenderVariants::Ipc(ipc_sender) => ipc_sender.size_of(ops),
268 GenericSenderVariants::Crossbeam(sender) => sender.size_of(ops),
269 }
270 }
271}
272
273#[derive(Debug)]
274pub enum SendError {
275 Disconnected,
276 SerializationError(String),
277}
278
279impl From<IpcError> for SendError {
280 fn from(value: IpcError) -> Self {
281 match value {
282 IpcError::SerializationError(ser_de_error) => {
283 SendError::SerializationError(ser_de_error.to_string())
284 },
285 IpcError::Io(error) => {
286 log::error!("IO Error in ipc {:?}", error);
287 SendError::Disconnected
288 },
289 IpcError::Disconnected => SendError::Disconnected,
290 }
291 }
292}
293
294impl From<SerDeError> for SendError {
295 fn from(value: SerDeError) -> Self {
296 SendError::SerializationError(value.to_string())
297 }
298}
299
300impl From<io::Error> for SendError {
301 fn from(value: io::Error) -> Self {
302 log::error!("IO Error in IPC {:?}", value);
303 SendError::Disconnected
304 }
305}
306
307impl Display for SendError {
308 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
309 write!(f, "{self:?}")
310 }
311}
312
313pub type SendResult = Result<(), SendError>;
314
315#[derive(Debug)]
316pub enum ReceiveError {
317 DeserializationFailed(String),
318 Io(std::io::Error),
320 Disconnected,
322}
323
324impl From<IpcError> for ReceiveError {
325 fn from(e: IpcError) -> Self {
326 match e {
327 IpcError::Disconnected => ReceiveError::Disconnected,
328 IpcError::Io(reason) => ReceiveError::Io(reason),
329 IpcError::SerializationError(ser_de_error) => {
330 ReceiveError::DeserializationFailed(ser_de_error.to_string())
331 },
332 }
333 }
334}
335
336impl From<crossbeam_channel::RecvError> for ReceiveError {
337 fn from(_: crossbeam_channel::RecvError) -> Self {
338 ReceiveError::Disconnected
339 }
340}
341
342impl fmt::Display for ReceiveError {
343 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
344 match *self {
345 ReceiveError::DeserializationFailed(ref error) => {
346 write!(fmt, "deserialization error: {error}")
347 },
348 ReceiveError::Io(ref error) => write!(fmt, "io error: {error}"),
349 ReceiveError::Disconnected => write!(fmt, "disconnected"),
350 }
351 }
352}
353impl From<std::io::Error> for ReceiveError {
354 fn from(value: std::io::Error) -> Self {
355 ReceiveError::Io(value)
356 }
357}
358
359pub enum TryReceiveError {
360 Empty,
361 ReceiveError(ReceiveError),
362}
363
364impl From<crossbeam_channel::RecvTimeoutError> for TryReceiveError {
365 fn from(value: crossbeam_channel::RecvTimeoutError) -> Self {
366 match value {
367 RecvTimeoutError::Timeout => TryReceiveError::Empty,
368 RecvTimeoutError::Disconnected => {
369 TryReceiveError::ReceiveError(ReceiveError::Disconnected)
370 },
371 }
372 }
373}
374
375impl From<ipc_channel::TryRecvError> for TryReceiveError {
376 fn from(e: ipc_channel::TryRecvError) -> Self {
377 match e {
378 ipc_channel::TryRecvError::Empty => TryReceiveError::Empty,
379 ipc_channel::TryRecvError::IpcError(inner) => {
380 TryReceiveError::ReceiveError(inner.into())
381 },
382 }
383 }
384}
385
386impl From<crossbeam_channel::TryRecvError> for TryReceiveError {
387 fn from(e: crossbeam_channel::TryRecvError) -> Self {
388 match e {
389 crossbeam_channel::TryRecvError::Empty => TryReceiveError::Empty,
390 crossbeam_channel::TryRecvError::Disconnected => {
391 TryReceiveError::ReceiveError(ReceiveError::Disconnected)
392 },
393 }
394 }
395}
396
397pub type RoutedReceiver<T> = crossbeam_channel::Receiver<Result<T, SendError>>;
398pub type ReceiveResult<T> = Result<T, ReceiveError>;
399pub type TryReceiveResult<T> = Result<T, TryReceiveError>;
400pub type RoutedReceiverReceiveResult<T> =
401 Result<Result<T, SendError>, crossbeam_channel::RecvError>;
402
403pub fn to_receive_result<T>(receive_result: RoutedReceiverReceiveResult<T>) -> ReceiveResult<T> {
404 match receive_result {
405 Ok(Ok(msg)) => Ok(msg),
406 Err(_crossbeam_recv_err) => Err(ReceiveError::Disconnected),
407 Ok(Err(ipc_err)) => Err(ReceiveError::DeserializationFailed(ipc_err.to_string())),
408 }
409}
410
411#[derive(MallocSizeOf)]
412pub struct GenericReceiver<T>(GenericReceiverVariants<T>)
413where
414 T: for<'de> Deserialize<'de> + Serialize;
415
416impl<T> std::fmt::Debug for GenericReceiver<T>
417where
418 T: for<'de> Deserialize<'de> + Serialize,
419{
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 f.debug_tuple("GenericReceiver").finish()
422 }
423}
424
425#[derive(MallocSizeOf)]
426enum GenericReceiverVariants<T>
427where
428 T: for<'de> Deserialize<'de> + Serialize,
429{
430 Ipc(ipc_channel::ipc::IpcReceiver<T>),
431 Crossbeam(RoutedReceiver<T>),
432}
433
434impl<T> GenericReceiver<T>
435where
436 T: for<'de> Deserialize<'de> + Serialize,
437{
438 #[inline]
439 pub fn recv(&self) -> ReceiveResult<T> {
440 match &self.0 {
441 GenericReceiverVariants::Ipc(receiver) => Ok(receiver.recv()?),
442 GenericReceiverVariants::Crossbeam(receiver) => {
443 let msg = receiver.recv()?;
445 Ok(msg.expect("Infallible"))
448 },
449 }
450 }
451
452 #[inline]
453 pub fn try_recv(&self) -> TryReceiveResult<T> {
454 match &self.0 {
455 GenericReceiverVariants::Ipc(receiver) => Ok(receiver.try_recv()?),
456 GenericReceiverVariants::Crossbeam(receiver) => {
457 let msg = receiver.try_recv()?;
458 Ok(msg.expect("Infallible"))
459 },
460 }
461 }
462
463 #[inline]
465 pub fn try_recv_timeout(&self, timeout: Duration) -> Result<T, TryReceiveError> {
466 match &self.0 {
467 GenericReceiverVariants::Ipc(ipc_receiver) => {
468 ipc_receiver.try_recv_timeout(timeout).map_err(|e| e.into())
469 },
470 GenericReceiverVariants::Crossbeam(receiver) => match receiver.recv_timeout(timeout) {
471 Ok(Ok(value)) => Ok(value),
472 Ok(Err(_)) => unreachable!("Infallable"),
473 Err(RecvTimeoutError::Disconnected) => {
474 Err(TryReceiveError::ReceiveError(ReceiveError::Disconnected))
475 },
476 Err(RecvTimeoutError::Timeout) => Err(TryReceiveError::Empty),
477 },
478 }
479 }
480
481 #[inline]
486 pub fn route_preserving_errors(self) -> RoutedReceiver<T>
487 where
488 T: Send + 'static,
489 {
490 match self.0 {
491 GenericReceiverVariants::Ipc(ipc_receiver) => {
492 let (crossbeam_sender, crossbeam_receiver) = crossbeam_channel::unbounded();
493 let crossbeam_sender_clone = crossbeam_sender;
494 ROUTER.add_typed_route(
495 ipc_receiver,
496 Box::new(move |message| {
497 let _ = crossbeam_sender_clone.send(message.map_err(|e| e.into()));
498 }),
499 );
500 crossbeam_receiver
501 },
502 GenericReceiverVariants::Crossbeam(receiver) => receiver,
503 }
504 }
505}
506
507impl<T> Serialize for GenericReceiver<T>
508where
509 T: for<'de> Deserialize<'de> + Serialize,
510{
511 fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
512 match &self.0 {
513 GenericReceiverVariants::Ipc(receiver) => {
514 s.serialize_newtype_variant("GenericReceiver", 0, "Ipc", receiver)
515 },
516 GenericReceiverVariants::Crossbeam(receiver) => {
517 if use_ipc() {
518 return Err(serde::ser::Error::custom(
519 "Crossbeam channel found in multiprocess mode!",
520 ));
521 } let receiver_clone_addr = Box::leak(Box::new(receiver.clone())) as *mut _ as usize;
524 s.serialize_newtype_variant("GenericReceiver", 1, "Crossbeam", &receiver_clone_addr)
525 },
526 }
527 }
528}
529
530struct GenericReceiverVisitor<T> {
531 marker: PhantomData<T>,
532}
533impl<'de, T> serde::de::Visitor<'de> for GenericReceiverVisitor<T>
534where
535 T: for<'a> Deserialize<'a> + Serialize,
536{
537 type Value = GenericReceiver<T>;
538
539 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
540 formatter.write_str("a GenericReceiver variant")
541 }
542
543 fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
544 where
545 A: serde::de::EnumAccess<'de>,
546 {
547 #[derive(Deserialize)]
548 enum GenericReceiverVariantNames {
549 Ipc,
550 Crossbeam,
551 }
552
553 let (variant_name, variant_data): (GenericReceiverVariantNames, _) = data.variant()?;
554
555 match variant_name {
556 GenericReceiverVariantNames::Ipc => variant_data
557 .newtype_variant::<ipc_channel::ipc::IpcReceiver<T>>()
558 .map(|receiver| GenericReceiver(GenericReceiverVariants::Ipc(receiver))),
559 GenericReceiverVariantNames::Crossbeam => {
560 if use_ipc() {
561 return Err(serde::de::Error::custom(
562 "Crossbeam channel found in multiprocess mode!",
563 ));
564 }
565 let addr = variant_data.newtype_variant::<usize>()?;
566 let ptr = addr as *mut RoutedReceiver<T>;
567 #[expect(unsafe_code)]
570 let receiver = unsafe { Box::from_raw(ptr) };
571 Ok(GenericReceiver(GenericReceiverVariants::Crossbeam(
572 *receiver,
573 )))
574 },
575 }
576 }
577}
578
579impl<'a, T> Deserialize<'a> for GenericReceiver<T>
580where
581 T: for<'de> Deserialize<'de> + Serialize,
582{
583 fn deserialize<D>(d: D) -> Result<GenericReceiver<T>, D::Error>
584 where
585 D: Deserializer<'a>,
586 {
587 d.deserialize_enum(
588 "GenericReceiver",
589 &["Ipc", "Crossbeam"],
590 GenericReceiverVisitor {
591 marker: PhantomData,
592 },
593 )
594 }
595}
596
597fn new_generic_channel_crossbeam<T>() -> (GenericSender<T>, GenericReceiver<T>)
601where
602 T: Serialize + for<'de> serde::Deserialize<'de>,
603{
604 let (tx, rx) = crossbeam_channel::unbounded();
605 (
606 GenericSender(GenericSenderVariants::Crossbeam(tx)),
607 GenericReceiver(GenericReceiverVariants::Crossbeam(rx)),
608 )
609}
610
611fn new_generic_channel_ipc<T>() -> Result<(GenericSender<T>, GenericReceiver<T>), std::io::Error>
612where
613 T: Serialize + for<'de> serde::Deserialize<'de>,
614{
615 ipc_channel::ipc::channel().map(|(tx, rx)| {
616 (
617 GenericSender(GenericSenderVariants::Ipc(tx)),
618 GenericReceiver(GenericReceiverVariants::Ipc(rx)),
619 )
620 })
621}
622
623pub fn channel<T>() -> Option<(GenericSender<T>, GenericReceiver<T>)>
627where
628 T: for<'de> Deserialize<'de> + Serialize,
629{
630 if use_ipc() {
631 new_generic_channel_ipc().ok()
632 } else {
633 Some(new_generic_channel_crossbeam())
634 }
635}
636
637#[cfg(test)]
638mod single_process_channel_tests {
639 use crate::generic_channel::{new_generic_channel_crossbeam, new_generic_channel_ipc};
644
645 #[test]
646 fn generic_crossbeam_can_send() {
647 let (tx, rx) = new_generic_channel_crossbeam();
648 tx.send(5).expect("Send failed");
649 let val = rx.recv().expect("Receive failed");
650 assert_eq!(val, 5);
651 }
652
653 #[test]
654 fn generic_crossbeam_ping_pong() {
655 let (tx, rx) = new_generic_channel_crossbeam();
656 let (tx2, rx2) = new_generic_channel_crossbeam();
657
658 tx.send(tx2).expect("Send failed");
659
660 std::thread::scope(|s| {
661 s.spawn(move || {
662 let reply_sender = rx.recv().expect("Receive failed");
663 reply_sender.send(42).expect("Sending reply failed");
664 });
665 });
666 let res = rx2.recv().expect("Receive of reply failed");
667 assert_eq!(res, 42);
668 }
669
670 #[test]
671 fn generic_ipc_ping_pong() {
672 let (tx, rx) = new_generic_channel_ipc().unwrap();
673 let (tx2, rx2) = new_generic_channel_ipc().unwrap();
674
675 tx.send(tx2).expect("Send failed");
676
677 std::thread::scope(|s| {
678 s.spawn(move || {
679 let reply_sender = rx.recv().expect("Receive failed");
680 reply_sender.send(42).expect("Sending reply failed");
681 });
682 });
683 let res = rx2.recv().expect("Receive of reply failed");
684 assert_eq!(res, 42);
685 }
686
687 #[test]
688 fn send_crossbeam_sender_over_ipc_channel() {
689 let (tx, rx) = new_generic_channel_ipc().unwrap();
690 let (tx2, rx2) = new_generic_channel_crossbeam();
691
692 tx.send(tx2).expect("Send failed");
693
694 std::thread::scope(|s| {
695 s.spawn(move || {
696 let reply_sender = rx.recv().expect("Receive failed");
697 reply_sender.send(42).expect("Sending reply failed");
698 });
699 });
700 let res = rx2.recv().expect("Receive of reply failed");
701 assert_eq!(res, 42);
702 }
703
704 #[test]
705 fn send_generic_ipc_channel_over_crossbeam() {
706 let (tx, rx) = new_generic_channel_crossbeam();
707 let (tx2, rx2) = new_generic_channel_ipc().unwrap();
708
709 tx.send(tx2).expect("Send failed");
710
711 std::thread::scope(|s| {
712 s.spawn(move || {
713 let reply_sender = rx.recv().expect("Receive failed");
714 reply_sender.send(42).expect("Sending reply failed");
715 });
716 });
717 let res = rx2.recv().expect("Receive of reply failed");
718 assert_eq!(res, 42);
719 }
720
721 #[test]
722 fn send_crossbeam_receiver_over_ipc_channel() {
723 let (tx, rx) = new_generic_channel_ipc().unwrap();
724 let (tx2, rx2) = new_generic_channel_crossbeam();
725
726 tx.send(rx2).expect("Send failed");
727 tx2.send(42).expect("Send failed");
728
729 std::thread::scope(|s| {
730 s.spawn(move || {
731 let another_receiver = rx.recv().expect("Receive failed");
732 let res = another_receiver.recv().expect("Receive failed");
733 assert_eq!(res, 42);
734 });
735 });
736 }
737
738 #[test]
739 fn test_timeout_ipc() {
740 let (tx, rx) = new_generic_channel_ipc().unwrap();
741 let timeout_duration = std::time::Duration::from_secs(3);
742 std::thread::spawn(move || {
743 std::thread::sleep(timeout_duration - std::time::Duration::from_secs(1));
744 assert!(tx.send(()).is_ok());
745 });
746 let received = rx.try_recv_timeout(timeout_duration);
747 assert!(received.is_ok());
748 }
749
750 #[test]
751 fn test_timeout_crossbeam() {
752 let (tx, rx) = new_generic_channel_crossbeam();
753 let timeout_duration = std::time::Duration::from_secs(3);
754 std::thread::spawn(move || {
755 std::thread::sleep(timeout_duration - std::time::Duration::from_secs(1));
756 assert!(tx.send(()).is_ok());
757 });
758 let received = rx.try_recv_timeout(timeout_duration);
759 assert!(received.is_ok());
760 }
761}
762
763#[cfg(test)]
765mod generic_receiversets_tests {
766 use std::time::Duration;
767
768 use crate::generic_channel::generic_channelset::{
769 GenericSelectionResult, create_crossbeam_receiver_set, create_ipc_receiver_set,
770 };
771 use crate::generic_channel::{new_generic_channel_crossbeam, new_generic_channel_ipc};
772
773 #[test]
774 fn test_ipc_side1() {
775 let (snd1, recv1) = new_generic_channel_ipc().unwrap();
776 let (snd2, recv2) = new_generic_channel_ipc().unwrap();
777
778 let snd1_c = snd1.clone();
780 let snd2_c = snd2.clone();
781 let mut set = create_ipc_receiver_set();
782 let recv1_select_index = set.add(recv1);
783 let _recv2_select_index = set.add(recv2);
784
785 std::thread::spawn(move || {
786 snd1_c.send(10).unwrap();
787 });
788 std::thread::spawn(move || {
789 std::thread::sleep(Duration::from_secs(1));
790 let _ = snd2_c.send(20); });
792
793 let select_result = set.select();
794 let channel_result = select_result.first().unwrap();
795 assert_eq!(
796 *channel_result,
797 GenericSelectionResult::MessageReceived(recv1_select_index, 10)
798 );
799 }
800
801 #[test]
802 fn test_ipc_side2() {
803 let (snd1, recv1) = new_generic_channel_ipc().unwrap();
804 let (snd2, recv2) = new_generic_channel_ipc().unwrap();
805
806 let snd1_c = snd1.clone();
808 let snd2_c = snd2.clone();
809 let mut set = create_ipc_receiver_set();
810 let _recv1_select_index = set.add(recv1);
811 let recv2_select_index = set.add(recv2);
812
813 std::thread::spawn(move || {
814 std::thread::sleep(Duration::from_secs(1));
815 let _ = snd1_c.send(10);
816 });
817 std::thread::spawn(move || {
818 snd2_c.send(20).unwrap();
819 });
820
821 let select_result = set.select();
822 let channel_result = select_result.first().unwrap();
823 assert_eq!(
824 *channel_result,
825 GenericSelectionResult::MessageReceived(recv2_select_index, 20)
826 );
827 }
828
829 #[test]
830 fn test_crossbeam_side1() {
831 let (snd1, recv1) = new_generic_channel_crossbeam();
832 let (snd2, recv2) = new_generic_channel_crossbeam();
833
834 let snd1_c = snd1.clone();
836 let snd2_c = snd2.clone();
837 let mut set = create_crossbeam_receiver_set();
838 let recv1_select_index = set.add(recv1);
839 let _recv2_select_index = set.add(recv2);
840
841 std::thread::spawn(move || {
842 snd1_c.send(10).unwrap();
843 });
844 std::thread::spawn(move || {
845 std::thread::sleep(Duration::from_secs(2));
846 let _ = snd2_c.send(20);
847 });
848
849 let select_result = set.select();
850 let channel_result = select_result.first().unwrap();
851 assert_eq!(
852 *channel_result,
853 GenericSelectionResult::MessageReceived(recv1_select_index, 10)
854 );
855 }
856
857 #[test]
858 fn test_crossbeam_side2() {
859 let (snd1, recv1) = new_generic_channel_crossbeam();
860 let (snd2, recv2) = new_generic_channel_crossbeam();
861
862 let snd1_c = snd1.clone();
864 let snd2_c = snd2.clone();
865 let mut set = create_crossbeam_receiver_set();
866 let _recv1_select_index = set.add(recv1);
867 let recv2_select_index = set.add(recv2);
868
869 std::thread::spawn(move || {
870 std::thread::sleep(Duration::from_secs(2));
871 let _ = snd1_c.send(10);
872 });
873 std::thread::spawn(move || {
874 snd2_c.send(20).unwrap();
875 });
876
877 let select_result = set.select();
878 let channel_result = select_result.first().unwrap();
879 assert_eq!(
880 *channel_result,
881 GenericSelectionResult::MessageReceived(recv2_select_index, 20)
882 );
883 }
884
885 #[test]
886 fn test_ipc_no_crash_on_disconnect() {
887 let (snd1, recv1) = new_generic_channel_ipc().unwrap();
890 let (snd2, recv2) = new_generic_channel_ipc().unwrap();
891
892 let snd1_c = snd1.clone();
894 let mut set = create_ipc_receiver_set();
895 let _recv1_select_index = set.add(recv1);
896 let recv2_select_index = set.add(recv2);
897
898 std::thread::spawn(move || {
899 std::thread::sleep(Duration::from_secs(2));
900 let _ = snd1_c.send(10);
901 });
902 std::thread::spawn(move || {
903 snd2.send(20).unwrap();
904 });
905 std::thread::sleep(Duration::from_secs(1));
906 let select_result = set.select();
907 let channel_result = select_result.first().unwrap();
908 assert_eq!(
909 *channel_result,
910 GenericSelectionResult::MessageReceived(recv2_select_index, 20)
911 );
912 }
913
914 #[test]
915 fn test_crossbeam_no_crash_on_disconnect() {
916 let (snd1, recv1) = new_generic_channel_crossbeam();
918 let (snd2, recv2) = new_generic_channel_crossbeam();
919
920 let snd1_c = snd1.clone();
922 let mut set = create_crossbeam_receiver_set();
923 let _recv1_select_index = set.add(recv1);
924 let recv2_select_index = set.add(recv2);
925
926 std::thread::spawn(move || {
927 std::thread::sleep(Duration::from_secs(2));
928 let _ = snd1_c.send(10);
929 });
930 std::thread::spawn(move || {
931 snd2.send(20).unwrap();
932 });
933 std::thread::sleep(Duration::from_secs(1));
934 let select_result = set.select();
935 let channel_result = select_result.first().unwrap();
936 assert_eq!(
937 *channel_result,
938 GenericSelectionResult::MessageReceived(recv2_select_index, 20)
939 );
940 }
941
942 #[test]
943 fn test_ipc_disconnect_correct_message() {
944 let (snd1, recv1) = new_generic_channel_ipc().unwrap();
946 let (snd2, recv2) = new_generic_channel_ipc().unwrap();
947
948 let snd1_c = snd1.clone();
950 let mut set = create_ipc_receiver_set();
951 let _recv1_select_index = set.add(recv1);
952 let recv2_select_index = set.add(recv2);
953
954 std::thread::spawn(move || {
955 std::thread::sleep(Duration::from_secs(2));
956 let _ = snd1_c.send(10);
957 });
958 std::thread::spawn(move || {
959 drop(snd2);
960 });
961
962 let select_result = set.select();
963 let channel_result = select_result.first().unwrap();
964 assert_eq!(
965 *channel_result,
966 GenericSelectionResult::ChannelClosed(recv2_select_index)
967 );
968 }
969
970 #[test]
971 fn test_crossbeam_disconnect_correct_messaget() {
972 let (snd1, recv1) = new_generic_channel_crossbeam();
973 let (snd2, recv2) = new_generic_channel_crossbeam();
974
975 let snd1_c = snd1.clone();
977 let mut set = create_crossbeam_receiver_set();
978 let _recv1_select_index = set.add(recv1);
979 let recv2_select_index = set.add(recv2);
980
981 std::thread::spawn(move || {
982 std::thread::sleep(Duration::from_secs(2));
983 let _ = snd1_c.send(10);
984 });
985 std::thread::spawn(move || {
986 drop(snd2);
987 });
988
989 let select_result = set.select();
990 let channel_result = select_result.first().unwrap();
991 assert_eq!(
992 *channel_result,
993 GenericSelectionResult::ChannelClosed(recv2_select_index)
994 );
995 }
996}