Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/echo-server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn srv(c: Chan<(), Rec<Srv>>) {
type Cli = <Srv as HasDual>::Dual;
fn cli(c: Chan<(), Rec<Cli>>) {

let mut stdin = std::io::stdin();
let stdin = std::io::stdin();
let mut count = 0usize;

let mut c = c.enter();
Expand Down
77 changes: 60 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,37 @@ pub enum Branch<L, R> {
Right(R)
}

impl <E, P> Drop for Chan<E, P> {
fn drop(&mut self) {
panic!("Session channel prematurely dropped");
}
}

impl<E> Chan<E, Eps> {
/// Close a channel. Should always be used at the end of your program.
pub fn close(self) {
// Consume `c`
pub fn close(mut self) {
// This method cleans up the channel without running the panicky destructor
// In essence, it calls the drop glue bypassing the `Drop::drop` method
use std::mem;

// Create some dummy values to place the real things inside
// This is safe because nobody will read these
// mem::swap uses a similar technique (also paired with `forget()`)
let mut sender = unsafe { mem::uninitialized() };
let mut receiver = unsafe { mem::uninitialized() };

// Extract the internal sender/receiver so that we can drop them
// We cannot drop directly since moving out of a type
// that implements `Drop` is disallowed
mem::swap(&mut self.0, &mut sender);
mem::swap(&mut self.1, &mut receiver);

drop(sender);drop(receiver); // drop them

// Ensure Chan destructors don't run so that we don't panic
// This also ensures that the uninitialized values don't get
// read at any point
mem::forget(self);
}
}

Expand Down Expand Up @@ -561,18 +588,16 @@ macro_rules! offer {
/// spawn(move|| send_str(tcs));
/// spawn(move|| send_usize(tcu));
///
/// loop {
/// chan_select! {
/// (c, s) = rcs.recv() => {
/// assert_eq!("Hello, World!".to_string(), s);
/// c.close();
/// break
/// },
/// (c, i) = rcu.recv() => {
/// assert_eq!(42, i);
/// c.close();
/// break
/// }
/// chan_select! {
/// (c, s) = rcs.recv() => {
/// assert_eq!("Hello, World!".to_string(), s);
/// c.close();
/// rcu.recv().0.close();
/// },
/// (c, i) = rcu.recv() => {
/// assert_eq!(42, i);
/// c.close();
/// rcs.recv().0.close();
/// }
/// }
/// }
Expand All @@ -598,17 +623,33 @@ macro_rules! offer {
/// let (c, s) = chan_one.recv();
/// assert_eq!("Hello, World!".to_string(), s);
/// c.close();
/// match chan_two.offer() {
/// Left(c) => c.recv().0.close(),
/// Right(c) => c.recv().0.close(),
/// }
/// },
/// Number => {
/// unreachable!()
/// chan_one.recv().0.close();
/// match chan_two.offer() {
/// Left(c) => c.recv().0.close(),
/// Right(c) => c.recv().0.close(),
/// }
/// }
/// },
/// _ign = chan_two.offer() => {
/// String => {
/// unreachable!()
/// chan_two.recv().0.close();
/// match chan_one.offer() {
/// Left(c) => c.recv().0.close(),
/// Right(c) => c.recv().0.close(),
/// }
/// },
/// Number => {
/// unreachable!()
/// chan_two.recv().0.close();
/// match chan_one.offer() {
/// Left(c) => c.recv().0.close(),
/// Right(c) => c.recv().0.close(),
/// }
/// }
/// }
/// }
Expand All @@ -622,6 +663,8 @@ macro_rules! offer {
/// let (ca1, ca2) = session_channel();
/// let (cb1, cb2) = session_channel();
///
/// cb2.sel2().send(42).close();
///
/// spawn(move|| cli(ca2));
///
/// srv(ca1, cb1);
Expand Down