Skip to content

Commit

Permalink
Improve unsafe and atomic hygiene
Browse files Browse the repository at this point in the history
  • Loading branch information
Cassy343 committed May 23, 2022
1 parent 90f2276 commit e1d5fbd
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 76 deletions.
16 changes: 9 additions & 7 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,52 @@
use super::Box;
use core::fmt;
use core::mem;
use core::ptr::NonNull;

/// An error returned when trying to send on a closed channel. Returned from
/// [`Sender::send`] if the corresponding [`Receiver`] has already been dropped.
///
/// The message that could not be sent can be retreived again with [`SendError::into_inner`].
pub struct SendError<T> {
channel_ptr: *mut super::Channel<T>,
channel_ptr: NonNull<super::Channel<T>>,
}

unsafe impl<T: Send> Send for SendError<T> {}

impl<T> SendError<T> {
pub(crate) const fn new(channel_ptr: *mut super::Channel<T>) -> Self {
pub(crate) const fn new(channel_ptr: NonNull<super::Channel<T>>) -> Self {
Self { channel_ptr }
}

/// Consumes the error and returns the message that failed to be sent.
#[inline]
pub fn into_inner(self) -> T {
// SAFETY: The reference won't be used after it is freed in this method
let channel: &mut super::Channel<T> = unsafe { &mut *self.channel_ptr };
let channel: &super::Channel<T> = unsafe { self.channel_ptr.as_ref() };
let channel_ptr = self.channel_ptr;

// Don't run destructor if we consumed ourselves. Freeing happens here.
mem::forget(self);

let message = unsafe { channel.take_message() };
unsafe { Box::from_raw(channel) };
unsafe { Box::from_raw(channel_ptr.as_ptr()) };
message
}

/// Get a reference to the message that failed to be sent.
#[inline]
pub fn as_inner(&self) -> &T {
unsafe { &*(*self.channel_ptr).message.as_ptr() }
unsafe { (*self.channel_ptr.as_ref().message.get()).assume_init_ref() }
}
}

impl<T> Drop for SendError<T> {
fn drop(&mut self) {
// SAFETY: The reference won't be used after it is freed in this method
let channel: &mut super::Channel<T> = unsafe { &mut *self.channel_ptr };
let channel: &super::Channel<T> = unsafe { self.channel_ptr.as_ref() };

unsafe { channel.drop_message() };
unsafe { Box::from_raw(channel) };
unsafe { Box::from_raw(self.channel_ptr.as_ptr()) };
}
}

Expand Down
Loading

0 comments on commit e1d5fbd

Please sign in to comment.