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;
7
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9
10use crate::generic_channel::{
11    GenericReceiverVariants, GenericSenderVariants, GenericSenderVisitor, ReceiveResult, SendError,
12    SendResult, serialize_generic_sender_variants,
13};
14
15/// The oneshot sender struct
16pub struct GenericOneshotSender<T: Serialize>(GenericSenderVariants<T>);
17
18impl<T: Serialize> GenericOneshotSender<T> {
19    #[inline]
20    /// Send a message across the channel
21    pub fn send(self, msg: T) -> SendResult {
22        match self.0 {
23            GenericSenderVariants::Ipc(ref sender) => sender
24                .send(msg)
25                .map_err(|e| SendError::SerializationError(format!("{e}"))),
26            GenericSenderVariants::Crossbeam(ref sender) => {
27                sender.send(Ok(msg)).map_err(|_| SendError::Disconnected)
28            },
29        }
30    }
31}
32
33impl<T> GenericOneshotReceiver<T>
34where
35    T: for<'de> Deserialize<'de> + Serialize,
36{
37    #[inline]
38    /// Receive a message across the channel
39    pub fn recv(self) -> ReceiveResult<T> {
40        match self.0 {
41            GenericReceiverVariants::Ipc(ref receiver) => Ok(receiver.recv()?),
42            GenericReceiverVariants::Crossbeam(ref receiver) => {
43                // `recv()` returns an error if the channel is disconnected
44                let msg = receiver.recv()?;
45                // `msg` must be `ok` because the corresponding [`GenericSender::Crossbeam`] will
46                // unconditionally send an `Ok(T)`
47                Ok(msg.expect("Infallible"))
48            },
49        }
50    }
51}
52
53/// The oneshot receiver struct
54pub struct GenericOneshotReceiver<T: Serialize + for<'de> Deserialize<'de>>(
55    GenericReceiverVariants<T>,
56);
57
58/// Creates a oneshot generic channel. This channel allows only a fixed capacity and might have other optimizations.
59/// The send and receive methods will consume the Sender/Receiver.
60/// We will automatically select ipc or crossbeam channels.
61pub fn oneshot<T>() -> Option<(GenericOneshotSender<T>, GenericOneshotReceiver<T>)>
62where
63    T: for<'de> Deserialize<'de> + Serialize,
64{
65    if servo_config::opts::get().multiprocess || servo_config::opts::get().force_ipc {
66        ipc_channel::ipc::channel()
67            .map(|(tx, rx)| {
68                (
69                    GenericOneshotSender(GenericSenderVariants::Ipc(tx)),
70                    GenericOneshotReceiver(GenericReceiverVariants::Ipc(rx)),
71                )
72            })
73            .ok()
74    } else {
75        let (rx, tx) = crossbeam_channel::bounded(1);
76        Some((
77            GenericOneshotSender(GenericSenderVariants::Crossbeam(rx)),
78            GenericOneshotReceiver(GenericReceiverVariants::Crossbeam(tx)),
79        ))
80    }
81}
82
83impl<T: Serialize> Serialize for GenericOneshotSender<T> {
84    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
85        serialize_generic_sender_variants(&self.0, s)
86    }
87}
88
89impl<'a, T: Serialize + Deserialize<'a>> Deserialize<'a> for GenericOneshotSender<T> {
90    fn deserialize<D>(d: D) -> Result<GenericOneshotSender<T>, D::Error>
91    where
92        D: Deserializer<'a>,
93    {
94        d.deserialize_enum(
95            "GenericSender",
96            &["Ipc", "Crossbeam"],
97            GenericSenderVisitor {
98                marker: PhantomData,
99            },
100        )
101        .map(|variant| GenericOneshotSender(variant))
102    }
103}
104
105impl<T: Serialize> fmt::Debug for GenericOneshotSender<T> {
106    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107        write!(f, "Sender(..)")
108    }
109}