Skip to content

Commit 545d471

Browse files
committed
std: Make std::comm return types consistent
There are currently a number of return values from the std::comm methods, not all of which are necessarily completely expressive: Sender::try_send(t: T) -> bool This method currently doesn't transmit back the data `t` if the send fails due to the other end having disconnected. Additionally, this shares the name of the synchronous try_send method, but it differs in semantics in that it only has one failure case, not two (the buffer can never be full). SyncSender::try_send(t: T) -> TrySendResult<T> This method accurately conveys all possible information, but it uses a custom type to the std::comm module with no convenience methods on it. Additionally, if you want to inspect the result you're forced to import something from `std::comm`. SyncSender::send_opt(t: T) -> Option<T> This method uses Some(T) as an "error value" and None as a "success value", but almost all other uses of Option<T> have Some/None the other way Receiver::try_recv(t: T) -> TryRecvResult<T> Similarly to the synchronous try_send, this custom return type is lacking in terms of usability (no convenience methods). With this number of drawbacks in mind, I believed it was time to re-work the return types of these methods. The new API for the comm module is: Sender::send(t: T) -> () Sender::send_opt(t: T) -> Result<(), T> SyncSender::send(t: T) -> () SyncSender::send_opt(t: T) -> Result<(), T> SyncSender::try_send(t: T) -> Result<(), TrySendError<T>> Receiver::recv() -> T Receiver::recv_opt() -> Result<T, ()> Receiver::try_recv() -> Result<T, TryRecvError> The notable changes made are: * Sender::try_send => Sender::send_opt. This renaming brings the semantics in line with the SyncSender::send_opt method. An asychronous send only has one failure case, unlike the synchronous try_send method which has two failure cases (full/disconnected). * Sender::send_opt returns the data back to the caller if the send is guaranteed to fail. This method previously returned `bool`, but then it was unable to retrieve the data if the data was guaranteed to fail to send. There is still a race such that when `Ok(())` is returned the data could still fail to be received, but that's inherent to an asynchronous channel. * Result is now the basis of all return values. This not only adds lots of convenience methods to all return values for free, but it also means that you can inspect the return values with no extra imports (Ok/Err are in the prelude). Additionally, it's now self documenting when something failed or not because the return value has "Err" in the name. Things I'm a little uneasy about: * The methods send_opt and recv_opt are not returning options, but rather results. I felt more strongly that Option was the wrong return type than the _opt prefix was wrong, and I coudn't think of a much better name for these methods. One possible way to think about them is to read the _opt suffix as "optionally". * Result<T, ()> is often better expressed as Option<T>. This is only applicable to the recv_opt() method, but I thought it would be more consistent for everything to return Result rather than one method returning an Option. Despite my two reasons to feel uneasy, I feel much better about the consistency in return values at this point, and I think the only real open question is if there's a better suffix for {send,recv}_opt. Closes #11527
1 parent 0156af1 commit 545d471

27 files changed

+232
-227
lines changed

