From f492cbf8c14835df67f8ec4e1efeff9bf84fa4ac Mon Sep 17 00:00:00 2001 From: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Date: Thu, 14 Aug 2025 20:28:58 +0200 Subject: [PATCH] base: Allow sending GenericReceiver (#38636) Implement Serialize and Deserialize for GenericReceiver to also allow the Receiver to be sent across ipc channels. This is necessary to allow using the GenericChannel in more places. Testing: Manually tested on follow-up feature branch. Does not require new tests. --------- Signed-off-by: Jonathan Schwender Signed-off-by: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Co-authored-by: Martin Robinson --- components/shared/base/generic_channel.rs | 38 +++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/components/shared/base/generic_channel.rs b/components/shared/base/generic_channel.rs index 18bbbfd0f86..2cd56394abe 100644 --- a/components/shared/base/generic_channel.rs +++ b/components/shared/base/generic_channel.rs @@ -9,6 +9,10 @@ use std::fmt; use ipc_channel::router::ROUTER; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +static GENERIC_CHANNEL_USAGE_ERROR_PANIC_MSG: &str = "May not send a crossbeam channel over an IPC channel. \ + Please also convert the ipc-channel you want to send this GenericReceiver over \ + into a GenericChannel."; + pub enum GenericSender { Ipc(ipc_channel::ipc::IpcSender), Crossbeam(crossbeam_channel::Sender), @@ -18,7 +22,7 @@ impl Serialize for GenericSender { fn serialize(&self, s: S) -> Result { match self { GenericSender::Ipc(i) => i.serialize(s), - GenericSender::Crossbeam(_) => unreachable!(), + GenericSender::Crossbeam(_) => panic!("{GENERIC_CHANNEL_USAGE_ERROR_PANIC_MSG}"), } } } @@ -28,8 +32,8 @@ impl<'a, T: Serialize> Deserialize<'a> for GenericSender { where D: Deserializer<'a>, { - // Only ipc_channle will encounter deserialize scenario. - ipc_channel::ipc::IpcSender::::deserialize(d).map(|s| GenericSender::Ipc(s)) + // Only ipc_channel will encounter deserialize scenario. + ipc_channel::ipc::IpcSender::::deserialize(d).map(GenericSender::Ipc) } } @@ -81,6 +85,7 @@ impl GenericReceiver where T: for<'de> Deserialize<'de> + Serialize, { + #[inline] pub fn recv(&self) -> ReceiveResult { match *self { GenericReceiver::Ipc(ref receiver) => receiver.recv().map_err(|_| ReceiveError), @@ -88,6 +93,7 @@ where } } + #[inline] pub fn try_recv(&self) -> ReceiveResult { match *self { GenericReceiver::Ipc(ref receiver) => receiver.try_recv().map_err(|_| ReceiveError), @@ -97,6 +103,7 @@ where } } + #[inline] pub fn into_inner(self) -> crossbeam_channel::Receiver where T: Send + 'static, @@ -110,6 +117,31 @@ where } } +impl Serialize for GenericReceiver +where + T: for<'de> Deserialize<'de> + Serialize, +{ + fn serialize(&self, s: S) -> Result { + match self { + GenericReceiver::Ipc(receiver) => receiver.serialize(s), + GenericReceiver::Crossbeam(_) => panic!("{GENERIC_CHANNEL_USAGE_ERROR_PANIC_MSG}"), + } + } +} + +impl<'a, T> Deserialize<'a> for GenericReceiver +where + T: for<'de> Deserialize<'de> + Serialize, +{ + fn deserialize(d: D) -> Result, D::Error> + where + D: Deserializer<'a>, + { + // Only ipc_channel will encounter deserialize scenario. + ipc_channel::ipc::IpcReceiver::::deserialize(d).map(GenericReceiver::Ipc) + } +} + /// Creates a Servo channel that can select different channel implementations based on multiprocess /// mode or not. If the scenario doesn't require message to pass process boundary, a simple /// crossbeam channel is preferred.