Skip to content

Commit

Permalink
counter: use NonNull
Browse files Browse the repository at this point in the history
counter::{Sender, Receiver} hold shared references to a channel,
similar to an Arc. Their raw pointers to the Counter are never null,
so change them from *mut Counter<C> to NonNull<Counter<C>>.
This makes it easier to verify the safety requirements for dereferences,
and allows the niche value optimization to apply.
  • Loading branch information
calebsander authored and taiki-e committed Jan 22, 2024
1 parent 3ce467f commit e316b3e
Showing 1 changed file with 9 additions and 8 deletions.
17 changes: 9 additions & 8 deletions crossbeam-channel/src/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use std::isize;
use std::ops;
use std::process;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

/// Reference counter internals.
Expand All @@ -22,26 +23,26 @@ struct Counter<C> {

/// Wraps a channel into the reference counter.
pub(crate) fn new<C>(chan: C) -> (Sender<C>, Receiver<C>) {
let counter = Box::into_raw(Box::new(Counter {
let counter = NonNull::from(Box::leak(Box::new(Counter {
senders: AtomicUsize::new(1),
receivers: AtomicUsize::new(1),
destroy: AtomicBool::new(false),
chan,
}));
})));
let s = Sender { counter };
let r = Receiver { counter };
(s, r)
}

/// The sending side.
pub(crate) struct Sender<C> {
counter: *mut Counter<C>,
counter: NonNull<Counter<C>>,
}

impl<C> Sender<C> {
/// Returns the internal `Counter`.
fn counter(&self) -> &Counter<C> {
unsafe { &*self.counter }
unsafe { self.counter.as_ref() }
}

/// Acquires another sender reference.
Expand All @@ -68,7 +69,7 @@ impl<C> Sender<C> {
disconnect(&self.counter().chan);

if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(unsafe { Box::from_raw(self.counter) });
drop(unsafe { Box::from_raw(self.counter.as_ptr()) });
}
}
}
Expand All @@ -90,13 +91,13 @@ impl<C> PartialEq for Sender<C> {

/// The receiving side.
pub(crate) struct Receiver<C> {
counter: *mut Counter<C>,
counter: NonNull<Counter<C>>,
}

impl<C> Receiver<C> {
/// Returns the internal `Counter`.
fn counter(&self) -> &Counter<C> {
unsafe { &*self.counter }
unsafe { self.counter.as_ref() }
}

/// Acquires another receiver reference.
Expand All @@ -123,7 +124,7 @@ impl<C> Receiver<C> {
disconnect(&self.counter().chan);

if self.counter().destroy.swap(true, Ordering::AcqRel) {
drop(unsafe { Box::from_raw(self.counter) });
drop(unsafe { Box::from_raw(self.counter.as_ptr()) });
}
}
}
Expand Down

0 comments on commit e316b3e

Please sign in to comment.