Skip to content

Commit

Permalink
Adding into_raw() and from_raw() methods
Browse files Browse the repository at this point in the history
See issue #28.
  • Loading branch information
bendk committed Sep 11, 2023
1 parent 43693cb commit 46db1ab
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 0 deletions.
49 changes: 49 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,31 @@ impl<T> Sender<T> {
_ => 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<T>),
_invariant: PhantomData,
}
}
}

impl<T> Drop for Sender<T> {
Expand Down Expand Up @@ -816,6 +841,30 @@ impl<T> Receiver<T> {
_ => 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<T>),
}
}
}

#[cfg(feature = "async")]
Expand Down
46 changes: 46 additions & 0 deletions tests/raw.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#![cfg(not(loom))]

use oneshot::{channel, Receiver, Sender};

#[test]
fn test_raw_sender() {
let (sender, receiver) = channel::<u32>();
let raw = sender.into_raw();
let recreated = unsafe { Sender::<u32>::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::<u32>();
let raw = receiver.into_raw();
sender.send(100).unwrap();
let recreated = unsafe { Receiver::<u32>::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::<u32>();
let raw_receiver = receiver.into_raw();
let raw_sender = sender.into_raw();

let recreated_sender = unsafe { Sender::<u32>::from_raw(raw_sender) };
recreated_sender.send(100).unwrap();

let recreated_receiver = unsafe { Receiver::<u32>::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
)
}

0 comments on commit 46db1ab

Please sign in to comment.