Skip to main content

servo_base/generic_channel/
oneshot.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::fmt;
6use std::marker::PhantomData;
7use std::panic::Location;
8
9use serde::{Deserialize, Deserializer, Serialize, Serializer};
10
11use crate::generic_channel::{
12    GenericReceiverVariants, GenericSenderVariants, GenericSenderVisitor, ReceiveResult, SendError,
13    SendResult, serialize_generic_sender_variants, use_ipc,
14};
15
16/// The oneshot sender struct
17pub struct GenericOneshotSender<T: Serialize>(GenericSenderVariants<T>);
18
19impl<T: Serialize> GenericOneshotSender<T> {
20    #[inline]
21    /// Send a message across the channel
22    pub fn send(self, msg: T) -> SendResult {
23        match self.0 {
24            GenericSenderVariants::Ipc(ref sender) => sender
25                .send(msg)
26                .map_err(|e| SendError::SerializationError(format!("{e}"))),
27            GenericSenderVariants::Crossbeam(ref sender) => {
28                sender.send(Ok(msg)).map_err(|_| SendError::Disconnected)
29            },
30        }
31    }
32
33    #[inline]
34    #[track_caller]
35    /// Send a message across the channel or log a warning if it fails
36    pub fn send_or_warn(self, msg: T) {
37        if let Err(error) = self.send(msg) {
38            let location = Location::caller();
39            log::warn!("Failed to send msg due to `{error}` at {location:?}");
40        }
41    }
42
43    #[inline]
44    /// Send a message across the channel, ignoring the result.
45    pub fn send_or_ignore(self, msg: T) {
46        let _ = self.send(msg);
47    }
48}
49
50impl<T> GenericOneshotReceiver<T>
51where
52    T: for<'de> Deserialize<'de> + Serialize,
53{
54    #[inline]
55    /// Receive a message across the channel
56    pub fn recv(self) -> ReceiveResult<T> {
57        match self.0 {
58            GenericReceiverVariants::Ipc(ref receiver) => Ok(receiver.recv()?),
59            GenericReceiverVariants::Crossbeam(ref receiver) => {
60                // `recv()` returns an error if the channel is disconnected
61                let msg = receiver.recv()?;
62                // `msg` must be `ok` because the corresponding [`GenericSender::Crossbeam`] will
63                // unconditionally send an `Ok(T)`
64                Ok(msg.expect("Infallible"))
65            },
66        }
67    }
68}
69
70/// The oneshot receiver struct
71pub struct GenericOneshotReceiver<T: Serialize + for<'de> Deserialize<'de>>(
72    GenericReceiverVariants<T>,
73);
74
75/// Creates a oneshot generic channel used to send only a single message, similar tokio::sync::oneshot.
76/// This is not the same as ipc_channel::oneshot.
77/// The send and receive methods will consume the Sender/Receiver.
78/// We will automatically select ipc or crossbeam channels.
79pub fn oneshot<T>() -> Option<(GenericOneshotSender<T>, GenericOneshotReceiver<T>)>
80where
81    T: for<'de> Deserialize<'de> + Serialize,
82{
83    if use_ipc() {
84        ipc_channel::ipc::channel()
85            .map(|(tx, rx)| {
86                (
87                    GenericOneshotSender(GenericSenderVariants::Ipc(tx)),
88                    GenericOneshotReceiver(GenericReceiverVariants::Ipc(rx)),
89                )
90            })
91            .ok()
92    } else {
93        let (rx, tx) = crossbeam_channel::bounded(1);
94        Some((
95            GenericOneshotSender(GenericSenderVariants::Crossbeam(rx)),
96            GenericOneshotReceiver(GenericReceiverVariants::Crossbeam(tx)),
97        ))
98    }
99}
100
101impl<T: Serialize> Serialize for GenericOneshotSender<T> {
102    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
103        serialize_generic_sender_variants(&self.0, s)
104    }
105}
106
107impl<'a, T: Serialize + Deserialize<'a>> Deserialize<'a> for GenericOneshotSender<T> {
108    fn deserialize<D>(d: D) -> Result<GenericOneshotSender<T>, D::Error>
109    where
110        D: Deserializer<'a>,
111    {
112        d.deserialize_enum(
113            "GenericSender",
114            &["Ipc", "Crossbeam"],
115            GenericSenderVisitor {
116                marker: PhantomData,
117            },
118        )
119        .map(|variant| GenericOneshotSender(variant))
120    }
121}
122
123impl<T: Serialize> fmt::Debug for GenericOneshotSender<T> {
124    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
125        write!(f, "Sender(..)")
126    }
127}