src/libgreen/sched.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,6 @@ fn new_sched_rng() -> XorShiftRng {
10111011
mod test {
10121012
use rustuv;
10131013

1014-
use std::comm;
10151014
use std::task::TaskOpts;
10161015
use std::rt::task::Task;
10171016
use std::rt::local::Local;
@@ -1428,7 +1427,7 @@ mod test {
14281427
// This task should not be able to starve the sender;
14291428
// The sender should get stolen to another thread.
14301429
spawn(proc() {
1431-
while rx.try_recv() != comm::Data(()) { }
1430+
while rx.try_recv().is_err() { }
14321431
});
14331432

14341433
tx.send(());
@@ -1445,7 +1444,7 @@ mod test {
14451444
// This task should not be able to starve the other task.
14461445
// The sends should eventually yield.
14471446
spawn(proc() {
1448-
while rx1.try_recv() != comm::Data(()) {
1447+
while rx1.try_recv().is_err() {
14491448
tx2.send(());
14501449
}
14511450
});
@@ -1499,7 +1498,7 @@ mod test {
14991498
let mut val = 20;
15001499
while val > 0 {
15011500
val = po.recv();
1502-
ch.try_send(val - 1);
1501+
let _ = ch.send_opt(val - 1);
15031502
}
15041503
}
15051504

src/libgreen/task.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ mod tests {
515515
let _tx = tx;
516516
fail!()
517517
});
518-
assert_eq!(rx.recv_opt(), None);
518+
assert_eq!(rx.recv_opt(), Err(()));
519519
}
520520

521521
#[test]

src/libnative/io/timer_other.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
//!
4747
//! Note that all time units in this file are in *milliseconds*.
4848
49-
use std::comm::Data;
5049
use libc;
5150
use std::mem;
5251
use std::os;
@@ -119,7 +118,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
119118
Some(timer) => timer, None => return
120119
};
121120
let tx = timer.tx.take_unwrap();
122-
if tx.try_send(()) && timer.repeat {
121+
if tx.send_opt(()).is_ok() && timer.repeat {
123122
timer.tx = Some(tx);
124123
timer.target += timer.interval;
125124
insert(timer, active);
@@ -162,14 +161,14 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
162161
1 => {
163162
loop {
164163
match messages.try_recv() {
165-
Data(Shutdown) => {
164+
Ok(Shutdown) => {
166165
assert!(active.len() == 0);
167166
break 'outer;
168167
}
169168

170-
Data(NewTimer(timer)) => insert(timer, &mut active),
169+
Ok(NewTimer(timer)) => insert(timer, &mut active),
171170

172-
Data(RemoveTimer(id, ack)) => {
171+
Ok(RemoveTimer(id, ack)) => {
173172
match dead.iter().position(|&(i, _)| id == i) {
174173
Some(i) => {
175174
let (_, i) = dead.remove(i).unwrap();

src/libnative/io/timer_timerfd.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
//!
2929
//! As with timer_other, all units in this file are in units of millseconds.
3030
31-
use std::comm::Data;
3231
use libc;
3332
use std::ptr;
3433
use std::os;
@@ -107,7 +106,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
107106
match list.as_slice().bsearch(|&(f, _, _)| f.cmp(&fd)) {
108107
Some(i) => {
109108
let (_, ref c, oneshot) = *list.get(i);
110-
(!c.try_send(()) || oneshot, i)
109+
(c.send_opt(()).is_err() || oneshot, i)
111110
}
112111
None => fail!("fd not active: {}", fd),
113112
}
@@ -121,7 +120,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
121120

122121
while incoming {
123122
match messages.try_recv() {
124-
Data(NewTimer(fd, chan, one, timeval)) => {
123+
Ok(NewTimer(fd, chan, one, timeval)) => {
125124
// acknowledge we have the new channel, we will never send
126125
// another message to the old channel
127126
chan.send(());
@@ -149,7 +148,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
149148
assert_eq!(ret, 0);
150149
}
151150

152-
Data(RemoveTimer(fd, chan)) => {
151+
Ok(RemoveTimer(fd, chan)) => {
153152
match list.as_slice().bsearch(|&(f, _, _)| f.cmp(&fd)) {
154153
Some(i) => {
155154
drop(list.remove(i));
@@ -160,7 +159,7 @@ fn helper(input: libc::c_int, messages: Receiver<Req>) {
160159
chan.send(());
161160
}
162161

163-
Data(Shutdown) => {
162+
Ok(Shutdown) => {
164163
assert!(list.len() == 0);
165164
break 'outer;
166165
}

src/libnative/io/timer_win32.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
//! Other than that, the implementation is pretty straightforward in terms of
2121
//! the other two implementations of timers with nothing *that* new showing up.
2222
23-
use std::comm::Data;
2423
use libc;
2524
use std::ptr;
2625
use std::rt::rtio;
@@ -54,11 +53,11 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
5453
if idx == 0 {
5554
loop {
5655
match messages.try_recv() {
57-
Data(NewTimer(obj, c, one)) => {
56+
Ok(NewTimer(obj, c, one)) => {
5857
objs.push(obj);
5958
chans.push((c, one));
6059
}
61-
Data(RemoveTimer(obj, c)) => {
60+
Ok(RemoveTimer(obj, c)) => {
6261
c.send(());
6362
match objs.iter().position(|&o| o == obj) {
6463
Some(i) => {
@@ -68,7 +67,7 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
6867
None => {}
6968
}
7069
}
71-
Data(Shutdown) => {
70+
Ok(Shutdown) => {
7271
assert_eq!(objs.len(), 1);
7372
assert_eq!(chans.len(), 0);
7473
break 'outer;
@@ -79,7 +78,7 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>) {
7978
} else {
8079
let remove = {
8180
match chans.get(idx as uint - 1) {
82-
&(ref c, oneshot) => !c.try_send(()) || oneshot
81+
&(ref c, oneshot) => c.send_opt(()).is_err() || oneshot
8382
}
8483
};
8584
if remove {

src/libnative/task.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ mod tests {
274274
let _tx = tx;
275275
fail!()
276276
});
277-
assert_eq!(rx.recv_opt(), None);
277+
assert_eq!(rx.recv_opt(), Err(()));
278278
}
279279

280280
#[test]

src/librustuv/net.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ mod test {
10651065
}
10661066
reads += 1;
10671067

1068-
tx2.try_send(());
1068+
let _ = tx2.send_opt(());
10691069
}
10701070

10711071
// Make sure we had multiple reads

src/librustuv/signal.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl SignalWatcher {
5151
extern fn signal_cb(handle: *uvll::uv_signal_t, signum: c_int) {
5252
let s: &mut SignalWatcher = unsafe { UvHandle::from_uv_handle(&handle) };
5353
assert_eq!(signum as int, s.signal as int);
54-
s.channel.try_send(s.signal);
54+
let _ = s.channel.send_opt(s.signal);
5555
}
5656

5757
impl HomingIO for SignalWatcher {

src/librustuv/timer.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,9 @@ extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
140140
let task = timer.blocker.take_unwrap();
141141
let _ = task.wake().map(|t| t.reawaken());
142142
}
143-
SendOnce(chan) => { let _ = chan.try_send(()); }
143+
SendOnce(chan) => { let _ = chan.send_opt(()); }
144144
SendMany(chan, id) => {
145-
let _ = chan.try_send(());
145+
let _ = chan.send_opt(());
146146

147147
// Note that the above operation could have performed some form of
148148
// scheduling. This means that the timer may have decided to insert
@@ -196,8 +196,8 @@ mod test {
196196
let oport = timer.oneshot(1);
197197
let pport = timer.period(1);
198198
timer.sleep(1);
199-
assert_eq!(oport.recv_opt(), None);
200-
assert_eq!(pport.recv_opt(), None);
199+
assert_eq!(oport.recv_opt(), Err(()));
200+
assert_eq!(pport.recv_opt(), Err(()));
201201
timer.oneshot(1).recv();
202202
}
203203

@@ -284,7 +284,7 @@ mod test {
284284
let mut timer = TimerWatcher::new(local_loop());
285285
timer.oneshot(1000)
286286
};
287-
assert_eq!(port.recv_opt(), None);
287+
assert_eq!(port.recv_opt(), Err(()));
288288
}
289289

290290
#[test]
@@ -293,7 +293,7 @@ mod test {
293293
let mut timer = TimerWatcher::new(local_loop());
294294
timer.period(1000)
295295
};
296-
assert_eq!(port.recv_opt(), None);
296+
assert_eq!(port.recv_opt(), Err(()));
297297
}
298298

299299
#[test]

0 commit comments

Comments
 (0)