From 8c4d1da7f7df439459492eed3222634e7cc19e2e Mon Sep 17 00:00:00 2001 From: Ben Dean-Kawamura Date: Tue, 29 Aug 2023 11:11:18 -0400 Subject: [PATCH] Adding into_raw() and from_raw() methods See issue #28. --- src/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/raw.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 tests/raw.rs diff --git a/src/lib.rs b/src/lib.rs index 7828e9f..14ea354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -314,6 +314,31 @@ impl Sender { _ => unreachable!(), } } + + /// Consumes the Sender, returning a raw pointer to the channel on the heap. + /// + /// This is intended to simplify using oneshot channels with some FFI code. The only safe thing + /// to do with the returned pointer is to later reconstruct the Sender with [Sender::from_raw]. + /// Memory will leak if the Sender is never reconstructed. + pub fn into_raw(self) -> *mut () { + let raw = self.channel_ptr.as_ptr() as *mut (); + mem::forget(self); + raw + } + + /// Consumes a raw pointer from [Sender::into_raw], recreating the Sender. + /// + /// # Safety + /// + /// This pointer must have come from [Sender::into_raw]. At most one Sender must exist for a + /// channel at any point in time. Constructing multiple Senders from the same raw pointer leads + /// to undefined behavior. + pub unsafe fn from_raw(raw: *mut ()) -> Self { + Self { + channel_ptr: NonNull::new_unchecked(raw as *mut Channel), + _invariant: PhantomData, + } + } } impl Drop for Sender { @@ -816,6 +841,30 @@ impl Receiver { _ => unreachable!(), } } + + /// Consumes the Receiver, returning a raw pointer to the channel on the heap. + /// + /// This is intended to simplify using oneshot channels with some FFI code. The only safe thing + /// to do with the returned pointer is to later reconstruct the Receiver with + /// [Receiver::from_raw]. Memory will leak if the Receiver is never reconstructed. + pub fn into_raw(self) -> *mut () { + let raw = self.channel_ptr.as_ptr() as *mut (); + mem::forget(self); + raw + } + + /// Consumes a raw pointer from [Receiver::into_raw], recreating the Receiver. + /// + /// # Safety + /// + /// This pointer must have come from [Receiver::into_raw]. At most one Receiver must exist for + /// a channel at any point in time. Constructing multiple Receiver from the same raw pointer + /// leads to undefined behavior. + pub unsafe fn from_raw(raw: *mut ()) -> Self { + Self { + channel_ptr: NonNull::new_unchecked(raw as *mut Channel), + } + } } #[cfg(feature = "async")] diff --git a/tests/raw.rs b/tests/raw.rs new file mode 100644 index 0000000..e38dc45 --- /dev/null +++ b/tests/raw.rs @@ -0,0 +1,46 @@ +#![cfg(not(loom))] + +use oneshot::{channel, Receiver, Sender}; + +#[test] +fn test_raw_sender() { + let (sender, receiver) = channel::(); + let raw = sender.into_raw(); + let recreated = unsafe { Sender::::from_raw(raw) }; + recreated + .send(100) + .unwrap_or_else(|e| panic!("error sending after into_raw/from_raw roundtrip: {e}")); + assert_eq!(receiver.try_recv(), Ok(100)) +} + +#[test] +fn test_raw_receiver() { + let (sender, receiver) = channel::(); + let raw = receiver.into_raw(); + sender.send(100).unwrap(); + let recreated = unsafe { Receiver::::from_raw(raw) }; + assert_eq!( + recreated + .try_recv() + .unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")), + 100 + ) +} + +#[test] +fn test_raw_sender_and_receiver() { + let (sender, receiver) = channel::(); + let raw_receiver = receiver.into_raw(); + let raw_sender = sender.into_raw(); + + let recreated_sender = unsafe { Sender::::from_raw(raw_sender) }; + recreated_sender.send(100).unwrap(); + + let recreated_receiver = unsafe { Receiver::::from_raw(raw_receiver) }; + assert_eq!( + recreated_receiver + .try_recv() + .unwrap_or_else(|e| panic!("error receiving after into_raw/from_raw roundtrip: {e}")), + 100 + ) +}