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. This channel allows only a fixed capacity and might have other optimizations.
76/// The send and receive methods will consume the Sender/Receiver.
77/// We will automatically select ipc or crossbeam channels.
78pub fn oneshot<T>() -> Option<(GenericOneshotSender<T>, GenericOneshotReceiver<T>)>
79where
80    T: for<'de> Deserialize<'de> + Serialize,
81{
82    if use_ipc() {
83        ipc_channel::ipc::channel()
84            .map(|(tx, rx)| {
85                (
86                    GenericOneshotSender(GenericSenderVariants::Ipc(tx)),
87                    GenericOneshotReceiver(GenericReceiverVariants::Ipc(rx)),
88                )
89            })
90            .ok()
91    } else {
92        let (rx, tx) = crossbeam_channel::bounded(1);
93        Some((
94            GenericOneshotSender(GenericSenderVariants::Crossbeam(rx)),
95            GenericOneshotReceiver(GenericReceiverVariants::Crossbeam(tx)),
96        ))
97    }
98}
99
100impl<T: Serialize> Serialize for GenericOneshotSender<T> {
101    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
102        serialize_generic_sender_variants(&self.0, s)
103    }
104}
105
106impl<'a, T: Serialize + Deserialize<'a>> Deserialize<'a> for GenericOneshotSender<T> {
107    fn deserialize<D>(d: D) -> Result<GenericOneshotSender<T>, D::Error>
108    where
109        D: Deserializer<'a>,
110    {
111        d.deserialize_enum(
112            "GenericSender",
113            &["Ipc", "Crossbeam"],
114            GenericSenderVisitor {
115                marker: PhantomData,
116            },
117        )
118        .map(|variant| GenericOneshotSender(variant))
119    }
120}
121
122impl<T: Serialize> fmt::Debug for GenericOneshotSender<T> {
123    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124        write!(f, "Sender(..)")
125    }
126}