From 4b3e766ac6a6f89430b65a5bc2f55bb29f6290ab Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 31 Jul 2013 16:10:35 -0700 Subject: [PATCH] Remove the pipes compiler The pipes compiler produced data types that encoded efficient and safe bounded message passing protocols between two endpoints. It was also capable of producing unbounded protocols. It was useful research but was arguably done before its proper time. I am removing it for the following reasons: * In practice we used it only for producing the `oneshot` and `stream` unbounded protocols and all communication in Rust use those. * The interface between the proto! macro and the standard library has a large surface area and was difficult to maintain through language and library changes. * It is now written in an old dialect of Rust and generates code which would likely be considered non-idiomatic. * Both the compiler and the runtime are difficult to understand, and likewise the relationship between the generated code and the library is hard to understand. Debugging is difficult. * The new scheduler implements `stream` and `oneshot` by hand in a way that will be significantly easier to maintain. This shouldn't be taken as an indication that 'channel protocols' for Rust are not worth pursuing again in the future. --- src/libsyntax/ext/base.rs | 6 +- src/libsyntax/ext/pipes/ast_builder.rs | 63 --- src/libsyntax/ext/pipes/check.rs | 82 --- src/libsyntax/ext/pipes/liveness.rs | 106 ---- src/libsyntax/ext/pipes/mod.rs | 84 ---- src/libsyntax/ext/pipes/parse_proto.rs | 124 ----- src/libsyntax/ext/pipes/pipec.rs | 467 ------------------ src/libsyntax/ext/pipes/proto.rs | 227 --------- src/libsyntax/ext/quote.rs | 2 +- src/libsyntax/syntax.rs | 2 - src/test/bench/msgsend-ring-pipes.rs | 111 ----- src/test/bench/pingpong.rs | 210 -------- src/test/run-pass/issue-2834.rs | 30 -- src/test/run-pass/issue-2930.rs | 21 - src/test/run-pass/pipe-bank-proto.rs | 115 ----- src/test/run-pass/pipe-detect-term.rs | 60 --- src/test/run-pass/pipe-peek.rs | 31 -- src/test/run-pass/pipe-pingpong-bounded.rs | 126 ----- src/test/run-pass/pipe-pingpong-proto.rs | 65 --- .../run-pass/pipe-presentation-examples.rs | 179 ------- src/test/run-pass/pipe-select-macro.rs | 62 --- src/test/run-pass/pipe-select.rs | 134 ----- src/test/run-pass/pipe-sleep.rs | 65 --- 23 files changed, 3 insertions(+), 2369 deletions(-) delete mode 100644 src/libsyntax/ext/pipes/ast_builder.rs delete mode 100644 src/libsyntax/ext/pipes/check.rs delete mode 100644 src/libsyntax/ext/pipes/liveness.rs delete mode 100644 src/libsyntax/ext/pipes/mod.rs delete mode 100644 src/libsyntax/ext/pipes/parse_proto.rs delete mode 100644 src/libsyntax/ext/pipes/pipec.rs delete mode 100644 src/libsyntax/ext/pipes/proto.rs delete mode 100644 src/test/bench/msgsend-ring-pipes.rs delete mode 100644 src/test/bench/pingpong.rs delete mode 100644 src/test/run-pass/issue-2834.rs delete mode 100644 src/test/run-pass/issue-2930.rs delete mode 100644 src/test/run-pass/pipe-bank-proto.rs delete mode 100644 src/test/run-pass/pipe-detect-term.rs delete mode 100644 src/test/run-pass/pipe-peek.rs delete mode 100644 src/test/run-pass/pipe-pingpong-bounded.rs delete mode 100644 src/test/run-pass/pipe-pingpong-proto.rs delete mode 100644 src/test/run-pass/pipe-presentation-examples.rs delete mode 100644 src/test/run-pass/pipe-select-macro.rs delete mode 100644 src/test/run-pass/pipe-select.rs delete mode 100644 src/test/run-pass/pipe-sleep.rs diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ea87646e60b0b..90e1c7db91a50 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -81,8 +81,8 @@ pub enum SyntaxExtension { // An IdentTT is a macro that has an // identifier in between the name of the // macro and the argument. Currently, - // the only examples of this are - // macro_rules! and proto! + // the only examples of this is + // macro_rules! // perhaps macro_rules! will lose its odd special identifier argument, // and this can go away also @@ -197,8 +197,6 @@ pub fn syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(intern(&"module_path"), builtin_normal_tt( ext::source_util::expand_mod)); - syntax_expanders.insert(intern(&"proto"), - builtin_item_tt(ext::pipes::expand_proto)); syntax_expanders.insert(intern(&"asm"), builtin_normal_tt(ext::asm::expand_asm)); syntax_expanders.insert( diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs deleted file mode 100644 index eb8b01c427dcb..0000000000000 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Functions for building ASTs, without having to fuss with spans. -// -// To start with, it will be use dummy spans, but it might someday do -// something smarter. - -use ast::ident; -use ast; -use codemap::span; - -use std::vec; - -// Transitional reexports so qquote can find the paths it is looking for -mod syntax { - pub use ext; - pub use parse; -} - -pub fn path(ids: ~[ident], span: span) -> ast::Path { - ast::Path { span: span, - global: false, - idents: ids, - rp: None, - types: ~[] } -} - -pub fn path_global(ids: ~[ident], span: span) -> ast::Path { - ast::Path { span: span, - global: true, - idents: ids, - rp: None, - types: ~[] } -} - -pub trait append_types { - fn add_ty(&self, ty: ast::Ty) -> ast::Path; - fn add_tys(&self, tys: ~[ast::Ty]) -> ast::Path; -} - -impl append_types for ast::Path { - fn add_ty(&self, ty: ast::Ty) -> ast::Path { - ast::Path { - types: vec::append_one(self.types.clone(), ty), - .. (*self).clone() - } - } - - fn add_tys(&self, tys: ~[ast::Ty]) -> ast::Path { - ast::Path { - types: vec::append(self.types.clone(), tys), - .. (*self).clone() - } - } -} diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs deleted file mode 100644 index adf10215cb566..0000000000000 --- a/src/libsyntax/ext/pipes/check.rs +++ /dev/null @@ -1,82 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// Correctness for protocols - -/* - -This section of code makes sure the protocol is likely to generate -correct code. The correctness criteria include: - - * No protocols transition to states that don't exist. - * Messages step to states with the right number of type parameters. - -In addition, this serves as a lint pass. Lint warns for the following -things. - - * States with no messages, it's better to step to !. - -It would also be nice to warn about unreachable states, but the -visitor infrastructure for protocols doesn't currently work well for -that. - -*/ - -use ast; -use codemap::span; -use ext::base::ExtCtxt; -use ext::pipes::proto::{state, protocol, next_state}; -use ext::pipes::proto; - -impl proto::visitor<(), (), ()> for @ExtCtxt { - fn visit_proto(&self, _proto: protocol, _states: &[()]) { } - - fn visit_state(&self, state: state, _m: &[()]) { - let messages = &*state.messages; - if messages.len() == 0 { - self.span_warn( - state.span, // use a real span! - fmt!("state %s contains no messages, \ - consider stepping to a terminal state instead", - state.name)) - } - } - - fn visit_message(&self, name: @str, _span: span, _tys: &[ast::Ty], - this: state, next: Option) { - match next { - Some(ref next_state) => { - let proto = this.proto; - if !proto.has_state(next_state.state) { - // This should be a span fatal, but then we need to - // track span information. - self.span_err( - proto.get_state(next_state.state).span, - fmt!("message %s steps to undefined state, %s", - name, next_state.state)); - } - else { - let next = proto.get_state(next_state.state); - - if next.generics.ty_params.len() != next_state.tys.len() { - self.span_err( - next.span, // use a real span - fmt!("message %s target (%s) \ - needs %u type parameters, but got %u", - name, next.name, - next.generics.ty_params.len(), - next_state.tys.len())); - } - } - } - None => () - } - } -} diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs deleted file mode 100644 index b080a730f3e29..0000000000000 --- a/src/libsyntax/ext/pipes/liveness.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/* - -Liveness analysis for protocols. This is useful for a lot of possible -optimizations. - -This analysis computes the "co-live" relationship between -states. Co-live is defined inductively as follows. - -1. u is co-live with v if u can transition to v in one message. - -2. u is co-live with v if there exists a w such that u and w are -co-live, w and v are co-live, and u and w have the same direction. - -This relationship approximates when it is safe to store two states in -the same memory location. If there is no u such u is co-live with -itself, then the protocol is bounded. - -(These assertions could use proofs) - -In addition, this analysis does reachability, to warn when we have -useless states. - -The algorithm is a fixpoint computation. For each state, we initialize -a bitvector containing whether it is co-live with each other state. At -first we use rule (1) above to set each vector. Then we iterate -updating the states using rule (2) until there are no changes. - -*/ - -use ext::base::ExtCtxt; -use ext::pipes::proto::{protocol_}; - -use extra::bitv::Bitv; - -pub fn analyze(proto: @mut protocol_, _cx: @ExtCtxt) { - debug!("initializing colive analysis"); - let num_states = proto.num_states(); - let mut colive: ~[~Bitv] = do proto.states.iter().transform() |state| { - let mut bv = ~Bitv::new(num_states, false); - for state.reachable |s| { - bv.set(s.id, true); - } - bv - }.collect(); - - let mut i = 0; - let mut changed = true; - while changed { - changed = false; - debug!("colive iteration %?", i); - let mut new_colive = ~[]; - foreach (i, this_colive) in colive.iter().enumerate() { - let mut result = this_colive.clone(); - let this = proto.get_state_by_id(i); - for this_colive.ones |j| { - let next = proto.get_state_by_id(j); - if this.dir == next.dir { - changed = result.union(colive[j]) || changed; - } - } - new_colive.push(result) - } - colive = new_colive; - i += 1; - } - - debug!("colive analysis complete"); - - // Determine if we're bounded - let mut self_live = ~[]; - foreach (i, bv) in colive.iter().enumerate() { - if bv.get(i) { - self_live.push(proto.get_state_by_id(i)) - } - } - - if self_live.len() > 0 { - let states = self_live.map(|s| s.name).connect(" "); - - debug!("protocol %s is unbounded due to loops involving: %s", - proto.name, - states); - - // Someday this will be configurable with a warning - //cx.span_warn(empty_span(), - // fmt!("protocol %s is unbounded due to loops \ - // involving these states: %s", - // *proto.name, - // states)); - - proto.bounded = Some(false); - } else { - debug!("protocol %s is bounded. yay!", proto.name); - proto.bounded = Some(true); - } -} diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs deleted file mode 100644 index b8a0da8fe8fb7..0000000000000 --- a/src/libsyntax/ext/pipes/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Implementation of proto! extension. - -This is frequently called the pipe compiler. It handles code such as... - -~~~ -proto! pingpong ( - ping: send { - ping -> pong - } - pong: recv { - pong -> ping - } -) -~~~ - -There are several components: - - * The parser (libsyntax/ext/pipes/parse_proto.rs) - * Responsible for building an AST from a protocol specification. - - * The checker (libsyntax/ext/pipes/check.rs) - * Basic correctness checking for protocols (i.e. no undefined states, etc.) - - * The analyzer (libsyntax/ext/pipes/liveness.rs) - * Determines whether the protocol is bounded or unbounded. - - * The compiler (libsynatx/ext/pipes/pipec.rs) - * Generates a Rust AST from the protocol AST and the results of analysis. - -There is more documentation in each of the files referenced above. - -FIXME (#3072) - This is still incomplete. - -*/ - -use ast; -use codemap::span; -use ext::base; -use ext::base::ExtCtxt; -use ext::pipes::parse_proto::proto_parser; -use ext::pipes::pipec::gen_init; -use ext::pipes::proto::visit; -use parse::lexer::{new_tt_reader, reader}; -use parse::parser::Parser; - -pub mod ast_builder; -pub mod parse_proto; -pub mod pipec; -pub mod proto; -pub mod check; -pub mod liveness; - - -pub fn expand_proto(cx: @ExtCtxt, _sp: span, id: ast::ident, - tt: ~[ast::token_tree]) -> base::MacResult { - let sess = cx.parse_sess(); - let cfg = cx.cfg(); - let tt_rdr = new_tt_reader(cx.parse_sess().span_diagnostic, - None, - tt.clone()); - let rdr = tt_rdr as @reader; - let rust_parser = Parser(sess, cfg, rdr.dup()); - - let proto = rust_parser.parse_proto(cx.str_of(id)); - - // check for errors - visit(proto, cx); - - // do analysis - liveness::analyze(proto, cx); - - // compile - base::MRItem(proto.compile(cx)) -} diff --git a/src/libsyntax/ext/pipes/parse_proto.rs b/src/libsyntax/ext/pipes/parse_proto.rs deleted file mode 100644 index e5219721594c9..0000000000000 --- a/src/libsyntax/ext/pipes/parse_proto.rs +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Parsing pipes protocols from token trees. - -use ast_util; -use ext::pipes::proto::*; -use parse::common::SeqSep; -use parse::parser; -use parse::token; -use parse::token::{interner_get}; - -pub trait proto_parser { - fn parse_proto(&self, id: @str) -> protocol; - fn parse_state(&self, proto: protocol); - fn parse_message(&self, state: state); -} - -impl proto_parser for parser::Parser { - fn parse_proto(&self, id: @str) -> protocol { - let proto = protocol(id, *self.span); - - self.parse_seq_to_before_end( - &token::EOF, - SeqSep { - sep: None, - trailing_sep_allowed: false, - }, - |this| this.parse_state(proto) - ); - - return proto; - } - - fn parse_state(&self, proto: protocol) { - let id = self.parse_ident(); - let name = interner_get(id.name); - - self.expect(&token::COLON); - let dir = match (*self.token).clone() { - token::IDENT(n, _) => interner_get(n.name), - _ => fail!() - }; - self.bump(); - let dir = match dir.as_slice() { - "send" => send, - "recv" => recv, - _ => fail!() - }; - - let generics = if *self.token == token::LT { - self.parse_generics() - } else { - ast_util::empty_generics() - }; - - let state = proto.add_state_poly(name, id, dir, generics); - - // parse the messages - self.parse_unspanned_seq( - &token::LBRACE, - &token::RBRACE, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |this| this.parse_message(state) - ); - } - - fn parse_message(&self, state: state) { - let mname = interner_get(self.parse_ident().name); - - let args = if *self.token == token::LPAREN { - self.parse_unspanned_seq( - &token::LPAREN, - &token::RPAREN, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |p| p.parse_ty(false) - ) - } - else { ~[] }; - - self.expect(&token::RARROW); - - let next = match *self.token { - token::IDENT(_, _) => { - let name = interner_get(self.parse_ident().name); - let ntys = if *self.token == token::LT { - self.parse_unspanned_seq( - &token::LT, - &token::GT, - SeqSep { - sep: Some(token::COMMA), - trailing_sep_allowed: true, - }, - |p| p.parse_ty(false) - ) - } - else { ~[] }; - Some(next_state {state: name, tys: ntys}) - } - token::NOT => { - // -> ! - self.bump(); - None - } - _ => self.fatal("invalid next state") - }; - - state.add_message(mname, *self.span, args, next); - - } -} diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs deleted file mode 100644 index 02aef13a3a829..0000000000000 --- a/src/libsyntax/ext/pipes/pipec.rs +++ /dev/null @@ -1,467 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// A protocol compiler for Rust. - -use ast; -use codemap::{dummy_sp, spanned}; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::pipes::ast_builder::{append_types, path}; -use ext::pipes::ast_builder::{path_global}; -use ext::pipes::proto::*; -use ext::quote::rt::*; -use opt_vec; -use opt_vec::OptVec; - -use std::vec; - -pub trait gen_send { - fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item; - fn to_ty(&mut self, cx: @ExtCtxt) -> ast::Ty; -} - -pub trait to_type_decls { - fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item]; - fn to_endpoint_decls(&self, cx: @ExtCtxt, - dir: direction) -> ~[@ast::item]; -} - -pub trait gen_init { - fn gen_init(&self, cx: @ExtCtxt) -> @ast::item; - fn compile(&self, cx: @ExtCtxt) -> @ast::item; - fn buffer_ty_path(&self, cx: @ExtCtxt) -> ast::Ty; - fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item; - fn gen_buffer_init(&self, ext_cx: @ExtCtxt) -> @ast::expr; - fn gen_init_bounded(&self, ext_cx: @ExtCtxt) -> @ast::expr; -} - -impl gen_send for message { - fn gen_send(&mut self, cx: @ExtCtxt, try: bool) -> @ast::item { - debug!("pipec: gen_send"); - let name = self.name(); - - match *self { - message(ref _id, span, ref tys, this, Some(ref next_state)) => { - debug!("pipec: next state exists"); - let next = this.proto.get_state(next_state.state); - assert!(next_state.tys.len() == - next.generics.ty_params.len()); - let arg_names = vec::from_fn(tys.len(), |i| cx.ident_of("x_"+i.to_str())); - let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(n, t)| - cx.arg(span, (*n).clone(), (*t).clone())).collect(); - - let pipe_ty = cx.ty_path( - path(~[this.data_name()], span) - .add_tys(cx.ty_vars(&this.generics.ty_params)), None); - let args_ast = vec::append( - ~[cx.arg(span, cx.ident_of("pipe"), pipe_ty)], - args_ast); - - let mut body = ~"{\n"; - body.push_str(fmt!("use super::%s;\n", name)); - body.push_str("let mut pipe = pipe;\n"); - - if this.proto.is_bounded() { - let (sp, rp) = match (this.dir, next.dir) { - (send, send) => (~"c", ~"s"), - (send, recv) => (~"s", ~"c"), - (recv, send) => (~"s", ~"c"), - (recv, recv) => (~"c", ~"s") - }; - - body.push_str("let mut b = pipe.reuse_buffer();\n"); - body.push_str(fmt!("let %s = ::std::pipes::SendPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - sp, - next.name)); - body.push_str(fmt!("let %s = ::std::pipes::RecvPacketBuffered(\ - &mut (b.buffer.data.%s));\n", - rp, - next.name)); - } - else { - let pat = match (this.dir, next.dir) { - (send, send) => "(s, c)", - (send, recv) => "(c, s)", - (recv, send) => "(c, s)", - (recv, recv) => "(s, c)" - }; - - body.push_str(fmt!("let %s = ::std::pipes::entangle();\n", pat)); - } - body.push_str(fmt!("let message = %s(%s);\n", - name, - vec::append_one(arg_names.map(|x| cx.str_of(*x)), @"s") - .connect(", "))); - - if !try { - body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); - // return the new channel - body.push_str("c }"); - } - else { - body.push_str(fmt!("if ::std::pipes::send(pipe, message) {\n \ - ::std::pipes::rt::make_some(c) \ - } else { ::std::pipes::rt::make_none() } }")); - } - - let body = cx.parse_expr(body.to_managed()); - - let mut rty = cx.ty_path(path(~[next.data_name()], - span) - .add_tys(next_state.tys.clone()), None); - if try { - rty = cx.ty_option(rty); - } - - let name = if try {cx.ident_of(~"try_" + name)} else {cx.ident_of(name)}; - - cx.item_fn_poly(dummy_sp(), - name, - args_ast, - rty, - self.get_generics(), - cx.blk_expr(body)) - } - - message(ref _id, span, ref tys, this, None) => { - debug!("pipec: no next state"); - let arg_names = vec::from_fn(tys.len(), |i| "x_" + i.to_str()); - - let args_ast: ~[ast::arg] = arg_names.iter().zip(tys.iter()) - .transform(|(n, t)| - cx.arg(span, cx.ident_of(*n), (*t).clone())).collect(); - - let args_ast = vec::append( - ~[cx.arg(span, - cx.ident_of("pipe"), - cx.ty_path( - path(~[this.data_name()], span) - .add_tys(cx.ty_vars( - &this.generics.ty_params)), None))], - args_ast); - - let message_args = if arg_names.len() == 0 { - ~"" - } - else { - ~"(" + arg_names.map(|x| (*x).clone()).connect(", ") + ")" - }; - - let mut body = ~"{ "; - body.push_str(fmt!("use super::%s;\n", name)); - body.push_str(fmt!("let message = %s%s;\n", name, message_args)); - - if !try { - body.push_str(fmt!("::std::pipes::send(pipe, message);\n")); - body.push_str(" }"); - } else { - body.push_str(fmt!("if ::std::pipes::send(pipe, message) \ - { \ - ::std::pipes::rt::make_some(()) \ - } else { \ - ::std::pipes::rt::make_none() \ - } }")); - } - - let body = cx.parse_expr(body.to_managed()); - - let name = if try {cx.ident_of(~"try_" + name)} else {cx.ident_of(name)}; - - cx.item_fn_poly(dummy_sp(), - name, - args_ast, - if try { - cx.ty_option(cx.ty_nil()) - } else { - cx.ty_nil() - }, - self.get_generics(), - cx.blk_expr(body)) - } - } - } - - fn to_ty(&mut self, cx: @ExtCtxt) -> ast::Ty { - cx.ty_path(path(~[cx.ident_of(self.name())], self.span()) - .add_tys(cx.ty_vars(&self.get_generics().ty_params)), None) - } -} - -impl to_type_decls for state { - fn to_type_decls(&self, cx: @ExtCtxt) -> ~[@ast::item] { - debug!("pipec: to_type_decls"); - // This compiles into two different type declarations. Say the - // state is called ping. This will generate both `ping` and - // `ping_message`. The first contains data that the user cares - // about. The second is the same thing, but extended with a - // next packet pointer, which is used under the covers. - - let name = self.data_name(); - - let mut items_msg = ~[]; - - foreach m in self.messages.iter() { - let message(name, span, tys, this, next) = (*m).clone(); - - let tys = match next { - Some(ref next_state) => { - let next = this.proto.get_state((next_state.state)); - let next_name = cx.str_of(next.data_name()); - - let dir = match this.dir { - send => "server", - recv => "client" - }; - - vec::append_one(tys, - cx.ty_path( - path(~[cx.ident_of(dir), - cx.ident_of(next_name)], span) - .add_tys(next_state.tys.clone()), None)) - } - None => tys - }; - - let v = cx.variant(span, cx.ident_of(name), tys); - - items_msg.push(v); - } - - ~[ - cx.item_enum_poly( - self.span, - name, - ast::enum_def { variants: items_msg }, - cx.strip_bounds(&self.generics) - ) - ] - } - - fn to_endpoint_decls(&self, cx: @ExtCtxt, - dir: direction) -> ~[@ast::item] { - debug!("pipec: to_endpoint_decls"); - let dir = match dir { - send => (*self).dir, - recv => (*self).dir.reverse() - }; - let mut items = ~[]; - - { - foreach m in self.messages.mut_iter() { - if dir == send { - items.push(m.gen_send(cx, true)); - items.push(m.gen_send(cx, false)); - } - } - } - - if !self.proto.is_bounded() { - items.push( - cx.item_ty_poly( - self.span, - self.data_name(), - cx.ty_path( - path_global(~[cx.ident_of("std"), - cx.ident_of("pipes"), - cx.ident_of(dir.to_str() + "Packet")], - dummy_sp()) - .add_ty(cx.ty_path( - path(~[cx.ident_of("super"), - self.data_name()], - dummy_sp()) - .add_tys(cx.ty_vars( - &self.generics.ty_params)), None)), None), - cx.strip_bounds(&self.generics))); - } - else { - items.push( - cx.item_ty_poly( - self.span, - self.data_name(), - cx.ty_path( - path_global(~[cx.ident_of("std"), - cx.ident_of("pipes"), - cx.ident_of(dir.to_str() - + "PacketBuffered")], - dummy_sp()) - .add_tys(~[cx.ty_path( - path(~[cx.ident_of("super"), - self.data_name()], - dummy_sp()) - .add_tys(cx.ty_vars_global( - &self.generics.ty_params)), None), - self.proto.buffer_ty_path(cx)]), None), - cx.strip_bounds(&self.generics))); - }; - items - } -} - -impl gen_init for protocol { - fn gen_init(&self, cx: @ExtCtxt) -> @ast::item { - let ext_cx = cx; - - debug!("gen_init"); - let start_state = self.states[0]; - - let body = if !self.is_bounded() { - quote_expr!( ::std::pipes::entangle() ) - } - else { - self.gen_init_bounded(ext_cx) - }; - - cx.parse_item(fmt!("pub fn init%s() -> (server::%s, client::%s)\ - { pub use std::pipes::HasBuffer; %s }", - start_state.generics.to_source(), - start_state.to_ty(cx).to_source(), - start_state.to_ty(cx).to_source(), - body.to_source()).to_managed()) - } - - fn gen_buffer_init(&self, ext_cx: @ExtCtxt) -> @ast::expr { - ext_cx.expr_struct( - dummy_sp(), - path(~[ext_cx.ident_of("__Buffer")], - dummy_sp()), - self.states.iter().transform(|s| { - let fty = s.to_ty(ext_cx); - ext_cx.field_imm(dummy_sp(), - ext_cx.ident_of(s.name), - quote_expr!( - ::std::pipes::mk_packet::<$fty>() - )) - }).collect()) - } - - fn gen_init_bounded(&self, ext_cx: @ExtCtxt) -> @ast::expr { - debug!("gen_init_bounded"); - let buffer_fields = self.gen_buffer_init(ext_cx); - let buffer = quote_expr!(~::std::pipes::Buffer { - header: ::std::pipes::BufferHeader(), - data: $buffer_fields, - }); - - let entangle_body = ext_cx.expr_blk( - ext_cx.blk( - dummy_sp(), - self.states.iter().transform( - |s| ext_cx.parse_stmt( - fmt!("data.%s.set_buffer(buffer)", - s.name).to_managed())).collect(), - Some(ext_cx.parse_expr(fmt!( - "::std::ptr::to_mut_unsafe_ptr(&mut (data.%s))", - self.states[0].name).to_managed())))); - - quote_expr!({ - let buffer = $buffer; - do ::std::pipes::entangle_buffer(buffer) |buffer, data| { - $entangle_body - } - }) - } - - fn buffer_ty_path(&self, cx: @ExtCtxt) -> ast::Ty { - let mut params: OptVec = opt_vec::Empty; - foreach s in self.states.iter() { - foreach tp in s.generics.ty_params.iter() { - match params.iter().find_(|tpp| tp.ident == tpp.ident) { - None => params.push((*tp).clone()), - _ => () - } - } - } - - cx.ty_path(path(~[cx.ident_of("super"), - cx.ident_of("__Buffer")], - self.span) - .add_tys(cx.ty_vars_global(¶ms)), None) - } - - fn gen_buffer_type(&self, cx: @ExtCtxt) -> @ast::item { - let ext_cx = cx; - let mut params: OptVec = opt_vec::Empty; - let fields = do self.states.iter().transform |s| { - foreach tp in s.generics.ty_params.iter() { - match params.iter().find_(|tpp| tp.ident == tpp.ident) { - None => params.push((*tp).clone()), - _ => () - } - } - - let ty = s.to_ty(cx); - let fty = quote_ty!( ::std::pipes::Packet<$ty> ); - - @spanned { - node: ast::struct_field_ { - kind: ast::named_field(cx.ident_of(s.name), - ast::inherited), - id: cx.next_id(), - ty: fty, - attrs: ~[], - }, - span: dummy_sp() - } - }.collect(); - - let generics = Generics { - lifetimes: opt_vec::Empty, - ty_params: params - }; - - cx.item_struct_poly( - dummy_sp(), - cx.ident_of("__Buffer"), - ast::struct_def { - fields: fields, - ctor_id: None - }, - cx.strip_bounds(&generics)) - } - - fn compile(&self, cx: @ExtCtxt) -> @ast::item { - let mut items = ~[self.gen_init(cx)]; - let mut client_states = ~[]; - let mut server_states = ~[]; - - foreach s in self.states.iter() { - items.push_all_move(s.to_type_decls(cx)); - - client_states.push_all_move(s.to_endpoint_decls(cx, send)); - server_states.push_all_move(s.to_endpoint_decls(cx, recv)); - } - - if self.is_bounded() { - items.push(self.gen_buffer_type(cx)) - } - - items.push(cx.item_mod(self.span, - cx.ident_of("client"), - ~[], ~[], - client_states)); - items.push(cx.item_mod(self.span, - cx.ident_of("server"), - ~[], ~[], - server_states)); - - // XXX: Would be nice if our generated code didn't violate - // Rust coding conventions - let allows = cx.attribute( - self.span, - cx.meta_list(self.span, - @"allow", - ~[cx.meta_word(self.span, @"non_camel_case_types"), - cx.meta_word(self.span, @"unused_mut")])); - cx.item_mod(self.span, cx.ident_of(self.name), ~[allows], ~[], items) - } -} diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs deleted file mode 100644 index 5d2ebb68b8a0d..0000000000000 --- a/src/libsyntax/ext/pipes/proto.rs +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use ast; -use codemap::span; -use ext::base::ExtCtxt; -use ext::build::AstBuilder; -use ext::pipes::ast_builder::{append_types, path}; - -#[deriving(Eq)] -pub enum direction { send, recv } - -impl ToStr for direction { - fn to_str(&self) -> ~str { - match *self { - send => ~"Send", - recv => ~"Recv" - } - } -} - -impl direction { - pub fn reverse(&self) -> direction { - match *self { - send => recv, - recv => send - } - } -} - -#[deriving(Clone)] -pub struct next_state { - state: @str, - tys: ~[ast::Ty], -} - -// name, span, data, current state, next state -#[deriving(Clone)] -pub struct message(@str, span, ~[ast::Ty], state, Option); - -impl message { - pub fn name(&mut self) -> @str { - match *self { - message(id, _, _, _, _) => id - } - } - - pub fn span(&mut self) -> span { - match *self { - message(_, span, _, _, _) => span - } - } - - /// Return the type parameters actually used by this message - pub fn get_generics(&self) -> ast::Generics { - match *self { - message(_, _, _, this, _) => this.generics.clone() - } - } -} - -pub type state = @state_; - -pub struct state_ { - id: uint, - name: @str, - ident: ast::ident, - span: span, - dir: direction, - generics: ast::Generics, - messages: @mut ~[message], - proto: protocol -} - -impl state_ { - pub fn add_message(@self, - name: @str, - span: span, - data: ~[ast::Ty], - next: Option) { - self.messages.push(message(name, span, data, self, - next)); - } - - pub fn filename(&self) -> ~str { - self.proto.filename() - } - - pub fn data_name(&self) -> ast::ident { - self.ident - } - - /// Returns the type that is used for the messages. - pub fn to_ty(&self, cx: @ExtCtxt) -> ast::Ty { - cx.ty_path - (path(~[cx.ident_of(self.name)],self.span).add_tys( - cx.ty_vars(&self.generics.ty_params)), None) - } - - /// Iterate over the states that can be reached in one message - /// from this state. - pub fn reachable(&self, f: &fn(state) -> bool) -> bool { - foreach m in self.messages.iter() { - match *m { - message(_, _, _, _, Some(next_state { state: ref id, _ })) => { - let state = self.proto.get_state((*id)); - if !f(state) { return false; } - } - _ => () - } - } - return true; - } -} - -pub type protocol = @mut protocol_; - -pub fn protocol(name: @str, span: span) -> protocol { - @mut protocol_(name, span) -} - -pub fn protocol_(name: @str, span: span) -> protocol_ { - protocol_ { - name: name, - span: span, - states: @mut ~[], - bounded: None - } -} - -pub struct protocol_ { - name: @str, - span: span, - states: @mut ~[state], - - bounded: Option, -} - -impl protocol_ { - /// Get a state. - pub fn get_state(&self, name: &str) -> state { - let mut i = self.states.iter(); - *i.find_(|i| name == i.name).get() - } - - pub fn get_state_by_id(&self, id: uint) -> state { self.states[id] } - - pub fn has_state(&self, name: &str) -> bool { - self.states.iter().find_(|i| name == i.name).is_some() - } - - pub fn filename(&self) -> ~str { - ~"proto://" + self.name - } - - pub fn num_states(&self) -> uint { - let states = &mut *self.states; - states.len() - } - - pub fn has_ty_params(&self) -> bool { - foreach s in self.states.iter() { - if s.generics.ty_params.len() > 0 { - return true; - } - } - false - } - - pub fn is_bounded(&self) -> bool { - let bounded = self.bounded.get(); - bounded - } -} - -impl protocol_ { - pub fn add_state_poly(@mut self, - name: @str, - ident: ast::ident, - dir: direction, - generics: ast::Generics) - -> state { - let messages = @mut ~[]; - let states = &mut *self.states; - - let state = @state_ { - id: states.len(), - name: name, - ident: ident, - span: self.span, - dir: dir, - generics: generics, - messages: messages, - proto: self - }; - - states.push(state); - state - } -} - -pub trait visitor { - fn visit_proto(&self, proto: protocol, st: &[Tstate]) -> Tproto; - fn visit_state(&self, state: state, m: &[Tmessage]) -> Tstate; - fn visit_message(&self, name: @str, spane: span, tys: &[ast::Ty], - this: state, next: Option) -> Tmessage; -} - -pub fn visit>( - proto: protocol, visitor: V) -> Tproto { - - let states: ~[Tstate] = do proto.states.iter().transform |&s| { - let messages: ~[Tmessage] = do s.messages.iter().transform |m| { - let message(name, span, tys, this, next) = (*m).clone(); - visitor.visit_message(name, span, tys, this, next) - }.collect(); - visitor.visit_state(s, messages) - }.collect(); - visitor.visit_proto(proto, states) -} diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index bcfd898dc6fda..4e7b0612e6446 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -683,7 +683,7 @@ fn expand_tts(cx: @ExtCtxt, // the site the string literal occurred, which was in a source file // _other_ than the one the user has control over. For example, an // error in a quote from the protocol compiler, invoked in user code - // using proto! for example, will be attributed to the pipec.rs file in + // using macro_rules! for example, will be attributed to the macro_rules.rs file in // libsyntax, which the user might not even have source to (unless they // happen to have a compiler on hand). Over all, the phase distinction // just makes quotes "hard to attribute". Possibly this could be fixed diff --git a/src/libsyntax/syntax.rs b/src/libsyntax/syntax.rs index ae2aa6ae73891..f39351bf91f08 100644 --- a/src/libsyntax/syntax.rs +++ b/src/libsyntax/syntax.rs @@ -78,7 +78,5 @@ pub mod ext { pub mod auto_encode; pub mod source_util; - pub mod pipes; - pub mod trace_macros; } diff --git a/src/test/bench/msgsend-ring-pipes.rs b/src/test/bench/msgsend-ring-pipes.rs deleted file mode 100644 index 27cd34c5199a1..0000000000000 --- a/src/test/bench/msgsend-ring-pipes.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This test creates a bunch of tasks that simultaneously send to each -// other in a ring. The messages should all be basically -// independent. It's designed to hammer the global kernel lock, so -// that things will look really good once we get that lock out of the -// message path. - -// This version uses automatically compiled channel contracts. - -extern mod extra; - -use extra::future; -use extra::time; -use std::cell::Cell; -use std::io; -use std::os; -use std::pipes::recv; -use std::uint; -use std::util; - -proto! ring ( - num:send { - num(uint) -> num - } -) - -fn thread_ring(i: uint, - count: uint, - num_chan: ring::client::num, - num_port: ring::server::num) { - let mut num_chan = Some(num_chan); - let mut num_port = Some(num_port); - // Send/Receive lots of messages. - for uint::range(0, count) |j| { - //error!("task %?, iter %?", i, j); - let num_chan2 = util::replace(&mut num_chan, None); - let num_port2 = util::replace(&mut num_port, None); - num_chan = Some(ring::client::num(num_chan2.unwrap(), i * j)); - let port = num_port2.unwrap(); - match recv(port) { - ring::num(_n, p) => { - //log(error, _n); - num_port = Some(p); - } - } - }; -} - -fn main() { - let args = os::args(); - let args = if os::getenv("RUST_BENCH").is_some() { - ~[~"", ~"100", ~"10000"] - } else if args.len() <= 1u { - ~[~"", ~"100", ~"1000"] - } else { - args.clone() - }; - - let num_tasks = uint::from_str(args[1]).get(); - let msg_per_task = uint::from_str(args[2]).get(); - - let (num_port, num_chan) = ring::init(); - let num_chan = Cell::new(num_chan); - - let start = time::precise_time_s(); - - // create the ring - let mut futures = ~[]; - - for uint::range(1u, num_tasks) |i| { - //error!("spawning %?", i); - let (num_port, new_chan) = ring::init(); - let num_chan2 = Cell::new(num_chan.take()); - let num_port = Cell::new(num_port); - let new_future = do future::spawn || { - let num_chan = num_chan2.take(); - let num_port1 = num_port.take(); - thread_ring(i, msg_per_task, num_chan, num_port1) - }; - futures.push(new_future); - num_chan.put_back(new_chan); - }; - - // do our iteration - thread_ring(0, msg_per_task, num_chan.take(), num_port); - - // synchronize - foreach f in futures.mut_iter() { - let _ = f.get(); - } - - let stop = time::precise_time_s(); - - // all done, report stats. - let num_msgs = num_tasks * msg_per_task; - let elapsed = (stop - start); - let rate = (num_msgs as float) / elapsed; - - printfln!("Sent %? messages in %? seconds", num_msgs, elapsed); - printfln!(" %? messages / second", rate); - printfln!(" %? μs / message", 1000000. / rate); -} diff --git a/src/test/bench/pingpong.rs b/src/test/bench/pingpong.rs deleted file mode 100644 index b11daeef12f51..0000000000000 --- a/src/test/bench/pingpong.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Compare bounded and unbounded protocol performance. - -// xfail-pretty - -extern mod extra; - -use extra::time::precise_time_s; -use std::cell::Cell; -use std::io; -use std::os; -use std::pipes::*; -use std::task; - -proto! pingpong ( - ping: send { - ping -> pong - } - - pong: recv { - pong -> ping - } -) - -proto! pingpong_unbounded ( - ping: send { - ping -> pong - } - - pong: recv { - pong -> ping - } - - you_will_never_catch_me: send { - never_ever_ever -> you_will_never_catch_me - } -) - -// This stuff should go in libcore::pipes -macro_rules! move_it ( - { $x:expr } => { let t = *ptr::to_unsafe_ptr(&($x)); t } -) - -macro_rules! follow ( - { - $($message:path($($x: ident),+) -> $next:ident $e:expr)+ - } => ( - |m| match m { - $(Some($message($($x,)* next)) => { - let $next = next; - $e })+ - _ => { fail!() } - } - ); - - { - $($message:path -> $next:ident $e:expr)+ - } => ( - |m| match m { - $(Some($message(next)) => { - let $next = next; - $e })+ - _ => { fail!() } - } - ) -) - - -/** Spawn a task to provide a service. - -It takes an initialization function that produces a send and receive -endpoint. The send endpoint is returned to the caller and the receive -endpoint is passed to the new task. - -*/ -pub fn spawn_service( - init: extern fn() -> (RecvPacketBuffered, - SendPacketBuffered), - service: ~fn(v: RecvPacketBuffered)) - -> SendPacketBuffered { - let (server, client) = init(); - - // This is some nasty gymnastics required to safely move the pipe - // into a new task. - let server = Cell::new(server); - do task::spawn { - service(server.take()); - } - - client -} - -/** Like `spawn_service_recv`, but for protocols that start in the -receive state. - -*/ -pub fn spawn_service_recv( - init: extern fn() -> (SendPacketBuffered, - RecvPacketBuffered), - service: ~fn(v: SendPacketBuffered)) - -> RecvPacketBuffered { - let (server, client) = init(); - - // This is some nasty gymnastics required to safely move the pipe - // into a new task. - let server = Cell::new(server); - do task::spawn { - service(server.take()) - } - - client -} - -fn switch(endp: std::pipes::RecvPacketBuffered, - f: &fn(v: Option) -> U) - -> U { - f(std::pipes::try_recv(endp)) -} - -// Here's the benchmark - -fn bounded(count: uint) { - use pingpong::*; - - let mut ch = do spawn_service(init) |ch| { - let mut count = count; - let mut ch = ch; - while count > 0 { - ch = switch(ch, follow! ( - ping -> next { server::pong(next) } - )); - - count -= 1; - } - }; - - let mut count = count; - while count > 0 { - let ch_ = client::ping(ch); - - ch = switch(ch_, follow! ( - pong -> next { next } - )); - - count -= 1; - } -} - -fn unbounded(count: uint) { - use pingpong_unbounded::*; - - let mut ch = do spawn_service(init) |ch| { - let mut count = count; - let mut ch = ch; - while count > 0 { - ch = switch(ch, follow! ( - ping -> next { server::pong(next) } - )); - - count -= 1; - } - }; - - let mut count = count; - while count > 0 { - let ch_ = client::ping(ch); - - ch = switch(ch_, follow! ( - pong -> next { next } - )); - - count -= 1; - } -} - -fn timeit(f: &fn()) -> float { - let start = precise_time_s(); - f(); - let stop = precise_time_s(); - stop - start -} - -fn main() { - let count = if os::getenv("RUST_BENCH").is_some() { - 250000 - } else { - 100 - }; - let bounded = do timeit { bounded(count) }; - let unbounded = do timeit { unbounded(count) }; - - printfln!("count: %?\n", count); - printfln!("bounded: %? s\t(%? μs/message)", - bounded, bounded * 1000000. / (count as float)); - printfln!("unbounded: %? s\t(%? μs/message)", - unbounded, unbounded * 1000000. / (count as float)); - - printfln!("\n\ - bounded is %?%% faster", - (unbounded - bounded) / bounded * 100.); -} diff --git a/src/test/run-pass/issue-2834.rs b/src/test/run-pass/issue-2834.rs deleted file mode 100644 index b0ddccf28944b..0000000000000 --- a/src/test/run-pass/issue-2834.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test case for issue #2843. -// - -proto! streamp ( - open:send { - data(T) -> open - } -) - -fn rendezvous() { - let (s, c) = streamp::init(); - let streams: ~[streamp::client::open] = ~[c]; - - error!("%?", streams[0]); -} - -pub fn main() { - //os::getenv("FOO"); - rendezvous(); -} diff --git a/src/test/run-pass/issue-2930.rs b/src/test/run-pass/issue-2930.rs deleted file mode 100644 index 10a19d62bd97b..0000000000000 --- a/src/test/run-pass/issue-2930.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -proto! stream ( - Stream:send { - send(T) -> Stream - } -) - -pub fn main() { - let (_bp, bc) = stream::init(); - - stream::client::send(bc, ~"abc"); -} diff --git a/src/test/run-pass/pipe-bank-proto.rs b/src/test/run-pass/pipe-bank-proto.rs deleted file mode 100644 index 11c43b9390198..0000000000000 --- a/src/test/run-pass/pipe-bank-proto.rs +++ /dev/null @@ -1,115 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// An example of the bank protocol from eholk's blog post. -// -// http://theincredibleholk.wordpress.com/2012/07/06/rusty-pipes/ - -use std::pipes; -use std::pipes::try_recv; -use std::ptr; - -pub type username = ~str; -pub type password = ~str; -pub type money = float; -pub type amount = float; - -proto! bank ( - login:send { - login(::username, ::password) -> login_response - } - - login_response:recv { - ok -> connected, - invalid -> login - } - - connected:send { - deposit(::money) -> connected, - withdrawal(::amount) -> withdrawal_response - } - - withdrawal_response:recv { - money(::money) -> connected, - insufficient_funds -> connected - } -) - -fn switch(endp: pipes::RecvPacket, - f: &fn(v: Option) -> U) -> U { - f(pipes::try_recv(endp)) -} - -macro_rules! follow ( - { - $($message:path$(($($x: ident),+))||* -> $next:ident $e:expr)+ - } => ( - |m| match m { - $(Some($message($($($x,)+)* next)) => { - let $next = next; - $e })+ - _ => { fail!() } - } - ); -) - -fn client_follow(bank: bank::client::login) { - use bank::*; - - let bank = client::login(bank, ~"theincredibleholk", ~"1234"); - let bank = switch(bank, follow! ( - ok -> connected { connected } - invalid -> _next { fail!("bank closed the connected") } - )); - - let bank = client::deposit(bank, 100.00); - let bank = client::withdrawal(bank, 50.00); - switch(bank, follow! ( - money(m) -> _next { - println(~"Yay! I got money!"); - } - insufficient_funds -> _next { - fail!("someone stole my money") - } - )); -} - -fn bank_client(bank: bank::client::login) { - use bank::*; - - let bank = client::login(bank, ~"theincredibleholk", ~"1234"); - let bank = match try_recv(bank) { - Some(ok(connected)) => { - connected - } - Some(invalid(_)) => { fail!("login unsuccessful") } - None => { fail!("bank closed the connection") } - }; - - let bank = client::deposit(bank, 100.00); - let bank = client::withdrawal(bank, 50.00); - match try_recv(bank) { - Some(money(*)) => { - println(~"Yay! I got money!"); - } - Some(insufficient_funds(_)) => { - fail!("someone stole my money") - } - None => { - fail!("bank closed the connection") - } - } -} - -pub fn main() { -} diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs deleted file mode 100644 index 42cd4081eda10..0000000000000 --- a/src/test/run-pass/pipe-detect-term.rs +++ /dev/null @@ -1,60 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Make sure that we can detect when one end of the pipe is closed. - -// xfail-win32 -// xfail-test needs sleep - -extern mod extra; -use extra::timer::sleep; -use extra::uv; - -use std::cell::Cell; -use std::pipes::{try_recv, recv}; -use std::task; - -proto! oneshot ( - waiting:send { - signal -> ! - } -) - -pub fn main() { - let iotask = &uv::global_loop::get(); - - let (port, chan) = oneshot::init(); - let port = Cell::new(port); - do spawn { - match try_recv(port.take()) { - Some(*) => { fail!() } - None => { } - } - } - - sleep(iotask, 100); - - task::spawn_unlinked(failtest); -} - -// Make sure the right thing happens during failure. -fn failtest() { - let (p, c) = oneshot::init(); - - do task::spawn_with(c) |_c| { - fail!(); - } - - error!("%?", recv(p)); - // make sure we get killed if we missed it in the receive. - loop { task::yield() } -} diff --git a/src/test/run-pass/pipe-peek.rs b/src/test/run-pass/pipe-peek.rs deleted file mode 100644 index a61aad2e55c7a..0000000000000 --- a/src/test/run-pass/pipe-peek.rs +++ /dev/null @@ -1,31 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::pipes; - -proto! oneshot ( - waiting:send { - signal -> ! - } -) - -pub fn main() { - let (p, c) = oneshot::init(); - let mut p = p; - let mut c = c; - - assert!(!pipes::peek(&mut p)); - - oneshot::client::signal(c); - - assert!(pipes::peek(&mut p)); -} diff --git a/src/test/run-pass/pipe-pingpong-bounded.rs b/src/test/run-pass/pipe-pingpong-bounded.rs deleted file mode 100644 index ab17607c4d7d5..0000000000000 --- a/src/test/run-pass/pipe-pingpong-bounded.rs +++ /dev/null @@ -1,126 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Ping-pong is a bounded protocol. This is place where I can -// experiment with what code the compiler should generate for bounded -// protocols. - -use std::cell::Cell; -use std::task; - -// This was generated initially by the pipe compiler, but it's been -// modified in hopefully straightforward ways. - -mod pingpong { - use std::pipes; - use std::pipes::*; - use std::ptr; - - pub struct Packets { - ping: Packet, - pong: Packet, - } - - pub fn init() -> (server::ping, client::ping) { - let buffer = ~Buffer { - header: BufferHeader(), - data: Packets { - ping: mk_packet::(), - pong: mk_packet::() - } - }; - do pipes::entangle_buffer(buffer) |buffer, data| { - data.ping.set_buffer(buffer); - data.pong.set_buffer(buffer); - ptr::to_mut_unsafe_ptr(&mut (data.ping)) - } - } - pub struct ping(server::pong); - pub struct pong(client::ping); - pub mod client { - use std::pipes; - use std::pipes::*; - use std::ptr; - - pub fn ping(mut pipe: ping) -> pong { - { - let mut b = pipe.reuse_buffer(); - let s = SendPacketBuffered(&mut b.buffer.data.pong); - let c = RecvPacketBuffered(&mut b.buffer.data.pong); - let message = ::pingpong::ping(s); - send(pipe, message); - c - } - } - pub type ping = pipes::SendPacketBuffered<::pingpong::ping, - ::pingpong::Packets>; - pub type pong = pipes::RecvPacketBuffered<::pingpong::pong, - ::pingpong::Packets>; - } - pub mod server { - use std::pipes; - use std::pipes::*; - use std::ptr; - - pub type ping = pipes::RecvPacketBuffered<::pingpong::ping, - ::pingpong::Packets>; - pub fn pong(mut pipe: pong) -> ping { - { - let mut b = pipe.reuse_buffer(); - let s = SendPacketBuffered(&mut b.buffer.data.ping); - let c = RecvPacketBuffered(&mut b.buffer.data.ping); - let message = ::pingpong::pong(s); - send(pipe, message); - c - } - } - pub type pong = pipes::SendPacketBuffered<::pingpong::pong, - ::pingpong::Packets>; - } -} - -mod test { - use std::pipes::recv; - use pingpong::{ping, pong}; - - pub fn client(chan: ::pingpong::client::ping) { - use pingpong::client; - - let chan = client::ping(chan); return; - error!("Sent ping"); - let pong(_chan) = recv(chan); - error!("Received pong"); - } - - pub fn server(chan: ::pingpong::server::ping) { - use pingpong::server; - - let ping(chan) = recv(chan); return; - error!("Received ping"); - let _chan = server::pong(chan); - error!("Sent pong"); - } -} - -pub fn main() { - let (server_, client_) = ::pingpong::init(); - let client_ = Cell::new(client_); - let server_ = Cell::new(server_); - do task::spawn { - let client__ = client_.take(); - test::client(client__); - }; - do task::spawn { - let server__ = server_.take(); - test::server(server__); - }; -} diff --git a/src/test/run-pass/pipe-pingpong-proto.rs b/src/test/run-pass/pipe-pingpong-proto.rs deleted file mode 100644 index a4268f9456b30..0000000000000 --- a/src/test/run-pass/pipe-pingpong-proto.rs +++ /dev/null @@ -1,65 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// An example to make sure the protocol parsing syntax extension works. - -use std::cell::Cell; -use std::option; -use std::task; - -proto! pingpong ( - ping:send { - ping -> pong - } - - pong:recv { - pong -> ping - } -) - -mod test { - use std::pipes::recv; - use pingpong::{ping, pong}; - - pub fn client(chan: ::pingpong::client::ping) { - use pingpong::client; - - let chan = client::ping(chan); - error!(~"Sent ping"); - let pong(_chan) = recv(chan); - error!(~"Received pong"); - } - - pub fn server(chan: ::pingpong::server::ping) { - use pingpong::server; - - let ping(chan) = recv(chan); - error!(~"Received ping"); - let _chan = server::pong(chan); - error!(~"Sent pong"); - } -} - -pub fn main() { - let (server_, client_) = pingpong::init(); - let client_ = Cell::new(client_); - let server_ = Cell::new(server_); - - do task::spawn { - let client__ = client_.take(); - test::client(client__); - }; - do task::spawn { - let server__ = server_.take(); - test::server(server__); - }; -} diff --git a/src/test/run-pass/pipe-presentation-examples.rs b/src/test/run-pass/pipe-presentation-examples.rs deleted file mode 100644 index 65e0537dfb704..0000000000000 --- a/src/test/run-pass/pipe-presentation-examples.rs +++ /dev/null @@ -1,179 +0,0 @@ -// xfail-fast -// xfail-test - -// XFAIL'd because this is going to be revamped, and it's not compatible as -// written with the new mutability rules. - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Examples from Eric's internship final presentation. -// -// Code is easier to write in emacs, and it's good to be sure all the -// code samples compile (or not) as they should. - -use double_buffer::client::*; -use double_buffer::give_buffer; -use std::comm::Selectable; - -macro_rules! select_if ( - { - $index:expr, - $count:expr, - $port:path => [ - $($message:path$(($($x: ident),+))dont_type_this* - -> $next:ident $e:expr),+ - ], - $( $ports:path => [ - $($messages:path$(($($xs: ident),+))dont_type_this* - -> $nexts:ident $es:expr),+ - ], )* - } => { - if $index == $count { - match std::pipes::try_recv($port) { - $(Some($message($($($x,)+)* next)) => { - let $next = next; - $e - })+ - _ => fail!() - } - } else { - select_if!( - $index, - $count + 1, - $( $ports => [ - $($messages$(($($xs),+))dont_type_this* - -> $nexts $es),+ - ], )* - ) - } - }; - - { - $index:expr, - $count:expr, - } => { - fail!() - } -) - -macro_rules! select ( - { - $( $port:path => { - $($message:path$(($($x: ident),+))dont_type_this* - -> $next:ident $e:expr),+ - } )+ - } => ({ - let index = std::comm::selecti([$(($port).header()),+]); - select_if!(index, 0, $( $port => [ - $($message$(($($x),+))dont_type_this* -> $next $e),+ - ], )+) - }) -) - -// Types and protocols -pub struct Buffer { - foo: (), - -} - -impl Drop for Buffer { - fn drop(&self) {} -} - -proto! double_buffer ( - acquire:send { - request -> wait_buffer - } - - wait_buffer:recv { - give_buffer(::Buffer) -> release - } - - release:send { - release(::Buffer) -> acquire - } -) - -// Code examples -fn render(_buffer: &Buffer) { - // A dummy function. -} - -fn draw_frame(+channel: double_buffer::client::acquire) { - let channel = request(channel); - select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - release(channel, buffer) - } - } - ); -} - -fn draw_two_frames(+channel: double_buffer::client::acquire) { - let channel = request(channel); - let channel = select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - release(channel, buffer) - } - } - ); - let channel = request(channel); - select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - release(channel, buffer) - } - } - ); -} - -#[cfg(bad1)] -fn draw_two_frames_bad1(+channel: double_buffer::client::acquire) { - let channel = request(channel); - select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - } - } - ); - let channel = request(channel); - select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - release(channel, buffer) - } - } - ); -} - -#[cfg(bad2)] -fn draw_two_frames_bad2(+channel: double_buffer::client::acquire) { - let channel = request(channel); - select! ( - channel => { - give_buffer(buffer) -> channel { - render(&buffer); - release(channel, buffer); - render(&buffer); - release(channel, buffer); - } - } - ); -} - -pub fn main() { } diff --git a/src/test/run-pass/pipe-select-macro.rs b/src/test/run-pass/pipe-select-macro.rs deleted file mode 100644 index cb126017247bc..0000000000000 --- a/src/test/run-pass/pipe-select-macro.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// FIXME #7303: xfail-test - -// Protocols -proto! foo ( - foo:recv { - do_foo -> foo - } -) - -proto! bar ( - bar:recv { - do_bar(int) -> barbar, - do_baz(bool) -> bazbar, - } - - barbar:send { - rebarbar -> bar, - } - - bazbar:send { - rebazbar -> bar - } -) - -fn macros() { - include!("select-macro.rs"); -} - -// Code -fn test(+foo: foo::client::foo, +bar: bar::client::bar) { - use bar::do_baz; - - select! ( - foo => { - foo::do_foo -> _next { - } - } - - bar => { - bar::do_bar(x) -> _next { - info!("%?", x) - }, - - do_baz(b) -> _next { - if b { info!("true") } else { info!("false") } - } - } - ) -} - -pub fn main() { -} diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs deleted file mode 100644 index d9e887fcee8bf..0000000000000 --- a/src/test/run-pass/pipe-select.rs +++ /dev/null @@ -1,134 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-pretty -// xfail-win32 -// xfail-test needs sleep - -extern mod extra; -use extra::timer::sleep; -use extra::uv; - -use std::cell::Cell; -use std::pipes::*; -use std::pipes; -use std::task; - -proto! oneshot ( - waiting:send { - signal -> ! - } -) - -proto! stream ( - Stream:send { - send(T) -> Stream - } -) - -pub fn spawn_service( - init: extern fn() -> (RecvPacketBuffered, - SendPacketBuffered), - service: ~fn(v: RecvPacketBuffered)) - -> SendPacketBuffered { - let (server, client) = init(); - - // This is some nasty gymnastics required to safely move the pipe - // into a new task. - let server = Cell::new(server); - do task::spawn { - service(server.take()); - } - - client -} - -pub fn main() { - use oneshot::client::*; - use stream::client::*; - - let iotask = &uv::global_loop::get(); - - let c = spawn_service(stream::init, |p| { - error!("waiting for pipes"); - let stream::send(x, p) = recv(p); - error!("got pipes"); - let (left, right) : (oneshot::server::waiting, - oneshot::server::waiting) - = x; - error!("selecting"); - let (i, _, _) = select(~[left, right]); - error!("selected"); - assert_eq!(i, 0); - - error!("waiting for pipes"); - let stream::send(x, _) = recv(p); - error!("got pipes"); - let (left, right) : (oneshot::server::waiting, - oneshot::server::waiting) - = x; - error!("selecting"); - let (i, m, _) = select(~[left, right]); - error!("selected %?", i); - if m.is_some() { - assert_eq!(i, 1); - } - }); - - let (p1, c1) = oneshot::init(); - let (p2, _c2) = oneshot::init(); - - let c = send(c, (p1, p2)); - - sleep(iotask, 100); - - signal(c1); - - let (p1, _c1) = oneshot::init(); - let (p2, c2) = oneshot::init(); - - send(c, (p1, p2)); - - sleep(iotask, 100); - - signal(c2); - - test_select2(); -} - -fn test_select2() { - let (ap, ac) = stream::init(); - let (bp, bc) = stream::init(); - - stream::client::send(ac, 42); - - match pipes::select2(ap, bp) { - Left(*) => { } - Right(*) => { fail!() } - } - - stream::client::send(bc, ~"abc"); - - error!("done with first select2"); - - let (ap, ac) = stream::init(); - let (bp, bc) = stream::init(); - - stream::client::send(bc, ~"abc"); - - match pipes::select2(ap, bp) { - Left(*) => { fail!() } - Right(*) => { } - } - - stream::client::send(ac, 42); -} diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs deleted file mode 100644 index 4475a16a63bb7..0000000000000 --- a/src/test/run-pass/pipe-sleep.rs +++ /dev/null @@ -1,65 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test needs sleep -// xfail-win32 #7999 - -extern mod extra; - -use extra::timer::sleep; -use extra::uv; -use std::cell::Cell; -use std::pipes::*; -use std::pipes; -use std::task; - -proto! oneshot ( - waiting:send { - signal -> ! - } -) - - -/** Spawn a task to provide a service. - -It takes an initialization function that produces a send and receive -endpoint. The send endpoint is returned to the caller and the receive -endpoint is passed to the new task. - -*/ -pub fn spawn_service( - init: extern fn() -> (RecvPacketBuffered, - SendPacketBuffered), - service: ~fn(v: RecvPacketBuffered)) - -> SendPacketBuffered { - let (server, client) = init(); - - // This is some nasty gymnastics required to safely move the pipe - // into a new task. - let server = Cell::new(server); - do task::spawn { - service(server.take()); - } - - client -} - -pub fn main() { - use oneshot::client::*; - - let c = spawn_service(oneshot::init, |p| { recv(p); }); - - let iotask = &uv::global_loop::get(); - sleep(iotask, 500); - - signal(c); -}