Better type inference for chans and ports.
This commit is contained in:
parent
f023f82090
commit
3ab21e5ee0
6 changed files with 65 additions and 59 deletions
|
@ -6,7 +6,7 @@ import task::task_id;
|
||||||
|
|
||||||
export _chan;
|
export _chan;
|
||||||
export _port;
|
export _port;
|
||||||
|
export chan_handle;
|
||||||
export mk_port;
|
export mk_port;
|
||||||
export send;
|
export send;
|
||||||
export recv;
|
export recv;
|
||||||
|
@ -32,10 +32,9 @@ native "rust-intrinsic" mod rusti {
|
||||||
|
|
||||||
type port_id = int;
|
type port_id = int;
|
||||||
|
|
||||||
type chan<~T> = {
|
type chan_handle<~T> = { task : task_id, port : port_id};
|
||||||
task : task_id,
|
|
||||||
port : port_id
|
tag chan<~T> { chan_t(chan_handle<T>); }
|
||||||
};
|
|
||||||
type _chan<~T> = chan<T>;
|
type _chan<~T> = chan<T>;
|
||||||
|
|
||||||
resource port_ptr(po: *rustrt::rust_port) {
|
resource port_ptr(po: *rustrt::rust_port) {
|
||||||
|
@ -43,11 +42,11 @@ resource port_ptr(po: *rustrt::rust_port) {
|
||||||
rustrt::del_port(po);
|
rustrt::del_port(po);
|
||||||
}
|
}
|
||||||
|
|
||||||
type port<~T> = @port_ptr;
|
tag port<~T> { port_t(@port_ptr); }
|
||||||
|
|
||||||
obj port_obj<~T>(raw_port : port<T>) {
|
obj port_obj<~T>(raw_port : port<T>) {
|
||||||
fn mk_chan() -> _chan<T> {
|
fn mk_chan() -> chan<T> {
|
||||||
chan::<T>(raw_port)
|
chan(raw_port)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv() -> T {
|
fn recv() -> T {
|
||||||
|
@ -60,21 +59,21 @@ fn mk_port<~T>() -> _port<T> {
|
||||||
ret port_obj::<T>(port::<T>());
|
ret port_obj::<T>(port::<T>());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<~T>(ch : chan<T>, data : -T) {
|
fn send<~T>(ch : &chan<T>, data : -T) {
|
||||||
rustrt::chan_id_send(ch.task, ch.port, data);
|
rustrt::chan_id_send(ch.task, ch.port, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn port<~T>() -> port<T> {
|
fn port<~T>() -> port<T> {
|
||||||
@port_ptr(rustrt::new_port(sys::size_of::<T>()))
|
port_t(@port_ptr(rustrt::new_port(sys::size_of::<T>())))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recv<~T>(p : port<T>) -> T {
|
fn recv<~T>(p : &port<T>) -> T {
|
||||||
ret rusti::recv(**p)
|
ret rusti::recv(***p)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chan<~T>(p : port<T>) -> chan<T> {
|
fn chan<~T>(p : &port<T>) -> chan<T> {
|
||||||
{
|
chan_t({
|
||||||
task: task::get_task_id(),
|
task: task::get_task_id(),
|
||||||
port: rustrt::get_port_id(**p)
|
port: rustrt::get_port_id(***p)
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import cast = unsafe::reinterpret_cast;
|
import cast = unsafe::reinterpret_cast;
|
||||||
import comm;
|
import comm;
|
||||||
import comm::_chan;
|
|
||||||
import option::some;
|
import option::some;
|
||||||
import option::none;
|
import option::none;
|
||||||
import option = option::t;
|
import option = option::t;
|
||||||
|
@ -33,7 +32,7 @@ native "rust" mod rustrt {
|
||||||
type rust_task = {
|
type rust_task = {
|
||||||
id : task,
|
id : task,
|
||||||
mutable notify_enabled : u8,
|
mutable notify_enabled : u8,
|
||||||
mutable notify_chan : _chan<task_notification>,
|
mutable notify_chan : comm::chan_handle<task_notification>,
|
||||||
ctx : task_context,
|
ctx : task_context,
|
||||||
stack_ptr : *u8
|
stack_ptr : *u8
|
||||||
};
|
};
|
||||||
|
@ -76,15 +75,13 @@ tag task_notification {
|
||||||
fn join(task_port : (task_id, comm::port<task_notification>))
|
fn join(task_port : (task_id, comm::port<task_notification>))
|
||||||
-> task_result {
|
-> task_result {
|
||||||
let (id, port) = task_port;
|
let (id, port) = task_port;
|
||||||
while true {
|
|
||||||
alt comm::recv::<task_notification>(port) {
|
alt comm::recv::<task_notification>(port) {
|
||||||
exit(_id, res) {
|
exit(_id, res) {
|
||||||
if _id == id { ret res }
|
if _id == id { ret res }
|
||||||
|
else { fail #fmt("join received id %d, expected %d", _id, id) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fail
|
|
||||||
}
|
|
||||||
|
|
||||||
fn join_id(t : task_id) -> task_result {
|
fn join_id(t : task_id) -> task_result {
|
||||||
alt rustrt::task_join(t) { 0 { tr_success } _ { tr_failure } }
|
alt rustrt::task_join(t) { 0 { tr_success } _ { tr_failure } }
|
||||||
|
@ -108,7 +105,7 @@ fn spawn(thunk : -fn() -> ()) -> task {
|
||||||
spawn_inner(thunk, none)
|
spawn_inner(thunk, none)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_notify(thunk : -fn() -> (), notify : _chan<task_notification>)
|
fn spawn_notify(thunk : -fn() -> (), notify : comm::chan<task_notification>)
|
||||||
-> task {
|
-> task {
|
||||||
spawn_inner(thunk, some(notify))
|
spawn_inner(thunk, some(notify))
|
||||||
}
|
}
|
||||||
|
@ -121,7 +118,7 @@ fn spawn_joinable(thunk : -fn()) -> (task_id, comm::port<task_notification>) {
|
||||||
|
|
||||||
// FIXME: make this a fn~ once those are supported.
|
// FIXME: make this a fn~ once those are supported.
|
||||||
fn spawn_inner(thunk : -fn() -> (),
|
fn spawn_inner(thunk : -fn() -> (),
|
||||||
notify : option<_chan<task_notification>>)
|
notify : option<comm::chan<task_notification>>)
|
||||||
-> task_id {
|
-> task_id {
|
||||||
let id = rustrt::new_task();
|
let id = rustrt::new_task();
|
||||||
|
|
||||||
|
@ -144,7 +141,7 @@ fn spawn_inner(thunk : -fn() -> (),
|
||||||
alt notify {
|
alt notify {
|
||||||
some(c) {
|
some(c) {
|
||||||
(**task_ptr).notify_enabled = 1u8;
|
(**task_ptr).notify_enabled = 1u8;
|
||||||
(**task_ptr).notify_chan = c;
|
(**task_ptr).notify_chan = *c;
|
||||||
}
|
}
|
||||||
none {}
|
none {}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,10 +14,10 @@ import std::os;
|
||||||
import std::run;
|
import std::run;
|
||||||
import std::io;
|
import std::io;
|
||||||
import std::str;
|
import std::str;
|
||||||
import std::comm::_chan;
|
import std::comm::chan;
|
||||||
import std::comm::mk_port;
|
import std::comm::port;
|
||||||
import std::comm::_port;
|
|
||||||
import std::comm::send;
|
import std::comm::send;
|
||||||
|
import std::comm::recv;
|
||||||
|
|
||||||
export handle;
|
export handle;
|
||||||
export mk;
|
export mk;
|
||||||
|
@ -26,27 +26,27 @@ export run;
|
||||||
export close;
|
export close;
|
||||||
export reqchan;
|
export reqchan;
|
||||||
|
|
||||||
type reqchan = _chan<request>;
|
type reqchan = chan<request>;
|
||||||
|
|
||||||
type handle = {task: option::t<task_id>, chan: reqchan};
|
type handle = {task: option::t<task_id>, chan: reqchan};
|
||||||
|
|
||||||
tag request {
|
tag request {
|
||||||
exec([u8], [u8], [[u8]], _chan<response>);
|
exec([u8], [u8], [[u8]], chan<response>);
|
||||||
stop;
|
stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
type response = {pid: int, infd: int, outfd: int, errfd: int};
|
type response = {pid: int, infd: int, outfd: int, errfd: int};
|
||||||
|
|
||||||
fn mk() -> handle {
|
fn mk() -> handle {
|
||||||
let setupport = mk_port();
|
let setupport = port();
|
||||||
let task = task::_spawn(bind fn(setupchan: _chan<_chan<request>>) {
|
let task = task::spawn(bind fn(setupchan: chan<chan<request>>) {
|
||||||
let reqport = mk_port();
|
let reqport = port();
|
||||||
let reqchan = reqport.mk_chan();
|
let reqchan = chan(reqport);
|
||||||
send(setupchan, reqchan);
|
send(setupchan, reqchan);
|
||||||
worker(reqport);
|
worker(reqport);
|
||||||
} (setupport.mk_chan()));
|
} (chan(setupport)));
|
||||||
ret {task: option::some(task),
|
ret {task: option::some(task),
|
||||||
chan: setupport.recv()
|
chan: recv(setupport)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,13 +60,13 @@ fn close(handle: &handle) {
|
||||||
fn run(handle: &handle, lib_path: &str,
|
fn run(handle: &handle, lib_path: &str,
|
||||||
prog: &str, args: &[str], input: &option::t<str>) ->
|
prog: &str, args: &[str], input: &option::t<str>) ->
|
||||||
{status: int, out: str, err: str} {
|
{status: int, out: str, err: str} {
|
||||||
let p = mk_port::<response>();
|
let p = port();
|
||||||
let ch = p.mk_chan();
|
let ch = chan(p);
|
||||||
send(handle.chan, exec(str::bytes(lib_path),
|
send(handle.chan, exec(str::bytes(lib_path),
|
||||||
str::bytes(prog),
|
str::bytes(prog),
|
||||||
clone_ivecstr(args),
|
clone_ivecstr(args),
|
||||||
ch));
|
ch));
|
||||||
let resp = p.recv();
|
let resp = recv(p);
|
||||||
|
|
||||||
writeclose(resp.infd, input);
|
writeclose(resp.infd, input);
|
||||||
let output = readclose(resp.outfd);
|
let output = readclose(resp.outfd);
|
||||||
|
@ -99,18 +99,12 @@ fn readclose(fd: int) -> str {
|
||||||
ret buf;
|
ret buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worker(p: _port<request>) {
|
fn worker(p: port<request>) {
|
||||||
|
|
||||||
// FIXME (787): If we declare this inside of the while loop and then
|
// FIXME (787): If we declare this inside of the while loop and then
|
||||||
// break out of it before it's ever initialized (i.e. we don't run
|
// break out of it before it's ever initialized (i.e. we don't run
|
||||||
// any tests), then the cleanups will puke, so we're initializing it
|
// any tests), then the cleanups will puke.
|
||||||
// here with defaults.
|
let execparms;
|
||||||
let execparms = {
|
|
||||||
lib_path: "",
|
|
||||||
prog: "",
|
|
||||||
args: ~[],
|
|
||||||
respchan: p.mk_chan()
|
|
||||||
};
|
|
||||||
|
|
||||||
while true {
|
while true {
|
||||||
// FIXME: Sending strings across channels seems to still
|
// FIXME: Sending strings across channels seems to still
|
||||||
|
@ -124,7 +118,7 @@ fn worker(p: _port<request>) {
|
||||||
// put the entire alt in another block to make sure the exec
|
// put the entire alt in another block to make sure the exec
|
||||||
// message goes out of scope. Seems like the scoping rules for
|
// message goes out of scope. Seems like the scoping rules for
|
||||||
// the alt discriminant are wrong.
|
// the alt discriminant are wrong.
|
||||||
alt p.recv() {
|
alt recv(p) {
|
||||||
exec(lib_path, prog, args, respchan) {
|
exec(lib_path, prog, args, respchan) {
|
||||||
{
|
{
|
||||||
lib_path: str::unsafe_from_bytes(lib_path),
|
lib_path: str::unsafe_from_bytes(lib_path),
|
||||||
|
|
|
@ -4,7 +4,7 @@ import std::comm::_chan;
|
||||||
import std::comm::mk_port;
|
import std::comm::mk_port;
|
||||||
import std::comm::send;
|
import std::comm::send;
|
||||||
|
|
||||||
fn echo<~T>(c: _chan<T>, oc: _chan<_chan<T>>) {
|
fn echo<~T>(c: &_chan<T>, oc: &_chan<_chan<T>>) {
|
||||||
// Tests that the type argument in port gets
|
// Tests that the type argument in port gets
|
||||||
// visited
|
// visited
|
||||||
let p = mk_port::<T>();
|
let p = mk_port::<T>();
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use std;
|
use std;
|
||||||
import std::comm::_chan;
|
import std::comm::chan;
|
||||||
import std::comm::send;
|
import std::comm::send;
|
||||||
import std::comm::mk_port;
|
import std::comm::port;
|
||||||
|
|
||||||
// tests that ctrl's type gets inferred properly
|
// tests that ctrl's type gets inferred properly
|
||||||
type command<K, V> = {key: K, val: V};
|
type command<~K, ~V> = {key: K, val: V};
|
||||||
|
|
||||||
fn cache_server<K, V>(c: _chan<_chan<command<K, V>>>) {
|
fn cache_server<~K, ~V>(c: &chan<chan<command<K, V>>>) {
|
||||||
let ctrl = mk_port::<_chan<command<K, V>>>();
|
let ctrl = port();
|
||||||
send(c, ctrl.mk_chan());
|
send(c, chan(ctrl));
|
||||||
}
|
}
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -25,3 +25,19 @@ fn send_recv_fn() {
|
||||||
comm::send(c, 42);
|
comm::send(c, 42);
|
||||||
assert(comm::recv(p) == 42);
|
assert(comm::recv(p) == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn send_recv_fn_infer() {
|
||||||
|
let p = comm::port();
|
||||||
|
let c = comm::chan(p);
|
||||||
|
comm::send(c, 42);
|
||||||
|
assert(comm::recv(p) == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn chan_chan() {
|
||||||
|
let p = comm::port(), p2 = comm::port::<int>();
|
||||||
|
let c = comm::chan(p);
|
||||||
|
comm::send(c, comm::chan(p2));
|
||||||
|
let c2 = comm::recv(p);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue