From ba821ce639f5a77dec2da7675d25724d08e153b7 Mon Sep 17 00:00:00 2001 From: Narfinger Date: Tue, 5 Aug 2025 11:16:12 +0200 Subject: [PATCH 1/2] Unify error handling to have IpcError and TryRecvError be the main error types. These types will give the Bincode error, Io errors (which are converted from platform errors) and Disconnect. Additionally we now use the thiserror crate which removes some of the code. Signed-off-by: Narfinger --- Cargo.toml | 1 + src/asynch.rs | 3 +- src/error.rs | 32 +++++++++++++++ src/ipc.rs | 73 ++++++---------------------------- src/lib.rs | 3 +- src/platform/inprocess/mod.rs | 44 +++++++-------------- src/platform/macos/mod.rs | 74 +++++++++++------------------------ src/platform/unix/mod.rs | 43 +++++++++----------- src/platform/windows/mod.rs | 38 ++++++++---------- src/router.rs | 3 +- src/test.rs | 15 ++++--- 11 files changed, 130 insertions(+), 199 deletions(-) create mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index f3b1cc98..fe4604ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ futures-channel = { version = "0.3.31", optional = true } futures-core = { version = "0.3.31", optional = true } libc = "0.2.162" serde = { version = "1.0", features = ["rc"] } +thiserror = "2.0.12" uuid = { version = "1", features = ["v4"] } [target.'cfg(any(target_os = "linux", target_os = "openbsd", target_os = "freebsd", target_os = "illumos"))'.dependencies] diff --git a/src/asynch.rs b/src/asynch.rs index fed5c60d..905bc878 100644 --- a/src/asynch.rs +++ b/src/asynch.rs @@ -10,6 +10,7 @@ use crate::ipc::{ self, IpcMessage, IpcReceiver, IpcReceiverSet, IpcSelectionResult, IpcSender, OpaqueIpcReceiver, }; +use crate::IpcError; use futures_channel::mpsc::UnboundedReceiver; use futures_channel::mpsc::UnboundedSender; use futures_core::stream::FusedStream; @@ -96,7 +97,7 @@ impl Stream for IpcStream where T: for<'de> Deserialize<'de> + Serialize, { - type Item = Result; + type Item = Result; fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll> { let recv = Pin::new(&mut self.0); diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..0a3292a1 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,32 @@ +use std::fmt::Display; +use std::io; + +use thiserror::Error; + +#[derive(Debug, Error)] +/// An error that occurs for serialization or deserialization +pub struct SerializationError(#[from] pub(crate) bincode::Error); + +impl Display for SerializationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Serialization error") + } +} + +#[derive(Debug, Error)] +pub enum IpcError { + #[error("Error in decoding or encoding: {0}")] + SerializationError(#[from] SerializationError), + #[error("Error in IO: {0}")] + Io(#[from] io::Error), + #[error("Ipc Disconnected")] + Disconnected, +} + +#[derive(Debug, Error)] +pub enum TryRecvError { + #[error("IPC error")] + IpcError(#[from] IpcError), + #[error("Channel empty")] + Empty, +} diff --git a/src/ipc.rs b/src/ipc.rs index c91a381a..ce39540c 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -7,16 +7,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use crate::error::SerializationError; use crate::platform::{self, OsIpcChannel, OsIpcReceiver, OsIpcReceiverSet, OsIpcSender}; use crate::platform::{ OsIpcOneShotServer, OsIpcSelectionResult, OsIpcSharedMemory, OsOpaqueIpcChannel, }; +use crate::{IpcError, TryRecvError}; use bincode; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use std::cell::RefCell; use std::cmp::min; -use std::error::Error as StdError; use std::fmt::{self, Debug, Formatter}; use std::io; use std::marker::PhantomData; @@ -37,57 +38,6 @@ thread_local! { const { RefCell::new(Vec::new()) } } -#[derive(Debug)] -pub enum IpcError { - Bincode(bincode::Error), - Io(io::Error), - Disconnected, -} - -impl fmt::Display for IpcError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - IpcError::Bincode(ref err) => write!(fmt, "bincode error: {err}"), - IpcError::Io(ref err) => write!(fmt, "io error: {err}"), - IpcError::Disconnected => write!(fmt, "disconnected"), - } - } -} - -impl StdError for IpcError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match *self { - IpcError::Bincode(ref err) => Some(err), - IpcError::Io(ref err) => Some(err), - IpcError::Disconnected => None, - } - } -} - -#[derive(Debug)] -pub enum TryRecvError { - IpcError(IpcError), - Empty, -} - -impl fmt::Display for TryRecvError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - TryRecvError::IpcError(ref err) => write!(fmt, "ipc error: {err}"), - TryRecvError::Empty => write!(fmt, "empty"), - } - } -} - -impl StdError for TryRecvError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match *self { - TryRecvError::IpcError(ref err) => Some(err), - TryRecvError::Empty => None, - } - } -} - /// Create a connected [IpcSender] and [IpcReceiver] that /// transfer messages of a given type provided by type `T` /// or inferred by the types of messages sent by the sender. @@ -248,7 +198,10 @@ where { /// Blocking receive. pub fn recv(&self) -> Result { - self.os_receiver.recv()?.to().map_err(IpcError::Bincode) + self.os_receiver + .recv()? + .to() + .map_err(IpcError::SerializationError) } /// Non-blocking receive @@ -256,7 +209,7 @@ where self.os_receiver .try_recv()? .to() - .map_err(IpcError::Bincode) + .map_err(IpcError::SerializationError) .map_err(TryRecvError::IpcError) } @@ -270,7 +223,7 @@ where self.os_receiver .try_recv_timeout(duration)? .to() - .map_err(IpcError::Bincode) + .map_err(IpcError::SerializationError) .map_err(TryRecvError::IpcError) } @@ -364,7 +317,7 @@ where } /// Send data across the channel to the receiver. - pub fn send(&self, data: T) -> Result<(), bincode::Error> { + pub fn send(&self, data: T) -> Result<(), IpcError> { let mut bytes = Vec::with_capacity(4096); OS_IPC_CHANNELS_FOR_SERIALIZATION.with(|os_ipc_channels_for_serialization| { OS_IPC_SHARED_MEMORY_REGIONS_FOR_SERIALIZATION.with( @@ -377,7 +330,7 @@ where let os_ipc_shared_memory_regions; let os_ipc_channels; { - bincode::serialize_into(&mut bytes, &data)?; + bincode::serialize_into(&mut bytes, &data).map_err(SerializationError)?; os_ipc_channels = mem::replace( &mut *os_ipc_channels_for_serialization.borrow_mut(), old_os_ipc_channels, @@ -726,7 +679,7 @@ impl IpcMessage { } /// Deserialize the raw data in the contained message into the inferred type. - pub fn to(mut self) -> Result + pub fn to(mut self) -> Result where T: for<'de> Deserialize<'de> + Serialize, { @@ -744,7 +697,7 @@ impl IpcMessage { .map(Some) .collect(), ); - let result = bincode::deserialize(&self.data[..]); + let result = bincode::deserialize(&self.data[..]).map_err(|e| e.into()); *os_ipc_shared_memory_regions_for_deserialization.borrow_mut() = old_ipc_shared_memory_regions_for_deserialization; mem::swap( @@ -886,7 +839,7 @@ where )) } - pub fn accept(self) -> Result<(IpcReceiver, T), bincode::Error> { + pub fn accept(self) -> Result<(IpcReceiver, T), IpcError> { let (os_receiver, ipc_message) = self.os_server.accept()?; Ok(( IpcReceiver { diff --git a/src/lib.rs b/src/lib.rs index 46cdf0bf..da52b326 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod asynch; #[cfg(all(not(feature = "force-inprocess"), target_os = "windows"))] extern crate windows; +mod error; pub mod ipc; pub mod platform; pub mod router; @@ -39,4 +40,4 @@ pub mod router; #[cfg(test)] mod test; -pub use bincode::{Error, ErrorKind}; +pub use error::{IpcError, TryRecvError}; diff --git a/src/platform/inprocess/mod.rs b/src/platform/inprocess/mod.rs index 2155c737..428ccbe8 100644 --- a/src/platform/inprocess/mod.rs +++ b/src/platform/inprocess/mod.rs @@ -7,13 +7,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::ipc::{self, IpcMessage}; -use bincode; +use crate::ipc::IpcMessage; use crossbeam_channel::{self, Receiver, RecvTimeoutError, Select, Sender, TryRecvError}; use std::cell::{Ref, RefCell}; use std::cmp::PartialEq; use std::collections::hash_map::HashMap; -use std::error::Error as StdError; use std::fmt::{self, Debug, Formatter}; use std::io; use std::ops::{Deref, RangeFrom}; @@ -21,6 +19,7 @@ use std::slice; use std::sync::{Arc, LazyLock, Mutex}; use std::time::Duration; use std::usize; +use thiserror::Error; use uuid::Uuid; #[derive(Clone)] @@ -387,11 +386,15 @@ impl OsIpcSharedMemory { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Error)] pub enum ChannelError { + #[error("Channel Closed")] ChannelClosedError, + #[error("Broken Pipe")] BrokenPipeError, + #[error("Channel Empty")] ChannelEmpty, + #[error("Unknown Error")] UnknownError, } @@ -402,42 +405,23 @@ impl ChannelError { } } -impl fmt::Display for ChannelError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - ChannelError::ChannelClosedError => write!(fmt, "channel closed"), - ChannelError::BrokenPipeError => write!(fmt, "broken pipe"), - ChannelError::ChannelEmpty => write!(fmt, "channel empty"), - ChannelError::UnknownError => write!(fmt, "unknown error"), - } - } -} - -impl StdError for ChannelError {} - -impl From for bincode::Error { - fn from(crossbeam_error: ChannelError) -> Self { - io::Error::from(crossbeam_error).into() - } -} - -impl From for ipc::IpcError { +impl From for crate::IpcError { fn from(error: ChannelError) -> Self { match error { - ChannelError::ChannelClosedError => ipc::IpcError::Disconnected, - e => ipc::IpcError::Bincode(io::Error::from(e).into()), + ChannelError::ChannelClosedError => crate::IpcError::Disconnected, + e => crate::IpcError::Io(io::Error::from(e).into()), } } } -impl From for ipc::TryRecvError { +impl From for crate::TryRecvError { fn from(error: ChannelError) -> Self { match error { ChannelError::ChannelClosedError => { - ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected) + crate::TryRecvError::IpcError(crate::IpcError::Disconnected) }, - ChannelError::ChannelEmpty => ipc::TryRecvError::Empty, - e => ipc::TryRecvError::IpcError(ipc::IpcError::Bincode(io::Error::from(e).into())), + ChannelError::ChannelEmpty => crate::TryRecvError::Empty, + e => crate::TryRecvError::IpcError(crate::IpcError::Io(io::Error::from(e).into())), } } } diff --git a/src/platform/macos/mod.rs b/src/platform/macos/mod.rs index a0935e8a..2716cd71 100644 --- a/src/platform/macos/mod.rs +++ b/src/platform/macos/mod.rs @@ -12,14 +12,12 @@ use self::mach_sys::{kern_return_t, mach_msg_body_t, mach_msg_header_t, mach_msg use self::mach_sys::{mach_msg_ool_descriptor_t, mach_msg_port_descriptor_t, mach_msg_type_name_t}; use self::mach_sys::{mach_msg_timeout_t, mach_port_limits_t, mach_port_msgcount_t}; use self::mach_sys::{mach_port_right_t, mach_port_t, mach_task_self_, vm_inherit_t}; -use crate::ipc::{self, IpcMessage}; +use crate::ipc::IpcMessage; -use bincode; use libc::{self, c_char, c_uint, c_void, size_t}; use rand::{self, Rng}; use std::cell::Cell; use std::convert::TryInto; -use std::error::Error as StdError; use std::ffi::CString; use std::fmt::{self, Debug, Formatter}; use std::io; @@ -30,6 +28,7 @@ use std::ptr; use std::slice; use std::sync::RwLock; use std::time::Duration; +use thiserror::Error; mod mach_sys; @@ -997,43 +996,28 @@ impl Message { } } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, Error, PartialEq)] pub enum KernelError { + #[error("Success")] Success, + #[error("No room in IPC name space for another right.")] NoSpace, + #[error("Name doesn't denote a right in the task")] InvalidName, + #[error("Name denotes a right, but not an appropiate right.")] InvalidRight, + #[error("Blatant range error")] InvalidValue, + #[error("The supplied (port) capability is improper")] InvalidCapability, + #[error("Operation would overflow limit on user-references")] UrefsOverflow, + #[error("Receive right is not a member of a port set.")] NotInSet, + #[error("Unkown kernel error. {0}")] Unknown(kern_return_t), } -impl fmt::Display for KernelError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match *self { - KernelError::Success => write!(fmt, "Success."), - KernelError::NoSpace => write!(fmt, "No room in IPC name space for another right."), - KernelError::InvalidName => write!(fmt, "Name doesn't denote a right in the task."), - KernelError::InvalidRight => { - write!(fmt, "Name denotes a right, but not an appropriate right.") - }, - KernelError::InvalidValue => write!(fmt, "Blatant range error."), - KernelError::InvalidCapability => { - write!(fmt, "The supplied (port) capability is improper.") - }, - KernelError::UrefsOverflow => { - write!(fmt, "Operation would overflow limit on user-references.") - }, - KernelError::NotInSet => write!(fmt, "Receive right is not a member of a port set."), - KernelError::Unknown(code) => write!(fmt, "Unknown kernel error: {:x}", code), - } - } -} - -impl StdError for KernelError {} - impl From for KernelError { fn from(code: kern_return_t) -> KernelError { match code { @@ -1050,10 +1034,10 @@ impl From for KernelError { } } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, Error, PartialEq)] pub enum MachError { Success, - Kernel(KernelError), + Kernel(#[from] KernelError), IpcSpace, VmSpace, IpcKernel, @@ -1185,14 +1169,6 @@ impl fmt::Display for MachError { } } -impl StdError for MachError {} - -impl From for bincode::Error { - fn from(mach_error: MachError) -> Self { - io::Error::from(mach_error).into() - } -} - impl From for MachError { fn from(code: mach_msg_return_t) -> MachError { match code { @@ -1240,27 +1216,23 @@ impl From for MachError { } } -impl From for MachError { - fn from(kernel_error: KernelError) -> MachError { - MachError::Kernel(kernel_error) - } -} - -impl From for ipc::TryRecvError { +impl From for crate::TryRecvError { fn from(error: MachError) -> Self { match error { - MachError::NotifyNoSenders => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected), - MachError::RcvTimedOut => ipc::TryRecvError::Empty, - e => ipc::TryRecvError::IpcError(ipc::IpcError::Io(io::Error::from(e))), + MachError::NotifyNoSenders => { + crate::TryRecvError::IpcError(crate::IpcError::Disconnected) + }, + MachError::RcvTimedOut => crate::TryRecvError::Empty, + e => crate::TryRecvError::IpcError(crate::IpcError::Io(io::Error::from(e))), } } } -impl From for ipc::IpcError { +impl From for crate::IpcError { fn from(error: MachError) -> Self { match error { - MachError::NotifyNoSenders => ipc::IpcError::Disconnected, - e => ipc::IpcError::Io(io::Error::from(e)), + MachError::NotifyNoSenders => crate::IpcError::Disconnected, + e => crate::IpcError::Io(io::Error::from(e)), } } } diff --git a/src/platform/unix/mod.rs b/src/platform/unix/mod.rs index c7821366..76d04470 100644 --- a/src/platform/unix/mod.rs +++ b/src/platform/unix/mod.rs @@ -7,8 +7,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::ipc::{self, IpcMessage}; -use bincode; +use crate::ipc::IpcMessage; use fnv::FnvHasher; use libc::{ self, cmsghdr, linger, CMSG_DATA, CMSG_LEN, CMSG_SPACE, MAP_FAILED, MAP_SHARED, PROT_READ, @@ -24,7 +23,6 @@ use std::cell::Cell; use std::cmp; use std::collections::HashMap; use std::convert::TryInto; -use std::error::Error as StdError; use std::ffi::{c_uint, CString}; use std::fmt::{self, Debug, Formatter}; use std::hash::BuildHasherDefault; @@ -40,6 +38,7 @@ use std::sync::{Arc, LazyLock}; use std::thread; use std::time::{Duration, UNIX_EPOCH}; use tempfile::{Builder, TempDir}; +use thiserror::Error; const MAX_FDS_IN_CMSG: u32 = 64; @@ -906,7 +905,7 @@ impl OsIpcSharedMemory { } } -#[derive(Debug)] +#[derive(Debug, Error)] pub enum UnixError { Errno(c_int), ChannelClosed, @@ -924,6 +923,15 @@ impl UnixError { } } +impl From for crate::IpcError { + fn from(error: UnixError) -> Self { + match error { + UnixError::ChannelClosed => crate::IpcError::Disconnected, + e => crate::IpcError::Io(io::Error::from(e)), + } + } +} + impl fmt::Display for UnixError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { @@ -936,14 +944,6 @@ impl fmt::Display for UnixError { } } -impl StdError for UnixError {} - -impl From for bincode::Error { - fn from(unix_error: UnixError) -> Self { - io::Error::from(unix_error).into() - } -} - impl From for io::Error { fn from(unix_error: UnixError) -> io::Error { match unix_error { @@ -954,23 +954,16 @@ impl From for io::Error { } } -impl From for ipc::IpcError { - fn from(error: UnixError) -> Self { - match error { - UnixError::ChannelClosed => ipc::IpcError::Disconnected, - e => ipc::IpcError::Io(io::Error::from(e)), - } - } -} - -impl From for ipc::TryRecvError { +impl From for crate::TryRecvError { fn from(error: UnixError) -> Self { match error { - UnixError::ChannelClosed => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected), + UnixError::ChannelClosed => { + crate::TryRecvError::IpcError(crate::IpcError::Disconnected) + }, UnixError::Errno(code) if code == EAGAIN || code == EWOULDBLOCK => { - ipc::TryRecvError::Empty + crate::TryRecvError::Empty }, - e => ipc::TryRecvError::IpcError(ipc::IpcError::Io(io::Error::from(e))), + e => crate::TryRecvError::IpcError(crate::IpcError::Io(io::Error::from(e))), } } } diff --git a/src/platform/windows/mod.rs b/src/platform/windows/mod.rs index 2bbbff0b..1dc5d544 100644 --- a/src/platform/windows/mod.rs +++ b/src/platform/windows/mod.rs @@ -7,9 +7,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::ipc::{self, IpcMessage}; +use crate::ipc::IpcMessage; use bincode; use serde; +use thiserror::Error; use std::{ cell::{Cell, RefCell}, @@ -1954,10 +1955,13 @@ impl OsOpaqueIpcChannel { } } -#[derive(Debug)] +#[derive(Debug, Error)] pub enum WinIpcError { - WinError(WinError), + #[error("Windows Error {0}")] + WinError(#[from] WinError), + #[error("Channel Closed")] ChannelClosed, + #[error("No Data")] NoData, } @@ -1967,33 +1971,23 @@ impl WinIpcError { } } -impl From for bincode::Error { - fn from(error: WinIpcError) -> bincode::Error { - io::Error::from(error).into() - } -} - -impl From for WinIpcError { - fn from(e: WinError) -> Self { - Self::WinError(e) - } -} - -impl From for ipc::IpcError { +impl From for crate::IpcError { fn from(error: WinIpcError) -> Self { match error { - WinIpcError::ChannelClosed => ipc::IpcError::Disconnected, - e => ipc::IpcError::Io(io::Error::from(e)), + WinIpcError::ChannelClosed => crate::IpcError::Disconnected, + e => crate::IpcError::Io(io::Error::from(e)), } } } -impl From for ipc::TryRecvError { +impl From for crate::TryRecvError { fn from(error: WinIpcError) -> Self { match error { - WinIpcError::ChannelClosed => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected), - WinIpcError::NoData => ipc::TryRecvError::Empty, - e => ipc::TryRecvError::IpcError(ipc::IpcError::Io(io::Error::from(e))), + WinIpcError::ChannelClosed => { + crate::TryRecvError::IpcError(crate::IpcError::Disconnected) + }, + WinIpcError::NoData => crate::TryRecvError::Empty, + e => crate::TryRecvError::IpcError(crate::IpcError::Io(io::Error::from(e))), } } } diff --git a/src/router.rs b/src/router.rs index 45e7f9d9..36d3246b 100644 --- a/src/router.rs +++ b/src/router.rs @@ -17,6 +17,7 @@ use std::collections::HashMap; use std::sync::{LazyLock, Mutex}; use std::thread; +use crate::error::SerializationError; use crate::ipc::OpaqueIpcReceiver; use crate::ipc::{self, IpcMessage, IpcReceiver, IpcReceiverSet, IpcSelectionResult, IpcSender}; use crossbeam_channel::{self, Receiver, Sender}; @@ -240,4 +241,4 @@ enum RouterMsg { pub type RouterHandler = Box; /// Like [RouterHandler] but includes the type that will be passed to the callback -pub type TypedRouterHandler = Box) + Send>; +pub type TypedRouterHandler = Box) + Send>; diff --git a/src/test.rs b/src/test.rs index 4f4f3e0a..6188838d 100644 --- a/src/test.rs +++ b/src/test.rs @@ -16,7 +16,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::cell::RefCell; #[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios")))] use std::env; -use std::iter; #[cfg(not(any(feature = "force-inprocess", target_os = "android", target_os = "ios",)))] use std::process::{self, Command, Stdio}; #[cfg(not(any( @@ -130,7 +129,7 @@ fn simple() { assert_eq!(person, received_person); drop(tx); match rx.recv().unwrap_err() { - ipc::IpcError::Disconnected => (), + crate::IpcError::Disconnected => (), e => panic!("expected disconnected error, got {e:?}"), } } @@ -549,19 +548,19 @@ fn try_recv() { let person = ("Patrick Walton".to_owned(), 29); let (tx, rx) = ipc::channel().unwrap(); match rx.try_recv() { - Err(ipc::TryRecvError::Empty) => (), + Err(crate::TryRecvError::Empty) => (), v => panic!("Expected empty channel err: {v:?}"), } tx.send(person.clone()).unwrap(); let received_person = rx.try_recv().unwrap(); assert_eq!(person, received_person); match rx.try_recv() { - Err(ipc::TryRecvError::Empty) => (), + Err(crate::TryRecvError::Empty) => (), v => panic!("Expected empty channel err: {v:?}"), } drop(tx); match rx.try_recv() { - Err(ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected)) => (), + Err(crate::TryRecvError::IpcError(crate::IpcError::Disconnected)) => (), v => panic!("Expected disconnected err: {v:?}"), } } @@ -573,7 +572,7 @@ fn try_recv_timeout() { let timeout = Duration::from_millis(1000); let start_recv = Instant::now(); match rx.try_recv_timeout(timeout) { - Err(ipc::TryRecvError::Empty) => { + Err(crate::TryRecvError::Empty) => { assert!(start_recv.elapsed() >= Duration::from_millis(500)) }, v => panic!("Expected empty channel err: {v:?}"), @@ -585,14 +584,14 @@ fn try_recv_timeout() { assert_eq!(person, received_person); let start_recv = Instant::now(); match rx.try_recv_timeout(timeout) { - Err(ipc::TryRecvError::Empty) => { + Err(crate::TryRecvError::Empty) => { assert!(start_recv.elapsed() >= Duration::from_millis(500)) }, v => panic!("Expected empty channel err: {v:?}"), } drop(tx); match rx.try_recv_timeout(timeout) { - Err(ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected)) => (), + Err(crate::TryRecvError::IpcError(crate::IpcError::Disconnected)) => (), v => panic!("Expected disconnected err: {v:?}"), } } From 457ebf517883f16cf116dfcd0edede1ed8063171 Mon Sep 17 00:00:00 2001 From: Narfinger Date: Thu, 7 Aug 2025 13:18:16 +0200 Subject: [PATCH 2/2] Switch to bitcode. Bitcode has a better performance characteristics at the moment. Signed-off-by: Narfinger --- Cargo.toml | 4 ++-- src/error.rs | 2 +- src/ipc.rs | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fe4604ea..cd24a396 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ipc-channel" -version = "0.20.1" +version = "0.21.0" description = "A multiprocess drop-in replacement for Rust channels" authors = ["The Servo Project Developers"] license = "MIT OR Apache-2.0" @@ -31,7 +31,7 @@ win32-trace = [] enable-slow-tests = [] [dependencies] -bincode = "1" +bitcode = { version = "0.6.6", features = ["serde"] } crossbeam-channel = "0.5" fnv = "1.0.3" futures-channel = { version = "0.3.31", optional = true } diff --git a/src/error.rs b/src/error.rs index 0a3292a1..7987ec98 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,7 +5,7 @@ use thiserror::Error; #[derive(Debug, Error)] /// An error that occurs for serialization or deserialization -pub struct SerializationError(#[from] pub(crate) bincode::Error); +pub struct SerializationError(#[from] pub(crate) bitcode::Error); impl Display for SerializationError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/src/ipc.rs b/src/ipc.rs index ce39540c..15e2ae9b 100644 --- a/src/ipc.rs +++ b/src/ipc.rs @@ -14,7 +14,7 @@ use crate::platform::{ }; use crate::{IpcError, TryRecvError}; -use bincode; +use bitcode; use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; use std::cell::RefCell; use std::cmp::min; @@ -330,7 +330,8 @@ where let os_ipc_shared_memory_regions; let os_ipc_channels; { - bincode::serialize_into(&mut bytes, &data).map_err(SerializationError)?; + bytes = bitcode::serialize(&data).map_err(SerializationError)?; + os_ipc_channels = mem::replace( &mut *os_ipc_channels_for_serialization.borrow_mut(), old_os_ipc_channels, @@ -697,7 +698,7 @@ impl IpcMessage { .map(Some) .collect(), ); - let result = bincode::deserialize(&self.data[..]).map_err(|e| e.into()); + let result = bitcode::deserialize(&self.data[..]).map_err(|e| e.into()); *os_ipc_shared_memory_regions_for_deserialization.borrow_mut() = old_ipc_shared_memory_regions_for_deserialization; mem::swap(