From 3a7eaac71443f3370b7fb7c5c1eb9cedce06dff5 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 4 Feb 2014 14:31:00 +1300 Subject: [PATCH 01/10] Check for trait impl conflicts across crates --- src/librustc/middle/typeck/coherence.rs | 32 ++++++++++++++++--- src/test/auxiliary/trait_impl_conflict.rs | 15 +++++++++ .../conflicting-implementations-aux.rs | 24 ++++++++++++++ 3 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 src/test/auxiliary/trait_impl_conflict.rs create mode 100644 src/test/compile-fail/conflicting-implementations-aux.rs diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 5ca879fea4a67..06776fc672eb0 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -15,7 +15,7 @@ // each trait in the system to its implementations. -use metadata::csearch::{each_impl, get_impl_trait}; +use metadata::csearch::{each_impl, get_impl_trait, each_implementation_for_trait}; use metadata::csearch; use middle::ty::get; use middle::ty::{ImplContainer, lookup_item_type, subst}; @@ -434,7 +434,7 @@ impl CoherenceChecker { pub fn check_implementation_coherence_of(&self, trait_def_id: DefId) { // Unify pairs of polytypes. - self.iter_impls_of_trait(trait_def_id, |a| { + self.iter_impls_of_trait_local(trait_def_id, |a| { let implementation_a = a; let polytype_a = self.get_self_type_for_implementation(implementation_a); @@ -452,12 +452,19 @@ impl CoherenceChecker { if self.polytypes_unify(polytype_a.clone(), polytype_b) { let session = self.crate_context.tcx.sess; session.span_err( - self.span_of_impl(implementation_b), + self.span_of_impl(implementation_a), format!("conflicting implementations for trait `{}`", ty::item_path_str(self.crate_context.tcx, trait_def_id))); - session.span_note(self.span_of_impl(implementation_a), - "note conflicting implementation here"); + if implementation_b.did.crate == LOCAL_CRATE { + session.span_note(self.span_of_impl(implementation_b), + "note conflicting implementation here"); + } else { + let crate_store = self.crate_context.tcx.sess.cstore; + let cdata = crate_store.get_crate_data(implementation_b.did.crate); + session.note( + "conflicting implementation in crate `" + cdata.name + "`"); + } } } }) @@ -465,6 +472,21 @@ impl CoherenceChecker { } pub fn iter_impls_of_trait(&self, trait_def_id: DefId, f: |@Impl|) { + self.iter_impls_of_trait_local(trait_def_id, |x| f(x)); + + if trait_def_id.crate == LOCAL_CRATE { + return; + } + + let crate_store = self.crate_context.tcx.sess.cstore; + csearch::each_implementation_for_trait(crate_store, trait_def_id, |impl_def_id| { + let implementation = @csearch::get_impl(self.crate_context.tcx, impl_def_id); + let _ = lookup_item_type(self.crate_context.tcx, implementation.did); + f(implementation); + }); + } + + pub fn iter_impls_of_trait_local(&self, trait_def_id: DefId, f: |@Impl|) { let trait_impls = self.crate_context.tcx.trait_impls.borrow(); match trait_impls.get().find(&trait_def_id) { Some(impls) => { diff --git a/src/test/auxiliary/trait_impl_conflict.rs b/src/test/auxiliary/trait_impl_conflict.rs new file mode 100644 index 0000000000000..990bc21604959 --- /dev/null +++ b/src/test/auxiliary/trait_impl_conflict.rs @@ -0,0 +1,15 @@ +// 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. + +pub trait Foo { +} + +impl Foo for int { +} diff --git a/src/test/compile-fail/conflicting-implementations-aux.rs b/src/test/compile-fail/conflicting-implementations-aux.rs new file mode 100644 index 0000000000000..e39059124a091 --- /dev/null +++ b/src/test/compile-fail/conflicting-implementations-aux.rs @@ -0,0 +1,24 @@ +// Copyright 2014 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. + +// Regression test for #3512 - conflicting trait impls in different crates should give a +// 'conflicting implementations' error message. + +// aux-build:trait_impl_conflict.rs +extern mod trait_impl_conflict; +use trait_impl_conflict::Foo; + +impl Foo for A { +//~^ ERROR conflicting implementations for trait `trait_impl_conflict::Foo` +//~^^ ERROR cannot provide an extension implementation where both trait and type are not defined in this crate +} + +fn main() { +} From 068250f301e3db6fec3d223ea0efa2f0c46a35e9 Mon Sep 17 00:00:00 2001 From: James Deng Date: Tue, 4 Feb 2014 16:35:57 +1100 Subject: [PATCH 02/10] Feature gate all quasi-quoting macros. --- src/librustc/front/feature_gate.rs | 25 ++++++++++++++++--- src/librustc/lib.rs | 2 ++ src/libsyntax/lib.rs | 2 ++ src/test/auxiliary/macro_crate_test.rs | 2 +- src/test/compile-fail/qquote-1.rs | 1 + src/test/compile-fail/qquote-2.rs | 1 + src/test/run-pass-fulldeps/qquote.rs | 1 + src/test/run-pass-fulldeps/quote-tokens.rs | 2 +- .../quote-unused-sp-no-warning.rs | 2 +- 9 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index ed4455c2f89a1..ae6c6ec683123 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -49,6 +49,12 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("trace_macros", Active), ("simd", Active), ("default_type_params", Active), + ("quote_tokens", Active), + ("quote_expr", Active), + ("quote_ty", Active), + ("quote_item", Active), + ("quote_pat", Active), + ("quote_stmt", Active), // These are used to test this portion of the compiler, they don't actually // mean anything @@ -189,24 +195,35 @@ impl Visitor<()> for Context { fn visit_mac(&mut self, macro: &ast::Mac, _: ()) { let ast::MacInvocTT(ref path, _, _) = macro.node; + let id = path.segments.last().unwrap().identifier; + let quotes = ["quote_tokens", "quote_expr", "quote_ty", + "quote_item", "quote_pat", "quote_stmt"]; + let msg = " is not stable enough for use and are subject to change"; - if path.segments.last().unwrap().identifier == self.sess.ident_of("macro_rules") { + + if id == self.sess.ident_of("macro_rules") { self.gate_feature("macro_rules", path.span, "macro definitions are \ not stable enough for use and are subject to change"); } - else if path.segments.last().unwrap().identifier == self.sess.ident_of("asm") { + else if id == self.sess.ident_of("asm") { self.gate_feature("asm", path.span, "inline assembly is not \ stable enough for use and is subject to change"); } - else if path.segments.last().unwrap().identifier == self.sess.ident_of("log_syntax") { + else if id == self.sess.ident_of("log_syntax") { self.gate_feature("log_syntax", path.span, "`log_syntax!` is not \ stable enough for use and is subject to change"); } - else if path.segments.last().unwrap().identifier == self.sess.ident_of("trace_macros") { + else if id == self.sess.ident_of("trace_macros") { self.gate_feature("trace_macros", path.span, "`trace_macros` is not \ stable enough for use and is subject to change"); + } else { + for "e in quotes.iter() { + if id == self.sess.ident_of(quote) { + self.gate_feature(quote, path.span, quote + msg); + } + } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 36f44c8870dcc..6848d2c49eb1c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -28,6 +28,8 @@ This API is completely unstable and subject to change. html_root_url = "http://static.rust-lang.org/doc/master")]; #[feature(macro_rules, globs, struct_variant, managed_boxes)]; +#[allow(unknown_features)]; // Note: remove it after a snapshot. +#[feature(quote_item, quote_expr)]; extern mod extra; extern mod flate; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index e2460b0171a20..d65f35f1866db 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -27,6 +27,8 @@ This API is completely unstable and subject to change. html_root_url = "http://static.rust-lang.org/doc/master")]; #[feature(macro_rules, globs, managed_boxes)]; +#[allow(unknown_features)]; +#[feature(quote_expr)]; #[deny(non_camel_case_types)]; diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index e5bf8574366c8..8fe8d545374eb 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -10,7 +10,7 @@ // force-host -#[feature(globs, macro_registrar, macro_rules)]; +#[feature(globs, macro_registrar, macro_rules, quote_expr)]; extern mod syntax; diff --git a/src/test/compile-fail/qquote-1.rs b/src/test/compile-fail/qquote-1.rs index f55fcfc204b2f..7dd809137512a 100644 --- a/src/test/compile-fail/qquote-1.rs +++ b/src/test/compile-fail/qquote-1.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-test Can't use syntax crate here +#[feature(quote_expr)]; extern mod extra; extern mod syntax; diff --git a/src/test/compile-fail/qquote-2.rs b/src/test/compile-fail/qquote-2.rs index 262abc045a411..4ef5e41a3be66 100644 --- a/src/test/compile-fail/qquote-2.rs +++ b/src/test/compile-fail/qquote-2.rs @@ -9,6 +9,7 @@ // except according to those terms. // xfail-test Can't use syntax crate here +#[feature(quote_stmt)]; extern mod extra; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 05225eb0e7ada..d1bf0abd0d021 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -10,6 +10,7 @@ // xfail-pretty // xfail-test +#[feature(quote_expr, quote_ty, quote_item, quote_stmt, quote_pat)]; extern mod extra; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index dc95faa198647..47bcb3e75750e 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -9,7 +9,7 @@ // except according to those terms. // xfail-test - +#[feature(quote_expr, quote_tokens, quote_item, quote_pat, quote_stmt)]; #[feature(managed_boxes)]; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs index a8b7dc3d382f3..a7979d19389d5 100644 --- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs +++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs @@ -10,7 +10,7 @@ // xfail-fast // xfail-android - +#[feature(quote_expr)]; #[deny(unused_variable)]; extern mod syntax; From d99a9653d7fe0ac67a6a9793560d8e50233a5240 Mon Sep 17 00:00:00 2001 From: James Deng Date: Tue, 4 Feb 2014 22:03:00 +1100 Subject: [PATCH 03/10] Replaced with a single "quote" feature gate. --- src/librustc/front/feature_gate.rs | 9 ++------- src/librustc/lib.rs | 2 +- src/libsyntax/lib.rs | 4 ++-- src/test/auxiliary/macro_crate_test.rs | 2 +- src/test/compile-fail/qquote-1.rs | 2 +- src/test/compile-fail/qquote-2.rs | 2 +- src/test/run-pass-fulldeps/qquote.rs | 2 +- src/test/run-pass-fulldeps/quote-tokens.rs | 2 +- src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs | 2 +- 9 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/librustc/front/feature_gate.rs b/src/librustc/front/feature_gate.rs index ae6c6ec683123..15056d9d2d842 100644 --- a/src/librustc/front/feature_gate.rs +++ b/src/librustc/front/feature_gate.rs @@ -49,12 +49,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[ ("trace_macros", Active), ("simd", Active), ("default_type_params", Active), - ("quote_tokens", Active), - ("quote_expr", Active), - ("quote_ty", Active), - ("quote_item", Active), - ("quote_pat", Active), - ("quote_stmt", Active), + ("quote", Active), // These are used to test this portion of the compiler, they don't actually // mean anything @@ -221,7 +216,7 @@ impl Visitor<()> for Context { } else { for "e in quotes.iter() { if id == self.sess.ident_of(quote) { - self.gate_feature(quote, path.span, quote + msg); + self.gate_feature("quote", path.span, quote + msg); } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 6848d2c49eb1c..8e722fae13a36 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -29,7 +29,7 @@ This API is completely unstable and subject to change. #[feature(macro_rules, globs, struct_variant, managed_boxes)]; #[allow(unknown_features)]; // Note: remove it after a snapshot. -#[feature(quote_item, quote_expr)]; +#[feature(quote)]; extern mod extra; extern mod flate; diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index d65f35f1866db..bcad19f21220c 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -27,8 +27,8 @@ This API is completely unstable and subject to change. html_root_url = "http://static.rust-lang.org/doc/master")]; #[feature(macro_rules, globs, managed_boxes)]; -#[allow(unknown_features)]; -#[feature(quote_expr)]; +#[allow(unknown_features)];// Note: remove it after a snapshot. +#[feature(quote)]; #[deny(non_camel_case_types)]; diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index 8fe8d545374eb..2867e0f814306 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -10,7 +10,7 @@ // force-host -#[feature(globs, macro_registrar, macro_rules, quote_expr)]; +#[feature(globs, macro_registrar, macro_rules, quote)]; extern mod syntax; diff --git a/src/test/compile-fail/qquote-1.rs b/src/test/compile-fail/qquote-1.rs index 7dd809137512a..6dcbf3df9d653 100644 --- a/src/test/compile-fail/qquote-1.rs +++ b/src/test/compile-fail/qquote-1.rs @@ -9,7 +9,7 @@ // except according to those terms. // xfail-test Can't use syntax crate here -#[feature(quote_expr)]; +#[feature(quote)]; extern mod extra; extern mod syntax; diff --git a/src/test/compile-fail/qquote-2.rs b/src/test/compile-fail/qquote-2.rs index 4ef5e41a3be66..0e5c852fd6ecb 100644 --- a/src/test/compile-fail/qquote-2.rs +++ b/src/test/compile-fail/qquote-2.rs @@ -9,7 +9,7 @@ // except according to those terms. // xfail-test Can't use syntax crate here -#[feature(quote_stmt)]; +#[feature(quote)]; extern mod extra; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index d1bf0abd0d021..dc67ff21585dc 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -10,7 +10,7 @@ // xfail-pretty // xfail-test -#[feature(quote_expr, quote_ty, quote_item, quote_stmt, quote_pat)]; +#[feature(quote)]; extern mod extra; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index 47bcb3e75750e..7429ac45904cc 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -9,7 +9,7 @@ // except according to those terms. // xfail-test -#[feature(quote_expr, quote_tokens, quote_item, quote_pat, quote_stmt)]; +#[feature(quote)]; #[feature(managed_boxes)]; extern mod syntax; diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs index a7979d19389d5..0411c0b1cea3f 100644 --- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs +++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs @@ -10,7 +10,7 @@ // xfail-fast // xfail-android -#[feature(quote_expr)]; +#[feature(quote)]; #[deny(unused_variable)]; extern mod syntax; From c4b333b81dd93a188423a4e8b52f202a401008dc Mon Sep 17 00:00:00 2001 From: chromatic Date: Tue, 4 Feb 2014 16:06:41 -0800 Subject: [PATCH 04/10] Improved pattern-match code and explanation. This cleans up a warning about an unused variable and explains the code further. --- src/doc/tutorial.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index a7696b4540560..75a5840a1ef69 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -509,7 +509,7 @@ fn angle(vector: (f64, f64)) -> f64 { let pi = f64::consts::PI; match vector { (0.0, y) if y < 0.0 => 1.5 * pi, - (0.0, y) => 0.5 * pi, + (0.0, _) => 0.5 * pi, (x, y) => atan(y / x) } } @@ -519,7 +519,9 @@ A variable name in a pattern matches any value, *and* binds that name to the value of the matched value inside of the arm's action. Thus, `(0.0, y)` matches any tuple whose first element is zero, and binds `y` to the second element. `(x, y)` matches any two-element tuple, and binds both -elements to variables. +elements to variables. `(0.0,_)` matches any tuple whose first element is zero +and does not bind anything to the second element. + A subpattern can also be bound to a variable, using `variable @ pattern`. For example: From a70e6b01c25bfb9f17af1f53e3fed82ea4537650 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 5 Feb 2014 02:11:06 -0500 Subject: [PATCH 05/10] stop calling `exchange_free` on 0-size types A solid step towards fixing #11998. Eventually, the size may always be passed to `exchange_free` but this will not be required to fix the bug. --- src/librustc/middle/trans/glue.rs | 36 ++++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 1bfbb3f99b199..99eccb8f40b99 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -30,7 +30,7 @@ use middle::trans::machine::*; use middle::trans::reflect; use middle::trans::tvec; use middle::trans::type_::Type; -use middle::trans::type_of::type_of; +use middle::trans::type_of::{type_of, sizing_type_of}; use middle::ty; use util::ppaux::ty_to_short_str; use util::ppaux; @@ -100,23 +100,29 @@ pub fn lazily_emit_all_tydesc_glue(ccx: @CrateContext, lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti); } -fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t { +fn get_glue_type(ccx: &CrateContext, field: uint, t: ty::t) -> ty::t { + let tcx = ccx.tcx; if field == abi::tydesc_field_drop_glue { if !ty::type_needs_drop(tcx, t) { - return ty::mk_nil(); + return ty::mk_i8(); } match ty::get(t).sty { - ty::ty_box(typ) - if !ty::type_needs_drop(tcx, typ) => - return ty::mk_box(tcx, ty::mk_nil()), - - ty::ty_uniq(typ) - if !ty::type_needs_drop(tcx, typ) => - return ty::mk_uniq(tcx, ty::mk_nil()), + ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) => + return ty::mk_box(tcx, ty::mk_i8()), + + ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => { + let llty = sizing_type_of(ccx, typ); + // Unique boxes do not allocate for zero-size types. The standard library may assume + // that `free` is never called on the pointer returned for `~ZeroSizeType`. + if llsize_of_alloc(ccx, llty) == 0 { + return ty::mk_i8(); + } else { + return ty::mk_uniq(tcx, ty::mk_i8()); + } + } - ty::ty_vec(mt, ty::vstore_uniq) - if !ty::type_needs_drop(tcx, mt.ty) => - return ty::mk_uniq(tcx, ty::mk_nil()), + ty::ty_vec(mt, ty::vstore_uniq) if !ty::type_needs_drop(tcx, mt.ty) => + return ty::mk_uniq(tcx, ty::mk_i8()), _ => {} } @@ -128,7 +134,7 @@ fn simplified_glue_type(tcx: ty::ctxt, field: uint, t: ty::t) -> ty::t { pub fn lazily_emit_tydesc_glue(ccx: @CrateContext, field: uint, ti: @tydesc_info) { let _icx = push_ctxt("lazily_emit_tydesc_glue"); - let simpl = simplified_glue_type(ccx.tcx, field, ti.ty); + let simpl = get_glue_type(ccx, field, ti.ty); if simpl != ti.ty { let _icx = push_ctxt("lazily_emit_simplified_tydesc_glue"); let simpl_ti = get_tydesc(ccx, simpl); @@ -204,7 +210,7 @@ pub fn call_tydesc_glue_full(bcx: &Block, v: ValueRef, tydesc: ValueRef, PointerCast(bcx, v, Type::i8p()) } else { let ty = static_ti.unwrap().ty; - let simpl = simplified_glue_type(ccx.tcx, field, ty); + let simpl = get_glue_type(ccx, field, ty); if simpl != ty { PointerCast(bcx, v, type_of(ccx, simpl).ptr_to()) } else { From e9a6bb217f8257ab5cec4ed046aa276b4d4cdde9 Mon Sep 17 00:00:00 2001 From: JeremyLetang Date: Thu, 30 Jan 2014 15:04:47 -0500 Subject: [PATCH 06/10] move concurrent stuff from libextra to libsync --- mk/crates.mk | 9 +- src/doc/guide-tasks.md | 108 ++++++++++++------ src/doc/index.md | 1 + src/etc/licenseck.py | 2 +- src/libextra/lib.rs | 15 ++- src/libextra/workcache.rs | 2 +- src/librustc/back/link.rs | 2 +- src/librustc/lib.rs | 1 + src/librustc/middle/trans/base.rs | 2 +- src/librustdoc/html/render.rs | 2 +- src/librustdoc/lib.rs | 1 + src/{libextra => libsync}/arc.rs | 8 +- src/{libextra => libsync}/comm.rs | 0 src/{libextra => libsync}/future.rs | 2 +- src/libsync/lib.rs | 31 +++++ src/{libextra => libsync}/sync/mod.rs | 6 +- .../sync/mpsc_intrusive.rs | 0 src/{libextra => libsync}/sync/mutex.rs | 4 +- src/{libextra => libsync}/sync/one.rs | 2 +- src/{libextra => libsync}/task_pool.rs | 0 src/test/bench/msgsend-ring-mutex-arcs.rs | 10 +- src/test/bench/msgsend-ring-rw-arcs.rs | 9 +- src/test/bench/shootout-binarytrees.rs | 4 +- src/test/bench/shootout-spectralnorm.rs | 6 +- .../compile-fail/arc-cant-nest-rw-arc-3177.rs | 4 +- .../arc-rw-cond-shouldnt-escape.rs | 6 +- .../arc-rw-read-mode-shouldnt-escape.rs | 6 +- .../arc-rw-state-shouldnt-escape.rs | 6 +- .../arc-rw-write-mode-cond-shouldnt-escape.rs | 6 +- .../arc-rw-write-mode-shouldnt-escape.rs | 6 +- .../functional-struct-update-noncopyable.rs | 4 +- src/test/compile-fail/future_not_copyable.rs | 4 +- src/test/compile-fail/mutex-arc-nested.rs | 4 +- src/test/compile-fail/no-capture-arc.rs | 6 +- src/test/compile-fail/no-reuse-move-arc.rs | 6 +- .../once-cant-call-twice-on-heap.rs | 6 +- .../once-cant-call-twice-on-stack.rs | 6 +- ...once-cant-move-out-of-non-once-on-stack.rs | 6 +- .../compile-fail/sync-cond-shouldnt-escape.rs | 4 +- .../sync-rwlock-cond-shouldnt-escape.rs | 6 +- .../sync-rwlock-read-mode-shouldnt-escape.rs | 6 +- ...-rwlock-write-mode-cond-shouldnt-escape.rs | 6 +- .../sync-rwlock-write-mode-shouldnt-escape.rs | 6 +- src/test/run-fail/issue-2444.rs | 6 +- src/test/run-pass/bind-by-move.rs | 8 +- src/test/run-pass/once-move-out-on-heap.rs | 6 +- src/test/run-pass/once-move-out-on-stack.rs | 6 +- src/test/run-pass/trait-bounds-in-arc.rs | 12 +- 48 files changed, 224 insertions(+), 145 deletions(-) rename src/{libextra => libsync}/arc.rs (99%) rename src/{libextra => libsync}/comm.rs (100%) rename src/{libextra => libsync}/future.rs (99%) create mode 100644 src/libsync/lib.rs rename src/{libextra => libsync}/sync/mod.rs (99%) rename src/{libextra => libsync}/sync/mpsc_intrusive.rs (100%) rename src/{libextra => libsync}/sync/mutex.rs (99%) rename src/{libextra => libsync}/sync/one.rs (99%) rename src/{libextra => libsync}/task_pool.rs (100%) diff --git a/mk/crates.mk b/mk/crates.mk index e02e4fb8706e8..dd94d268becb5 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -49,25 +49,26 @@ # automatically generated for all stage/host/target combinations. ################################################################################ -TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid +TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid sync HOST_CRATES := syntax rustc rustdoc CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_std := native:rustrt -DEPS_extra := std term +DEPS_extra := std term sync DEPS_green := std DEPS_rustuv := std native:uv native:uv_support DEPS_native := std DEPS_syntax := std extra term -DEPS_rustc := syntax native:rustllvm flate arena -DEPS_rustdoc := rustc native:sundown +DEPS_rustc := syntax native:rustllvm flate arena sync +DEPS_rustdoc := rustc native:sundown sync DEPS_flate := std native:miniz DEPS_arena := std extra DEPS_glob := std DEPS_term := std DEPS_semver := std DEPS_uuid := std extra +DEPS_sync := std TOOL_DEPS_compiletest := extra green rustuv TOOL_DEPS_rustdoc := rustdoc green rustuv diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index c3bdbe3a3ee89..387f481025df7 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -39,7 +39,7 @@ data through the global _exchange heap_. While Rust's type system provides the building blocks needed for safe and efficient tasks, all of the task functionality itself is implemented -in the standard and extra libraries, which are still under development +in the standard and sync libraries, which are still under development and do not always present a consistent or complete interface. For your reference, these are the standard modules involved in Rust @@ -47,18 +47,43 @@ concurrency at this writing: * [`std::task`] - All code relating to tasks and task scheduling, * [`std::comm`] - The message passing interface, -* [`extra::comm`] - Additional messaging types based on `std::comm`, -* [`extra::sync`] - More exotic synchronization tools, including locks, -* [`extra::arc`] - The Arc (atomically reference counted) type, - for safely sharing immutable data, -* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time. +* [`sync::DuplexStream`] - An extension of `pipes::stream` that allows both sending and receiving, +* [`sync::SyncChan`] - An extension of `pipes::stream` that provides synchronous message sending, +* [`sync::SyncPort`] - An extension of `pipes::stream` that acknowledges each message received, +* [`sync::rendezvous`] - Creates a stream whose channel, upon sending a message, blocks until the + message is received. +* [`sync::Arc`] - The Arc (atomically reference counted) type, for safely sharing immutable data, +* [`sync::RWArc`] - A dual-mode Arc protected by a reader-writer lock, +* [`sync::MutexArc`] - An Arc with mutable data protected by a blocking mutex, +* [`sync::Semaphore`] - A counting, blocking, bounded-waiting semaphore, +* [`sync::Mutex`] - A blocking, bounded-waiting, mutual exclusion lock with an associated + FIFO condition variable, +* [`sync::RWLock`] - A blocking, no-starvation, reader-writer lock with an associated condvar, +* [`sync::Barrier`] - A barrier enables multiple tasks to synchronize the beginning + of some computation, +* [`sync::TaskPool`] - A task pool abstraction, +* [`sync::Future`] - A type encapsulating the result of a computation which may not be complete, +* [`sync::one`] - A "once initialization" primitive +* [`sync::mutex`] - A proper mutex implementation regardless of the "flavor of task" which is + acquiring the lock. [`std::task`]: std/task/index.html [`std::comm`]: std/comm/index.html -[`extra::comm`]: extra/comm/index.html -[`extra::sync`]: extra/sync/index.html -[`extra::arc`]: extra/arc/index.html -[`extra::future`]: extra/future/index.html +[`sync::DuplexStream`]: sync/struct.DuplexStream.html +[`sync::SyncChan`]: sync/struct.SyncChan.html +[`sync::SyncPort`]: sync/struct.SyncPort.html +[`sync::rendezvous`]: sync/fn.rendezvous.html +[`sync::Arc`]: sync/struct.Arc.html +[`sync::RWArc`]: sync/struct.RWArc.html +[`sync::MutexArc`]: sync/struct.MutexArc.html +[`sync::Semaphore`]: sync/struct.Semaphore.html +[`sync::Mutex`]: sync/struct.Mutex.html +[`sync::RWLock`]: sync/struct.RWLock.html +[`sync::Barrier`]: sync/struct.Barrier.html +[`sync::TaskPool`]: sync/struct.TaskPool.html +[`sync::Future`]: sync/struct.Future.html +[`sync::one`]: sync/one/index.html +[`sync::mutex`]: sync/mutex/index.html # Basics @@ -254,21 +279,25 @@ let result = ports.iter().fold(0, |accum, port| accum + port.recv() ); ~~~ ## Backgrounding computations: Futures -With `extra::future`, rust has a mechanism for requesting a computation and getting the result +With `sync::Future`, rust has a mechanism for requesting a computation and getting the result later. The basic example below illustrates this. ~~~ +# extern mod sync; + +# fn main() { # fn make_a_sandwich() {}; fn fib(n: u64) -> u64 { // lengthy computation returning an uint 12586269025 } -let mut delayed_fib = extra::future::Future::spawn(proc() fib(50)); +let mut delayed_fib = sync::Future::spawn(proc() fib(50)); make_a_sandwich(); println!("fib(50) = {:?}", delayed_fib.get()) +# } ~~~ The call to `future::spawn` returns immediately a `future` object regardless of how long it @@ -281,6 +310,7 @@ Here is another example showing how futures allow you to background computations be distributed on the available cores. ~~~ +# extern mod sync; # use std::vec; fn partial_sum(start: uint) -> f64 { let mut local_sum = 0f64; @@ -291,7 +321,7 @@ fn partial_sum(start: uint) -> f64 { } fn main() { - let mut futures = vec::from_fn(1000, |ind| extra::future::Future::spawn( proc() { partial_sum(ind) })); + let mut futures = vec::from_fn(1000, |ind| sync::Future::spawn( proc() { partial_sum(ind) })); let mut final_res = 0f64; for ft in futures.mut_iter() { @@ -309,16 +339,17 @@ add up to a significant amount of wasted memory and would require copying the sa necessary. To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in -the `extra` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc +the `sync` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc acts as a reference to the shared data and only this reference is shared and cloned. Here is a small example showing how to use Arcs. We wish to run concurrently several computations on a single large vector of floats. Each task needs the full vector to perform its duty. ~~~ +# extern mod sync; # use std::vec; # use std::rand; -use extra::arc::Arc; +use sync::Arc; fn pnorm(nums: &~[f64], p: uint) -> f64 { nums.iter().fold(0.0, |a,b| a+(*b).powf(&(p as f64)) ).powf(&(1.0 / (p as f64))) @@ -348,23 +379,29 @@ at the power given as argument and takes the inverse power of this value). The A created by the line ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers = vec::from_fn(1000000, |_| rand::random::()); let numbers_arc=Arc::new(numbers); +# } ~~~ and a clone of it is sent to each task ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers=vec::from_fn(1000000, |_| rand::random::()); # let numbers_arc = Arc::new(numbers); # let (port, chan) = Chan::new(); chan.send(numbers_arc.clone()); +# } ~~~ copying only the wrapper and not its contents. @@ -372,15 +409,18 @@ copying only the wrapper and not its contents. Each task recovers the underlying data by ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers=vec::from_fn(1000000, |_| rand::random::()); # let numbers_arc=Arc::new(numbers); # let (port, chan) = Chan::new(); # chan.send(numbers_arc.clone()); # let local_arc : Arc<~[f64]> = port.recv(); let task_numbers = local_arc.get(); +# } ~~~ and can use it as if it were local. @@ -450,7 +490,7 @@ proceed). A very common thing to do is to spawn a child task where the parent and child both need to exchange messages with each other. The -function `extra::comm::DuplexStream()` supports this pattern. We'll +function `sync::comm::DuplexStream()` supports this pattern. We'll look briefly at how to use it. To see how `DuplexStream()` works, we will create a child task @@ -458,17 +498,19 @@ that repeatedly receives a `uint` message, converts it to a string, and sends the string in response. The child terminates when it receives `0`. Here is the function that implements the child task: -~~~{.ignore .linked-failure} -# use extra::comm::DuplexStream; -# use std::uint; -fn stringifier(channel: &DuplexStream<~str, uint>) { - let mut value: uint; - loop { - value = channel.recv(); - channel.send(uint::to_str(value)); - if value == 0 { break; } +~~~ +# extern mod sync; +# fn main() { +# use sync::DuplexStream; + fn stringifier(channel: &DuplexStream<~str, uint>) { + let mut value: uint; + loop { + value = channel.recv(); + channel.send(value.to_str()); + if value == 0 { break; } + } } -} +# } ~~~~ The implementation of `DuplexStream` supports both sending and @@ -481,15 +523,15 @@ response itself is simply the stringified version of the received value, Here is the code for the parent task: -~~~{.ignore .linked-failure} +~~~ +# extern mod sync; # use std::task::spawn; -# use std::uint; -# use extra::comm::DuplexStream; +# use sync::DuplexStream; # fn stringifier(channel: &DuplexStream<~str, uint>) { # let mut value: uint; # loop { # value = channel.recv(); -# channel.send(uint::to_str(value)); +# channel.send(value.to_str()); # if value == 0u { break; } # } # } diff --git a/src/doc/index.md b/src/doc/index.md index 9915d67bfcad3..5aa92c9fec4db 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -43,6 +43,7 @@ li {list-style-type: none; } * [The `semver` version collation library](semver/index.html) * [The `term` terminal-handling library](term/index.html) * [The UUID library](uuid/index.html) +* [The `sync` library for concurrency-enabled mechanisms and primitives](sync/index.html) # Tooling diff --git a/src/etc/licenseck.py b/src/etc/licenseck.py index afbf34d07535d..e214a40e3d134 100644 --- a/src/etc/licenseck.py +++ b/src/etc/licenseck.py @@ -41,7 +41,7 @@ "libstd/sync/mpsc_queue.rs", # BSD "libstd/sync/spsc_queue.rs", # BSD "libstd/sync/mpmc_bounded_queue.rs", # BSD - "libextra/sync/mpsc_intrusive.rs", # BSD + "libsync/sync/mpsc_intrusive.rs", # BSD ] def check_license(name, contents): diff --git a/src/libextra/lib.rs b/src/libextra/lib.rs index d198fd44450c4..401ece64a5dc2 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -34,17 +34,16 @@ Rust extras are part of the standard Rust distribution. #[deny(non_camel_case_types)]; #[deny(missing_doc)]; -// Utility modules +extern mod sync; -pub mod c_vec; +#[cfg(stage0)] +macro_rules! if_ok ( + ($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) }) +) -// Concurrency +// Utility modules -pub mod sync; -pub mod arc; -pub mod comm; -pub mod future; -pub mod task_pool; +pub mod c_vec; // Collections diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 4d8e7e50dcfd5..d16edb7aa1e79 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -13,7 +13,7 @@ use json; use json::ToJson; use serialize::{Encoder, Encodable, Decoder, Decodable}; -use arc::{Arc,RWArc}; +use sync::{Arc,RWArc}; use treemap::TreeMap; use std::str; use std::io; diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index e224a06818af1..aea9b65087dc6 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -331,7 +331,7 @@ pub mod write { } unsafe fn configure_llvm(sess: Session) { - use extra::sync::one::{Once, ONCE_INIT}; + use sync::one::{Once, ONCE_INIT}; static mut INIT: Once = ONCE_INIT; // Copy what clang does by turning on loop vectorization at O2 and diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 8e722fae13a36..d4a6c29752d16 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,6 +35,7 @@ extern mod extra; extern mod flate; extern mod arena; extern mod syntax; +extern mod sync; use back::link; use driver::session; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 1ebe4a03cfdd2..5b4a961761277 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2660,7 +2660,7 @@ pub fn trans_crate(sess: session::Session, output: &Path) -> CrateTranslation { // Before we touch LLVM, make sure that multithreading is enabled. unsafe { - use extra::sync::one::{Once, ONCE_INIT}; + use sync::one::{Once, ONCE_INIT}; static mut INIT: Once = ONCE_INIT; static mut POISONED: bool = false; INIT.doit(|| { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 65696528a6fa1..f01e420030f6d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -41,7 +41,7 @@ use std::io::{fs, File, BufferedWriter}; use std::str; use std::vec; -use extra::arc::Arc; +use sync::Arc; use extra::json::ToJson; use syntax::ast; use syntax::attr; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index fe989279e7147..bf096a7e49b46 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -18,6 +18,7 @@ extern mod syntax; extern mod rustc; extern mod extra; +extern mod sync; use std::local_data; use std::io; diff --git a/src/libextra/arc.rs b/src/libsync/arc.rs similarity index 99% rename from src/libextra/arc.rs rename to src/libsync/arc.rs index 7f8d64053d51c..0e53ecd416a7a 100644 --- a/src/libextra/arc.rs +++ b/src/libsync/arc.rs @@ -18,7 +18,7 @@ * With simple pipes, without Arc, a copy would have to be made for each task. * * ```rust - * use extra::arc::Arc; + * use sync::Arc; * use std::{rand, vec}; * * let numbers = vec::from_fn(100, |i| (i as f32) * rand::random()); @@ -38,7 +38,7 @@ * ``` */ -#[allow(missing_doc)]; +#[allow(missing_doc, dead_code)]; use sync; @@ -424,7 +424,7 @@ impl RWArc { * # Example * * ```rust - * use extra::arc::RWArc; + * use sync::RWArc; * * let arc = RWArc::new(1); * arc.write_downgrade(|mut write_token| { @@ -605,7 +605,7 @@ impl Clone for CowArc { #[cfg(test)] mod tests { - use arc::*; + use super::{Arc, RWArc, MutexArc, CowArc}; use std::task; diff --git a/src/libextra/comm.rs b/src/libsync/comm.rs similarity index 100% rename from src/libextra/comm.rs rename to src/libsync/comm.rs diff --git a/src/libextra/future.rs b/src/libsync/future.rs similarity index 99% rename from src/libextra/future.rs rename to src/libsync/future.rs index b9121290f33f4..479174d17afb0 100644 --- a/src/libextra/future.rs +++ b/src/libsync/future.rs @@ -15,7 +15,7 @@ * # Example * * ```rust - * use extra::future::Future; + * use sync::Future; * # fn fib(n: uint) -> uint {42}; * # fn make_a_sandwich() {}; * let mut delayed_fib = Future::spawn(proc() { fib(5000) }); diff --git a/src/libsync/lib.rs b/src/libsync/lib.rs new file mode 100644 index 0000000000000..de1b0f91d6dc5 --- /dev/null +++ b/src/libsync/lib.rs @@ -0,0 +1,31 @@ +// 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. + +/*! + * Concurrency-enabled mechanisms and primitives. + */ + +#[crate_id = "sync#0.10-pre"]; +#[crate_type = "rlib"]; +#[crate_type = "dylib"]; +#[license = "MIT/ASL2"]; + +pub use arc::{Arc, MutexArc, RWArc, RWWriteMode, RWReadMode, Condvar}; +pub use sync::{Mutex, RWLock, Condvar, Semaphore, RWLockWriteMode, + RWLockReadMode, Barrier, one, mutex}; +pub use comm::{DuplexStream, SyncChan, SyncPort, rendezvous}; +pub use task_pool::TaskPool; +pub use future::Future; + +mod arc; +mod sync; +mod comm; +mod task_pool; +mod future; diff --git a/src/libextra/sync/mod.rs b/src/libsync/sync/mod.rs similarity index 99% rename from src/libextra/sync/mod.rs rename to src/libsync/sync/mod.rs index 03bf1101f1f29..cfff31e08d4b3 100644 --- a/src/libextra/sync/mod.rs +++ b/src/libsync/sync/mod.rs @@ -588,7 +588,7 @@ impl RWLock { * # Example * * ```rust - * use extra::sync::RWLock; + * use sync::RWLock; * * let lock = RWLock::new(); * lock.write_downgrade(|mut write_token| { @@ -695,7 +695,7 @@ impl<'a> RWLockReadMode<'a> { /// of some computation. /// /// ```rust -/// use extra::sync::Barrier; +/// use sync::Barrier; /// /// let barrier = Barrier::new(10); /// for _ in range(0, 10) { @@ -759,7 +759,7 @@ impl Barrier { #[cfg(test)] mod tests { - use sync::*; + use sync::{Semaphore, Mutex, RWLock, Barrier, Condvar}; use std::cast; use std::result; diff --git a/src/libextra/sync/mpsc_intrusive.rs b/src/libsync/sync/mpsc_intrusive.rs similarity index 100% rename from src/libextra/sync/mpsc_intrusive.rs rename to src/libsync/sync/mpsc_intrusive.rs diff --git a/src/libextra/sync/mutex.rs b/src/libsync/sync/mutex.rs similarity index 99% rename from src/libextra/sync/mutex.rs rename to src/libsync/sync/mutex.rs index 7ea98c0741a29..f1a81d65c1da5 100644 --- a/src/libextra/sync/mutex.rs +++ b/src/libsync/sync/mutex.rs @@ -83,7 +83,7 @@ pub static NATIVE_BLOCKED: uint = 1 << 2; /// # Example /// /// ```rust -/// use extra::sync::mutex::Mutex; +/// use sync::mutex::Mutex; /// /// let mut m = Mutex::new(); /// let guard = m.lock(); @@ -113,7 +113,7 @@ enum Flavor { /// # Example /// /// ```rust -/// use extra::sync::mutex::{StaticMutex, MUTEX_INIT}; +/// use sync::mutex::{StaticMutex, MUTEX_INIT}; /// /// static mut LOCK: StaticMutex = MUTEX_INIT; /// diff --git a/src/libextra/sync/one.rs b/src/libsync/sync/one.rs similarity index 99% rename from src/libextra/sync/one.rs rename to src/libsync/sync/one.rs index 826955d93e8d3..93d818b704dc9 100644 --- a/src/libextra/sync/one.rs +++ b/src/libsync/sync/one.rs @@ -30,7 +30,7 @@ use sync::mutex::{StaticMutex, MUTEX_INIT}; /// # Example /// /// ```rust -/// use extra::sync::one::{Once, ONCE_INIT}; +/// use sync::one::{Once, ONCE_INIT}; /// /// static mut START: Once = ONCE_INIT; /// unsafe { diff --git a/src/libextra/task_pool.rs b/src/libsync/task_pool.rs similarity index 100% rename from src/libextra/task_pool.rs rename to src/libsync/task_pool.rs diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index b1b2300466a5e..4b505ec811762 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -16,15 +16,17 @@ // This also serves as a pipes test, because Arcs are implemented with pipes. extern mod extra; +extern mod sync; -use extra::arc; -use extra::future::Future; +use sync::Arc; +use sync::MutexArc; +use sync::Future; use extra::time; use std::os; use std::uint; // A poor man's pipe. -type pipe = arc::MutexArc<~[uint]>; +type pipe = MutexArc<~[uint]>; fn send(p: &pipe, msg: uint) { unsafe { @@ -46,7 +48,7 @@ fn recv(p: &pipe) -> uint { } fn init() -> (pipe,pipe) { - let m = arc::MutexArc::new(~[]); + let m = MutexArc::new(~[]); ((&m).clone(), m) } diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs index d7bd0f2f6bd3d..23b4f00b280da 100644 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ b/src/test/bench/msgsend-ring-rw-arcs.rs @@ -16,15 +16,16 @@ // This also serves as a pipes test, because Arcs are implemented with pipes. extern mod extra; +extern mod sync; -use extra::arc; -use extra::future::Future; +use sync::RWArc; +use sync::Future; use extra::time; use std::os; use std::uint; // A poor man's pipe. -type pipe = arc::RWArc<~[uint]>; +type pipe = RWArc<~[uint]>; fn send(p: &pipe, msg: uint) { p.write_cond(|state, cond| { @@ -42,7 +43,7 @@ fn recv(p: &pipe) -> uint { } fn init() -> (pipe,pipe) { - let x = arc::RWArc::new(~[]); + let x = RWArc::new(~[]); ((&x).clone(), x) } diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index da658e6d041f7..c0e22f207b8f9 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; +extern mod sync; extern mod arena; use std::iter::range_step; -use extra::future::Future; +use sync::Future; use arena::TypedArena; enum Tree<'a> { diff --git a/src/test/bench/shootout-spectralnorm.rs b/src/test/bench/shootout-spectralnorm.rs index d68ca4e0abbae..9de62aaf960e8 100644 --- a/src/test/bench/shootout-spectralnorm.rs +++ b/src/test/bench/shootout-spectralnorm.rs @@ -10,15 +10,15 @@ // xfail-test arcs no longer unwrap -extern mod extra; +extern mod sync; use std::from_str::FromStr; use std::iter::count; use std::num::min; use std::os; use std::vec::from_elem; -use extra::arc::Arc; -use extra::arc::RWArc; +use sync::Arc; +use sync::RWArc; fn A(i: uint, j: uint) -> f64 { ((i + j) * (i + j + 1) / 2 + i + 1) as f64 diff --git a/src/test/compile-fail/arc-cant-nest-rw-arc-3177.rs b/src/test/compile-fail/arc-cant-nest-rw-arc-3177.rs index 49412b3aafdea..5c55f10ab4f2a 100644 --- a/src/test/compile-fail/arc-cant-nest-rw-arc-3177.rs +++ b/src/test/compile-fail/arc-cant-nest-rw-arc-3177.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; -use extra::arc::RWArc; +extern mod sync; +use sync::RWArc; fn main() { let arc1 = RWArc::new(true); diff --git a/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs index c31a7bb244c72..c9cd132788225 100644 --- a/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-cond-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of return value does not outlive the function call -extern mod extra; -use extra::arc; +extern mod sync; +use sync::RWArc; fn main() { - let x = ~arc::RWArc::new(1); + let x = ~RWArc::new(1); let mut y = None; x.write_cond(|_one, cond| y = Some(cond)); y.unwrap().wait(); diff --git a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs index 716dfe2c8b5c5..dfdbd882acff6 100644 --- a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; -use extra::arc; +extern mod sync; +use sync::RWArc; fn main() { - let x = ~arc::RWArc::new(1); + let x = ~RWArc::new(1); let mut y = None; x.write_downgrade(|write_mode| { y = Some(x.downgrade(write_mode)); diff --git a/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs index 7c129ae0dcaad..4bb7653d23e5c 100644 --- a/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-state-shouldnt-escape.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; -use extra::arc; +extern mod sync; +use sync::RWArc; fn main() { - let x = ~arc::RWArc::new(1); + let x = ~RWArc::new(1); let mut y = None; //~ ERROR lifetime of variable does not enclose its declaration x.write(|one| y = Some(one)); *y.unwrap() = 2; diff --git a/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs index 674cd5708889c..1410308107e94 100644 --- a/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-cond-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of variable does not enclose its declaration -extern mod extra; -use extra::arc; +extern mod sync; +use sync::RWArc; fn main() { - let x = ~arc::RWArc::new(1); + let x = ~RWArc::new(1); let mut y = None; x.write_downgrade(|write_mode| { (&write_mode).write_cond(|_one, cond| { diff --git a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs index 213bf48a08750..68226d96a18ef 100644 --- a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of variable does not enclose its declaration -extern mod extra; -use extra::arc; +extern mod sync; +use sync::RWArc; fn main() { - let x = ~arc::RWArc::new(1); + let x = ~RWArc::new(1); let mut y = None; x.write_downgrade(|write_mode| y = Some(write_mode)); y.unwrap(); diff --git a/src/test/compile-fail/functional-struct-update-noncopyable.rs b/src/test/compile-fail/functional-struct-update-noncopyable.rs index 00945ea84693c..f2c9ba5822893 100644 --- a/src/test/compile-fail/functional-struct-update-noncopyable.rs +++ b/src/test/compile-fail/functional-struct-update-noncopyable.rs @@ -11,8 +11,8 @@ // issue 7327 // xfail-fast #7103 -extern mod extra; -use extra::arc::Arc; +extern mod sync; +use sync::Arc; struct A { y: Arc, x: Arc } diff --git a/src/test/compile-fail/future_not_copyable.rs b/src/test/compile-fail/future_not_copyable.rs index aef5d0f9b04a6..69a90275ec78b 100644 --- a/src/test/compile-fail/future_not_copyable.rs +++ b/src/test/compile-fail/future_not_copyable.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; +extern mod sync; -use extra::future::Future; +use sync::Future; fn main() { let f = Future::from_value(()); diff --git a/src/test/compile-fail/mutex-arc-nested.rs b/src/test/compile-fail/mutex-arc-nested.rs index 24a141c4799d5..cdfdd29410e76 100644 --- a/src/test/compile-fail/mutex-arc-nested.rs +++ b/src/test/compile-fail/mutex-arc-nested.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; +extern mod sync; use std::task; -use extra::arc::{MutexArc}; +use sync::MutexArc; fn test_mutex_arc_nested() { let arc = ~MutexArc::new(1); diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index 5ae38e69ec0e3..cc529abd6f94f 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -10,14 +10,14 @@ // error-pattern: use of moved value -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; use std::task; fn main() { let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let arc_v = arc::Arc::new(v); + let arc_v = Arc::new(v); task::spawn(proc() { let v = arc_v.get(); diff --git a/src/test/compile-fail/no-reuse-move-arc.rs b/src/test/compile-fail/no-reuse-move-arc.rs index c6c0ba41ab91a..204a0e1cdd4a0 100644 --- a/src/test/compile-fail/no-reuse-move-arc.rs +++ b/src/test/compile-fail/no-reuse-move-arc.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; use std::task; fn main() { let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let arc_v = arc::Arc::new(v); + let arc_v = Arc::new(v); task::spawn(proc() { let v = arc_v.get(); diff --git a/src/test/compile-fail/once-cant-call-twice-on-heap.rs b/src/test/compile-fail/once-cant-call-twice-on-heap.rs index 8d5e2229b2e5d..a7e4f8de43704 100644 --- a/src/test/compile-fail/once-cant-call-twice-on-heap.rs +++ b/src/test/compile-fail/once-cant-call-twice-on-heap.rs @@ -12,8 +12,8 @@ // This program would segfault if it were legal. #[feature(once_fns)]; -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; fn foo(blk: proc()) { blk(); @@ -21,7 +21,7 @@ fn foo(blk: proc()) { } fn main() { - let x = arc::Arc::new(true); + let x = Arc::new(true); foo(proc() { assert!(*x.get()); drop(x); diff --git a/src/test/compile-fail/once-cant-call-twice-on-stack.rs b/src/test/compile-fail/once-cant-call-twice-on-stack.rs index 71293555d499d..8b168dd67870e 100644 --- a/src/test/compile-fail/once-cant-call-twice-on-stack.rs +++ b/src/test/compile-fail/once-cant-call-twice-on-stack.rs @@ -12,8 +12,8 @@ // This program would segfault if it were legal. #[feature(once_fns)]; -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; fn foo(blk: once ||) { blk(); @@ -21,7 +21,7 @@ fn foo(blk: once ||) { } fn main() { - let x = arc::Arc::new(true); + let x = Arc::new(true); foo(|| { assert!(*x.get()); drop(x); diff --git a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs index 7206b9bdb88eb..4fa6b6af7949e 100644 --- a/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs +++ b/src/test/compile-fail/once-cant-move-out-of-non-once-on-stack.rs @@ -11,8 +11,8 @@ // Testing guarantees provided by once functions. // This program would segfault if it were legal. -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; fn foo(blk: ||) { blk(); @@ -20,7 +20,7 @@ fn foo(blk: ||) { } fn main() { - let x = arc::Arc::new(true); + let x = Arc::new(true); foo(|| { assert!(*x.get()); drop(x); //~ ERROR cannot move out of captured outer variable diff --git a/src/test/compile-fail/sync-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-cond-shouldnt-escape.rs index 4df08b28eb896..06b8ad6259b6b 100644 --- a/src/test/compile-fail/sync-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-cond-shouldnt-escape.rs @@ -9,8 +9,8 @@ // except according to those terms. // error-pattern: lifetime of variable does not enclose its declaration -extern mod extra; -use extra::sync; +extern mod sync; +use sync::Mutex; fn main() { let m = ~sync::Mutex::new(); diff --git a/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs index d59eaf62abf84..52466c122dd7f 100644 --- a/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-cond-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of method receiver does not outlive the method call -extern mod extra; -use extra::sync; +extern mod sync; +use sync::RWLock; fn main() { - let x = ~sync::RWLock::new(); + let x = ~RWLock::new(); let mut y = None; x.write_cond(|cond| { y = Some(cond); diff --git a/src/test/compile-fail/sync-rwlock-read-mode-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-read-mode-shouldnt-escape.rs index 0078841acb139..0201f9dd51cbf 100644 --- a/src/test/compile-fail/sync-rwlock-read-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-read-mode-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: cannot infer an appropriate lifetime -extern mod extra; -use extra::sync; +extern mod sync; +use sync::RWLock; fn main() { - let x = ~sync::RWLock::new(); + let x = ~RWLock::new(); let mut y = None; x.write_downgrade(|write_mode| { y = Some(x.downgrade(write_mode)); diff --git a/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs index cbe5181d46f24..71a9dd100c395 100644 --- a/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-write-mode-cond-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of variable does not enclose its declaration -extern mod extra; -use extra::sync; +extern mod sync; +use sync::RWLock; fn main() { - let x = ~sync::RWLock::new(); + let x = ~RWLock::new(); let mut y = None; x.write_downgrade(|write_mode| { (&write_mode).write_cond(|cond| { diff --git a/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs b/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs index 6e9216830750b..53966bf48a493 100644 --- a/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/sync-rwlock-write-mode-shouldnt-escape.rs @@ -9,10 +9,10 @@ // except according to those terms. // error-pattern: lifetime of variable does not enclose its declaration -extern mod extra; -use extra::sync; +extern mod sync; +use sync::RWLock; fn main() { - let x = ~sync::RWLock::new(); + let x = ~RWLock::new(); let mut y = None; x.write_downgrade(|write_mode| { y = Some(write_mode); diff --git a/src/test/run-fail/issue-2444.rs b/src/test/run-fail/issue-2444.rs index c1357988f7db5..16f54e929236a 100644 --- a/src/test/run-fail/issue-2444.rs +++ b/src/test/run-fail/issue-2444.rs @@ -10,10 +10,10 @@ // error-pattern:explicit failure -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; -enum e { e(arc::Arc) } +enum e { e(Arc) } fn foo() -> e {fail!();} diff --git a/src/test/run-pass/bind-by-move.rs b/src/test/run-pass/bind-by-move.rs index a7a4aa9885e6e..3a86357bdaad1 100644 --- a/src/test/run-pass/bind-by-move.rs +++ b/src/test/run-pass/bind-by-move.rs @@ -9,12 +9,12 @@ // except according to those terms. // xfail-fast -extern mod extra; -use extra::arc; -fn dispose(_x: arc::Arc) { } +extern mod sync; +use sync::Arc; +fn dispose(_x: Arc) { } pub fn main() { - let p = arc::Arc::new(true); + let p = Arc::new(true); let x = Some(p); match x { Some(z) => { dispose(z); }, diff --git a/src/test/run-pass/once-move-out-on-heap.rs b/src/test/run-pass/once-move-out-on-heap.rs index bc56712ee3bc1..0ccf7b8f8a3e1 100644 --- a/src/test/run-pass/once-move-out-on-heap.rs +++ b/src/test/run-pass/once-move-out-on-heap.rs @@ -13,15 +13,15 @@ // xfail-fast #[feature(once_fns)]; -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; fn foo(blk: proc()) { blk(); } pub fn main() { - let x = arc::Arc::new(true); + let x = Arc::new(true); foo(proc() { assert!(*x.get()); drop(x); diff --git a/src/test/run-pass/once-move-out-on-stack.rs b/src/test/run-pass/once-move-out-on-stack.rs index 07dd5175a0fae..e732d0c76a663 100644 --- a/src/test/run-pass/once-move-out-on-stack.rs +++ b/src/test/run-pass/once-move-out-on-stack.rs @@ -13,15 +13,15 @@ // xfail-fast #[feature(once_fns)]; -extern mod extra; -use extra::arc; +extern mod sync; +use sync::Arc; fn foo(blk: once ||) { blk(); } pub fn main() { - let x = arc::Arc::new(true); + let x = Arc::new(true); foo(|| { assert!(*x.get()); drop(x); diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 2bf18e1ae1d5f..454da6d2aaa07 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -15,9 +15,9 @@ // xfail-fast -extern mod extra; +extern mod sync; -use extra::arc; +use sync::Arc; use std::task; trait Pet { @@ -65,7 +65,7 @@ pub fn main() { let dogge1 = Dogge { bark_decibels: 100, tricks_known: 42, name: ~"alan_turing" }; let dogge2 = Dogge { bark_decibels: 55, tricks_known: 11, name: ~"albert_einstein" }; let fishe = Goldfyshe { swim_speed: 998, name: ~"alec_guinness" }; - let arc = arc::Arc::new(~[~catte as ~Pet:Freeze+Send, + let arc = Arc::new(~[~catte as ~Pet:Freeze+Send, ~dogge1 as ~Pet:Freeze+Send, ~fishe as ~Pet:Freeze+Send, ~dogge2 as ~Pet:Freeze+Send]); @@ -83,21 +83,21 @@ pub fn main() { p3.recv(); } -fn check_legs(arc: arc::Arc<~[~Pet:Freeze+Send]>) { +fn check_legs(arc: Arc<~[~Pet:Freeze+Send]>) { let mut legs = 0; for pet in arc.get().iter() { legs += pet.num_legs(); } assert!(legs == 12); } -fn check_names(arc: arc::Arc<~[~Pet:Freeze+Send]>) { +fn check_names(arc: Arc<~[~Pet:Freeze+Send]>) { for pet in arc.get().iter() { pet.name(|name| { assert!(name[0] == 'a' as u8 && name[1] == 'l' as u8); }) } } -fn check_pedigree(arc: arc::Arc<~[~Pet:Freeze+Send]>) { +fn check_pedigree(arc: Arc<~[~Pet:Freeze+Send]>) { for pet in arc.get().iter() { assert!(pet.of_good_pedigree()); } From 5b7c1fb415f2094b1ea5ac8a6fe1a22a622c1d85 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 5 Feb 2014 08:52:54 -0800 Subject: [PATCH 07/10] pull extra::{serialize, ebml} into a separate libserialize crate - `extra::json` didn't make the cut, because of `extra::json` required dep on `extra::TreeMap`. If/when `extra::TreeMap` moves out of `extra`, then `extra::json` could move into `serialize` - `libextra`, `libsyntax` and `librustc` depend on the newly created `libserialize` - The extensions to various `extra` types like `DList`, `RingBuf`, `TreeMap` and `TreeSet` for `Encodable`/`Decodable` were moved into the respective modules in `extra` - There is some trickery, evident in `src/libextra/lib.rs` where a stub of `extra::serialize` is set up (in `src/libextra/serialize.rs`) for use in the stage0 build, where the snapshot rustc is still making deriving for `Encodable` and `Decodable` point at extra. Big props to @huonw for help working out the re-export solution for this extra: inline extra::serialize stub fix stuff clobbered in rebase + don't reexport serialize::serialize no more globs in libserialize syntax: fix import of libserialize traits librustc: fix bad imports in encoder/decoder add serialize dep to librustdoc fix failing run-pass tests w/ serialize dep adjust uuid dep more rebase de-clobbering for libserialize fixing tests, pushing libextra dep into cfg(test) fix doc code in extra::json adjust index.md links to serialize and uuid library --- mk/crates.mk | 13 +- src/doc/index.md | 5 +- src/libextra/dlist.rs | 27 ++++ src/libextra/json.rs | 22 +-- src/libextra/lib.rs | 13 +- src/libextra/ringbuf.rs | 27 ++++ src/libextra/treemap.rs | 67 ++++++++++ src/librustc/lib.rs | 1 + src/librustc/metadata/csearch.rs | 2 +- src/librustc/metadata/decoder.rs | 6 +- src/librustc/metadata/encoder.rs | 4 +- src/librustc/middle/astencode.rs | 12 +- src/librustdoc/lib.rs | 3 +- src/{libextra => libserialize}/ebml.rs | 28 ++-- src/libserialize/lib.rs | 33 +++++ src/{libextra => libserialize}/serialize.rs | 125 +----------------- src/libsyntax/ast.rs | 5 +- src/libsyntax/codemap.rs | 2 +- src/libsyntax/ext/deriving/decodable.rs | 7 +- src/libsyntax/ext/deriving/encodable.rs | 6 +- src/libsyntax/ext/deriving/generic.rs | 2 +- src/libsyntax/lib.rs | 1 + src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/token.rs | 2 +- src/libuuid/lib.rs | 9 +- src/test/run-pass/auto-encode.rs | 2 +- .../run-pass/deriving-encodable-decodable.rs | 10 +- src/test/run-pass/deriving-global.rs | 2 +- src/test/run-pass/issue-4016.rs | 5 +- src/test/run-pass/issue-4036.rs | 9 +- 30 files changed, 259 insertions(+), 193 deletions(-) rename src/{libextra => libserialize}/ebml.rs (97%) create mode 100644 src/libserialize/lib.rs rename src/{libextra => libserialize}/serialize.rs (86%) diff --git a/mk/crates.mk b/mk/crates.mk index dd94d268becb5..ea573b9db8d21 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -49,25 +49,26 @@ # automatically generated for all stage/host/target combinations. ################################################################################ -TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid sync +TARGET_CRATES := std extra green rustuv native flate arena glob term semver uuid serialize sync HOST_CRATES := syntax rustc rustdoc CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_std := native:rustrt -DEPS_extra := std term sync +DEPS_extra := std serialize sync term DEPS_green := std DEPS_rustuv := std native:uv native:uv_support DEPS_native := std -DEPS_syntax := std extra term -DEPS_rustc := syntax native:rustllvm flate arena sync -DEPS_rustdoc := rustc native:sundown sync +DEPS_syntax := std extra term serialize +DEPS_rustc := syntax native:rustllvm flate arena serialize sync +DEPS_rustdoc := rustc native:sundown serialize sync DEPS_flate := std native:miniz DEPS_arena := std extra DEPS_glob := std +DEPS_serialize := std DEPS_term := std DEPS_semver := std -DEPS_uuid := std extra +DEPS_uuid := std serialize DEPS_sync := std TOOL_DEPS_compiletest := extra green rustuv diff --git a/src/doc/index.md b/src/doc/index.md index 5aa92c9fec4db..54b8b484693a9 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -41,9 +41,10 @@ li {list-style-type: none; } * [The `flate` compression library](flate/index.html) * [The `glob` file path matching library](glob/index.html) * [The `semver` version collation library](semver/index.html) -* [The `term` terminal-handling library](term/index.html) -* [The UUID library](uuid/index.html) +* [The `serialize` value encoding/decoding library](serialize/index.html) * [The `sync` library for concurrency-enabled mechanisms and primitives](sync/index.html) +* [The `term` terminal-handling library](term/index.html) +* [The `uuid` 128-bit universally unique identifier library](uuid/index.html) # Tooling diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs index ee80fa1c4c46e..88df73845d03d 100644 --- a/src/libextra/dlist.rs +++ b/src/libextra/dlist.rs @@ -30,6 +30,8 @@ use std::iter; use container::Deque; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + /// A doubly-linked list. pub struct DList { priv length: uint, @@ -628,6 +630,31 @@ impl Clone for DList { } } +impl< + S: Encoder, + T: Encodable +> Encodable for DList { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)); + } + }) + } +} + +impl> Decodable for DList { + fn decode(d: &mut D) -> DList { + let mut list = DList::new(); + d.read_seq(|d, len| { + for i in range(0u, len) { + list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + }); + list + } +} + #[cfg(test)] mod tests { use container::Deque; diff --git a/src/libextra/json.rs b/src/libextra/json.rs index ef8e0999521b8..8b082bf3056d6 100644 --- a/src/libextra/json.rs +++ b/src/libextra/json.rs @@ -51,17 +51,18 @@ A simple JSON document encoding a person, his/her age, address and phone numbers Rust provides a mechanism for low boilerplate encoding & decoding of values to and from JSON via the serialization API. -To be able to encode a piece of data, it must implement the `extra::serialize::Encodable` trait. -To be able to decode a piece of data, it must implement the `extra::serialize::Decodable` trait. +To be able to encode a piece of data, it must implement the `serialize::Encodable` trait. +To be able to decode a piece of data, it must implement the `serialize::Decodable` trait. The Rust compiler provides an annotation to automatically generate the code for these traits: `#[deriving(Decodable, Encodable)]` To encode using Encodable : ```rust +extern mod serialize; use extra::json; use std::io; -use extra::serialize::Encodable; +use serialize::Encodable; #[deriving(Encodable)] pub struct TestStruct { @@ -125,7 +126,8 @@ fn main() { To decode a json string using `Decodable` trait : ```rust -use extra::serialize::Decodable; +extern mod serialize; +use serialize::Decodable; #[deriving(Decodable)] pub struct MyStruct { @@ -150,8 +152,9 @@ Create a struct called TestStruct1 and serialize and deserialize it to and from using the serialization API, using the derived serialization code. ```rust +extern mod serialize; use extra::json; -use extra::serialize::{Encodable, Decodable}; +use serialize::{Encodable, Decodable}; #[deriving(Decodable, Encodable)] //generate Decodable, Encodable impl. pub struct TestStruct1 { @@ -181,9 +184,10 @@ This example use the ToJson impl to unserialize the json string. Example of `ToJson` trait implementation for TestStruct1. ```rust +extern mod serialize; use extra::json; use extra::json::ToJson; -use extra::serialize::{Encodable, Decodable}; +use serialize::{Encodable, Decodable}; use extra::treemap::TreeMap; #[deriving(Decodable, Encodable)] // generate Decodable, Encodable impl. @@ -312,7 +316,7 @@ impl<'a> Encoder<'a> { } /// Encode the specified struct into a json [u8] - pub fn buffer_encode>>(to_encode_object: &T) -> ~[u8] { + pub fn buffer_encode>>(to_encode_object: &T) -> ~[u8] { //Serialize the object in a string using a writer let mut m = MemWriter::new(); { @@ -323,7 +327,7 @@ impl<'a> Encoder<'a> { } /// Encode the specified struct into a json str - pub fn str_encode>>(to_encode_object: &T) -> ~str { + pub fn str_encode>>(to_encode_object: &T) -> ~str { let buff:~[u8] = Encoder::buffer_encode(to_encode_object); str::from_utf8_owned(buff).unwrap() } @@ -684,7 +688,7 @@ impl serialize::Encodable for Json { } } -impl Json{ +impl Json { /// Encodes a json value into a io::writer. Uses a single line. pub fn to_writer(&self, wr: &mut io::Writer) -> io::IoResult<()> { let mut encoder = Encoder::new(wr); diff --git a/src/libextra/lib.rs b/src/libextra/lib.rs index 401ece64a5dc2..37b4d3cc524be 100644 --- a/src/libextra/lib.rs +++ b/src/libextra/lib.rs @@ -35,6 +35,17 @@ Rust extras are part of the standard Rust distribution. #[deny(missing_doc)]; extern mod sync; +#[cfg(not(stage0))] +extern mod serialize; + +#[cfg(stage0)] +pub mod serialize { + #[allow(missing_doc)]; + // Temp re-export until after a snapshot + extern mod serialize = "serialize"; + pub use self::serialize::{Encoder, Decoder, Encodable, Decodable, + EncoderHelpers, DecoderHelpers}; +} #[cfg(stage0)] macro_rules! if_ok ( @@ -62,7 +73,6 @@ pub mod lru_cache; // And ... other stuff pub mod url; -pub mod ebml; pub mod getopts; pub mod json; pub mod tempfile; @@ -85,7 +95,6 @@ mod unicode; // Compiler support modules pub mod test; -pub mod serialize; // A curious inner-module that's not exported that contains the binding // 'extra' so that macro-expanded references to extra::serialize and such diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs index 4da35942935f1..17631f5bdff01 100644 --- a/src/libextra/ringbuf.rs +++ b/src/libextra/ringbuf.rs @@ -19,6 +19,8 @@ use std::iter::{Rev, RandomAccessIterator}; use container::Deque; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + static INITIAL_CAPACITY: uint = 8u; // 2^3 static MINIMUM_CAPACITY: uint = 2u; @@ -402,6 +404,31 @@ impl Extendable for RingBuf { } } +impl< + S: Encoder, + T: Encodable +> Encodable for RingBuf { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + for (i, e) in self.iter().enumerate() { + s.emit_seq_elt(i, |s| e.encode(s)); + } + }) + } +} + +impl> Decodable for RingBuf { + fn decode(d: &mut D) -> RingBuf { + let mut deque = RingBuf::new(); + d.read_seq(|d, len| { + for i in range(0u, len) { + deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + }); + deque + } +} + #[cfg(test)] mod tests { use container::Deque; diff --git a/src/libextra/treemap.rs b/src/libextra/treemap.rs index 6605ea00c4413..449e72dd0ec81 100644 --- a/src/libextra/treemap.rs +++ b/src/libextra/treemap.rs @@ -17,6 +17,8 @@ use std::iter::{Peekable}; use std::cmp::Ordering; use std::ptr; +use serialize::{Encodable, Decodable, Encoder, Decoder}; + // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where red (horizontal) nodes can only be added // as a right child. The time complexity is the same, and re-balancing @@ -1004,6 +1006,71 @@ impl Extendable for TreeSet { } } +impl< + E: Encoder, + K: Encodable + Eq + TotalOrd, + V: Encodable + Eq +> Encodable for TreeMap { + fn encode(&self, e: &mut E) { + e.emit_map(self.len(), |e| { + let mut i = 0; + for (key, val) in self.iter() { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + K: Decodable + Eq + TotalOrd, + V: Decodable + Eq +> Decodable for TreeMap { + fn decode(d: &mut D) -> TreeMap { + d.read_map(|d, len| { + let mut map = TreeMap::new(); + for i in range(0u, len) { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + }) + } +} + +impl< + S: Encoder, + T: Encodable + Eq + TotalOrd +> Encodable for TreeSet { + fn encode(&self, s: &mut S) { + s.emit_seq(self.len(), |s| { + let mut i = 0; + for e in self.iter() { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + }) + } +} + +impl< + D: Decoder, + T: Decodable + Eq + TotalOrd +> Decodable for TreeSet { + fn decode(d: &mut D) -> TreeSet { + d.read_seq(|d, len| { + let mut set = TreeSet::new(); + for i in range(0u, len) { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + }) + } +} + #[cfg(test)] mod test_treemap { diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d4a6c29752d16..52ddc8c810888 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -35,6 +35,7 @@ extern mod extra; extern mod flate; extern mod arena; extern mod syntax; +extern mod serialize; extern mod sync; use back::link; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 1a65b326bbdea..8a6ba824dcb27 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -18,8 +18,8 @@ use middle::ty; use middle::typeck; use std::vec; +use reader = serialize::ebml::reader; use std::rc::Rc; -use reader = extra::ebml::reader; use syntax::ast; use syntax::ast_map; use syntax::diagnostic::expect; diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 8ba98e84dfa50..d18017d00439b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -31,9 +31,9 @@ use std::io::extensions::u64_from_be_bytes; use std::option; use std::rc::Rc; use std::vec; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize::Decodable; +use serialize::ebml::reader; +use serialize::ebml; +use serialize::Decodable; use syntax::ast_map; use syntax::attr; use syntax::parse::token::{IdentInterner, special_idents}; diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index d56d211b713ee..ba33f57309f8e 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -22,7 +22,7 @@ use middle::ty; use middle::typeck; use middle; -use extra::serialize::Encodable; +use serialize::Encodable; use std::cast; use std::cell::{Cell, RefCell}; use std::hashmap::{HashMap, HashSet}; @@ -45,7 +45,7 @@ use syntax::parse::token; use syntax::visit::Visitor; use syntax::visit; use syntax; -use writer = extra::ebml::writer; +use writer = serialize::ebml::writer; // used by astencode: type abbrev_map = @RefCell>; diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 29ea3475d3441..8adbd37462b94 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -37,12 +37,12 @@ use std::cast; use std::io::Seek; use std::rc::Rc; -use extra::ebml::reader; -use extra::ebml; -use extra::serialize; -use extra::serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; -use extra::serialize::{Decoder, Decodable}; -use writer = extra::ebml::writer; +use serialize::ebml::reader; +use serialize::ebml; +use serialize; +use serialize::{Encoder, Encodable, EncoderHelpers, DecoderHelpers}; +use serialize::{Decoder, Decodable}; +use writer = serialize::ebml::writer; #[cfg(test)] use syntax::parse; #[cfg(test)] use syntax::print::pprust; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index bf096a7e49b46..7256e8923fa87 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -18,6 +18,7 @@ extern mod syntax; extern mod rustc; extern mod extra; +extern mod serialize; extern mod sync; use std::local_data; @@ -27,7 +28,7 @@ use std::str; use extra::getopts; use extra::getopts::groups; use extra::json; -use extra::serialize::{Decodable, Encodable}; +use serialize::{Decodable, Encodable}; use extra::time; pub mod clean; diff --git a/src/libextra/ebml.rs b/src/libserialize/ebml.rs similarity index 97% rename from src/libextra/ebml.rs rename to src/libserialize/ebml.rs index 1900313ab6c8e..9d1c099c6f0fb 100644 --- a/src/libextra/ebml.rs +++ b/src/libserialize/ebml.rs @@ -83,15 +83,19 @@ pub enum EbmlEncoderTag { pub mod reader { use std::char; - use super::*; - - use serialize; use std::cast::transmute; use std::int; use std::option::{None, Option, Some}; use std::io::extensions::u64_from_be_bytes; + use serialize; + + use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey, + EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8, + EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint, + EsOpaque, EsLabel, EbmlEncoderTag, Doc, TaggedDoc }; + // ebml reading pub struct Res { @@ -588,8 +592,6 @@ pub mod reader { } pub mod writer { - use super::*; - use std::cast; use std::clone::Clone; use std::io; @@ -597,6 +599,13 @@ pub mod writer { use std::io::MemWriter; use std::io::extensions::u64_to_be_bytes; + use super::{ EsVec, EsMap, EsEnum, EsVecLen, EsVecElt, EsMapLen, EsMapKey, + EsEnumVid, EsU64, EsU32, EsU16, EsU8, EsInt, EsI64, EsI32, EsI16, EsI8, + EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, EsEnumBody, EsUint, + EsOpaque, EsLabel, EbmlEncoderTag }; + + use serialize; + // ebml writing pub struct Encoder<'a> { // FIXME(#5665): this should take a trait object. Note that if you @@ -775,7 +784,7 @@ pub mod writer { } } - impl<'a> ::serialize::Encoder for Encoder<'a> { + impl<'a> serialize::Encoder for Encoder<'a> { fn emit_nil(&mut self) {} fn emit_uint(&mut self, v: uint) { @@ -952,8 +961,7 @@ pub mod writer { mod tests { use ebml::reader; use ebml::writer; - use serialize::Encodable; - use serialize; + use {Encodable, Decodable}; use std::io::MemWriter; use std::option::{None, Option, Some}; @@ -1017,7 +1025,7 @@ mod tests { } let ebml_doc = reader::Doc(wr.get_ref()); let mut deser = reader::Decoder(ebml_doc); - let v1 = serialize::Decodable::decode(&mut deser); + let v1 = Decodable::decode(&mut deser); debug!("v1 == {:?}", v1); assert_eq!(v, v1); } @@ -1031,7 +1039,7 @@ mod tests { #[cfg(test)] mod bench { use ebml::reader; - use test::BenchHarness; + use extra::test::BenchHarness; #[bench] pub fn vuint_at_A_aligned(bh: &mut BenchHarness) { diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs new file mode 100644 index 0000000000000..5f473b253697c --- /dev/null +++ b/src/libserialize/lib.rs @@ -0,0 +1,33 @@ +// Copyright 2012-2014 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. + +//! Support code for encoding and decoding types. + +/* +Core encoding and decoding interfaces. +*/ + +#[crate_id = "serialize#0.10-pre"]; +#[crate_type = "rlib"]; +#[crate_type = "dylib"]; +#[license = "MIT/ASL2"]; +#[allow(missing_doc)]; +#[forbid(non_camel_case_types)]; +#[feature(macro_rules,managed_boxes)]; + +// test harness access +#[cfg(test)] +extern mod extra; + +pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, + DecoderHelpers, EncoderHelpers}; + +mod serialize; +pub mod ebml; diff --git a/src/libextra/serialize.rs b/src/libserialize/serialize.rs similarity index 86% rename from src/libextra/serialize.rs rename to src/libserialize/serialize.rs index 9b1b1e0548e07..c4f0a7a1830f3 100644 --- a/src/libextra/serialize.rs +++ b/src/libserialize/serialize.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -14,18 +14,10 @@ Core encoding and decoding interfaces. */ -#[allow(missing_doc)]; -#[forbid(non_camel_case_types)]; - - use std::hashmap::{HashMap, HashSet}; use std::rc::Rc; use std::trie::{TrieMap, TrieSet}; use std::vec; -use ringbuf::RingBuf; -use container::Deque; -use dlist::DList; -use treemap::{TreeMap, TreeSet}; pub trait Encoder { // Primitive types: @@ -614,56 +606,6 @@ impl< } } -impl< - S: Encoder, - T: Encodable -> Encodable for DList { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)); - } - }) - } -} - -impl> Decodable for DList { - fn decode(d: &mut D) -> DList { - let mut list = DList::new(); - d.read_seq(|d, len| { - for i in range(0u, len) { - list.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - }); - list - } -} - -impl< - S: Encoder, - T: Encodable -> Encodable for RingBuf { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s)); - } - }) - } -} - -impl> Decodable for RingBuf { - fn decode(d: &mut D) -> RingBuf { - let mut deque = RingBuf::new(); - d.read_seq(|d, len| { - for i in range(0u, len) { - deque.push_back(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - }); - deque - } -} - impl< E: Encoder, K: Encodable + Hash + IterBytes + Eq, @@ -782,71 +724,6 @@ impl Decodable for TrieSet { } } -impl< - E: Encoder, - K: Encodable + Eq + TotalOrd, - V: Encodable + Eq -> Encodable for TreeMap { - fn encode(&self, e: &mut E) { - e.emit_map(self.len(), |e| { - let mut i = 0; - for (key, val) in self.iter() { - e.emit_map_elt_key(i, |e| key.encode(e)); - e.emit_map_elt_val(i, |e| val.encode(e)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - K: Decodable + Eq + TotalOrd, - V: Decodable + Eq -> Decodable for TreeMap { - fn decode(d: &mut D) -> TreeMap { - d.read_map(|d, len| { - let mut map = TreeMap::new(); - for i in range(0u, len) { - let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); - let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); - map.insert(key, val); - } - map - }) - } -} - -impl< - S: Encoder, - T: Encodable + Eq + TotalOrd -> Encodable for TreeSet { - fn encode(&self, s: &mut S) { - s.emit_seq(self.len(), |s| { - let mut i = 0; - for e in self.iter() { - s.emit_seq_elt(i, |s| e.encode(s)); - i += 1; - } - }) - } -} - -impl< - D: Decoder, - T: Decodable + Eq + TotalOrd -> Decodable for TreeSet { - fn decode(d: &mut D) -> TreeSet { - d.read_seq(|d, len| { - let mut set = TreeSet::new(); - for i in range(0u, len) { - set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); - } - set - }) - } -} - // ___________________________________________________________________________ // Helper routines // diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 228329cbda12a..abfd119acbb99 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -22,7 +22,7 @@ use std::hashmap::HashMap; use std::option::Option; use std::rc::Rc; use std::to_str::ToStr; -use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; /// A pointer abstraction. FIXME(eddyb) #10676 use Rc in the future. pub type P = @T; @@ -1204,6 +1204,7 @@ pub enum InlinedItem { #[cfg(test)] mod test { + use serialize; use extra; use codemap::*; use super::*; @@ -1230,6 +1231,6 @@ mod test { }, }; // doesn't matter which encoder we use.... - let _f = (@e as @extra::serialize::Encodable); + let _f = (@e as @serialize::Encodable); } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 2ada3ac16ea66..a6c1a373d887f 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -23,7 +23,7 @@ source code snippets, etc. use std::cell::RefCell; use std::cmp; -use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; +use serialize::{Encodable, Decodable, Encoder, Decoder}; pub trait Pos { fn from_uint(n: uint) -> Self; diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 019a4dfe7cca4..ad7b3a2e950ae 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -28,12 +28,12 @@ pub fn expand_deriving_decodable(cx: &ExtCtxt, let trait_def = TraitDef { cx: cx, span: span, - path: Path::new_(~["extra", "serialize", "Decodable"], None, + path: Path::new_(~["serialize", "Decodable"], None, ~[~Literal(Path::new_local("__D"))], true), additional_bounds: ~[], generics: LifetimeBounds { lifetimes: ~[], - bounds: ~[("__D", ~[Path::new(~["extra", "serialize", "Decoder"])])], + bounds: ~[("__D", ~[Path::new(~["serialize", "Decoder"])])], }, methods: ~[ MethodDef { @@ -56,8 +56,7 @@ pub fn expand_deriving_decodable(cx: &ExtCtxt, fn decodable_substructure(cx: &ExtCtxt, trait_span: Span, substr: &Substructure) -> @Expr { let decoder = substr.nonself_args[0]; - let recurse = ~[cx.ident_of("extra"), - cx.ident_of("serialize"), + let recurse = ~[cx.ident_of("serialize"), cx.ident_of("Decodable"), cx.ident_of("decode")]; // throw an underscore in front to suppress unused variable warnings diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index c50c9f18389c2..66b744ecbcb4a 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -22,7 +22,7 @@ For example, a type like: would generate two implementations like: -impl Encodable for Node { +impl Encodable for Node { fn encode(&self, s: &S) { s.emit_struct("Node", 1, || { s.emit_field("id", 0, || s.emit_uint(self.id)) @@ -89,12 +89,12 @@ pub fn expand_deriving_encodable(cx: &ExtCtxt, let trait_def = TraitDef { cx: cx, span: span, - path: Path::new_(~["extra", "serialize", "Encodable"], None, + path: Path::new_(~["serialize", "Encodable"], None, ~[~Literal(Path::new_local("__E"))], true), additional_bounds: ~[], generics: LifetimeBounds { lifetimes: ~[], - bounds: ~[("__E", ~[Path::new(~["extra", "serialize", "Encoder"])])], + bounds: ~[("__E", ~[Path::new(~["serialize", "Encoder"])])], }, methods: ~[ MethodDef { diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 8eaff592765b2..992ee3175edd9 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -204,7 +204,7 @@ pub struct TraitDef<'a> { /// other than the current trait additional_bounds: ~[Ty<'a>], - /// Any extra lifetimes and/or bounds, e.g. `D: extra::serialize::Decoder` + /// Any extra lifetimes and/or bounds, e.g. `D: serialize::Decoder` generics: LifetimeBounds<'a>, methods: ~[MethodDef<'a>] diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index bcad19f21220c..3f305a4eb0e64 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ This API is completely unstable and subject to change. #[deny(non_camel_case_types)]; extern mod extra; +extern mod serialize; extern mod term; pub mod util { diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 328f0e7f22187..faebd97e7c270 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -284,7 +284,7 @@ pub fn maybe_aborted(result: T, mut p: Parser) -> T { #[cfg(test)] mod test { use super::*; - use extra::serialize::Encodable; + use serialize::Encodable; use extra; use std::io; use std::io::MemWriter; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index f1dd844fc7c68..090774ec76ff2 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -15,7 +15,7 @@ use parse::token; use util::interner::{RcStr, StrInterner}; use util::interner; -use extra::serialize::{Decodable, Decoder, Encodable, Encoder}; +use serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cast; use std::char; use std::fmt; diff --git a/src/libuuid/lib.rs b/src/libuuid/lib.rs index 60e69af324e1a..1951c52237f5f 100644 --- a/src/libuuid/lib.rs +++ b/src/libuuid/lib.rs @@ -59,7 +59,10 @@ Examples of string representations: #[crate_type = "dylib"]; #[license = "MIT/ASL2"]; +// test harness access +#[cfg(test)] extern mod extra; +extern mod serialize; use std::str; use std::vec; @@ -73,7 +76,7 @@ use std::cmp::Eq; use std::cast::{transmute,transmute_copy}; use std::to_bytes::{IterBytes, Cb}; -use extra::serialize::{Encoder, Encodable, Decoder, Decodable}; +use serialize::{Encoder, Encodable, Decoder, Decodable}; /// A 128-bit (16 byte) buffer containing the ID pub type UuidBytes = [u8, ..16]; @@ -784,8 +787,8 @@ mod test { #[test] fn test_serialize_round_trip() { - use extra::ebml; - use extra::serialize::{Encodable, Decodable}; + use serialize::ebml; + use serialize::{Encodable, Decodable}; let u = Uuid::new_v4(); let mut wr = MemWriter::new(); diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index f3af7d652cde4..027b329b17831 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -26,7 +26,7 @@ use EBWriter = extra::ebml::writer; use std::cmp::Eq; use std::cmp; use std::io; -use extra::serialize::{Decodable, Encodable}; +use serialize::{Decodable, Encodable}; use extra::time; fn test_ebml<'a, A: diff --git a/src/test/run-pass/deriving-encodable-decodable.rs b/src/test/run-pass/deriving-encodable-decodable.rs index 444790bcce99c..dedacd92535a5 100644 --- a/src/test/run-pass/deriving-encodable-decodable.rs +++ b/src/test/run-pass/deriving-encodable-decodable.rs @@ -16,14 +16,14 @@ #[feature(struct_variant, managed_boxes)]; -extern mod extra; +extern mod serialize; use std::io::MemWriter; use std::rand::{random, Rand}; -use extra::serialize::{Encodable, Decodable}; -use extra::ebml; -use extra::ebml::writer::Encoder; -use extra::ebml::reader::Decoder; +use serialize::{Encodable, Decodable}; +use serialize::ebml; +use serialize::ebml::writer::Encoder; +use serialize::ebml::reader::Decoder; #[deriving(Encodable, Decodable, Eq, Rand)] struct A; diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs index ce51e2dcd7059..a7a3784877c59 100644 --- a/src/test/run-pass/deriving-global.rs +++ b/src/test/run-pass/deriving-global.rs @@ -11,7 +11,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod extra; // {En,De}codable +extern mod serialize; // {En,De}codable mod submod { // if any of these are implemented without global calls for any // function calls, then being in a submodule will (correctly) diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index c1f40d302c865..87a52de2269d2 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -9,10 +9,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast + extern mod extra; +extern mod serialize; use extra::json; -use extra::serialize::Decodable; +use serialize::Decodable; trait JD : Decodable { } diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass/issue-4036.rs index 5665bff571e4c..b746e524d7f0c 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass/issue-4036.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-fast + // Issue #4036: Test for an issue that arose around fixing up type inference // byproducts in vtable records. extern mod extra; -use self::extra::json; -use self::extra::serialize; +extern mod serialize; +use extra::json; +use serialize::Decodable; pub fn main() { let json = json::from_str("[1]").unwrap(); let mut decoder = json::Decoder::new(json); - let _x: ~[int] = serialize::Decodable::decode(&mut decoder); + let _x: ~[int] = Decodable::decode(&mut decoder); } From 35c30a69a68eccadd16e3573603f57be92013a75 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 22 Jan 2014 19:32:16 -0800 Subject: [PATCH 08/10] Implement clone() for TCP/UDP/Unix sockets This is part of the overall strategy I would like to take when approaching issue #11165. The only two I/O objects that reasonably want to be "split" are the network stream objects. Everything else can be "split" by just creating another version. The initial idea I had was the literally split the object into a reader and a writer half, but that would just introduce lots of clutter with extra interfaces that were a little unnnecssary, or it would return a ~Reader and a ~Writer which means you couldn't access things like the remote peer name or local socket name. The solution I found to be nicer was to just clone the stream itself. The clone is just a clone of the handle, nothing fancy going on at the kernel level. Conceptually I found this very easy to wrap my head around (everything else supports clone()), and it solved the "split" problem at the same time. The cloning support is pretty specific per platform/lib combination: * native/win32 - uses some specific WSA apis to clone the SOCKET handle * native/unix - uses dup() to get another file descriptor * green/all - This is where things get interesting. When we support full clones of a handle, this implies that we're allowing simultaneous writes and reads to happen. It turns out that libuv doesn't support two simultaneous reads or writes of the same object. It does support *one* read and *one* write at the same time, however. Some extra infrastructure was added to just block concurrent writers/readers until the previous read/write operation was completed. I've added tests to the tcp/unix modules to make sure that this functionality is supported everywhere. --- src/libnative/io/file.rs | 47 +++++---- src/libnative/io/net.rs | 130 +++++++++++++++---------- src/librustuv/access.rs | 109 +++++++++++++++++++++ src/librustuv/homing.rs | 4 +- src/librustuv/lib.rs | 4 +- src/librustuv/net.rs | 62 ++++++++++-- src/librustuv/pipe.rs | 31 +++++- src/librustuv/rc.rs | 49 ++++++++++ src/libstd/io/net/tcp.rs | 181 ++++++++++++++++++++++++++++++++++- src/libstd/io/net/udp.rs | 117 ++++++++++++++++++++++ src/libstd/io/net/unix.rs | 96 +++++++++++++++++++ src/libstd/io/pipe.rs | 6 ++ src/libstd/libc.rs | 49 ++++++++++ src/libstd/option.rs | 1 - src/libstd/rt/rtio.rs | 4 + src/libstd/unstable/mutex.rs | 1 - src/libstd/util.rs | 1 - src/libstd/vec.rs | 2 +- 18 files changed, 812 insertions(+), 82 deletions(-) create mode 100644 src/librustuv/access.rs create mode 100644 src/librustuv/rc.rs diff --git a/src/libnative/io/file.rs b/src/libnative/io/file.rs index cc5b0770d4d20..25fb2809e764a 100644 --- a/src/libnative/io/file.rs +++ b/src/libnative/io/file.rs @@ -10,6 +10,7 @@ //! Blocking posix-based file I/O +use std::sync::arc::UnsafeArc; use std::c_str::CString; use std::io::IoError; use std::io; @@ -55,9 +56,13 @@ pub fn keep_going(data: &[u8], f: |*u8, uint| -> i64) -> i64 { pub type fd_t = libc::c_int; +struct Inner { + fd: fd_t, + close_on_drop: bool, +} + pub struct FileDesc { - priv fd: fd_t, - priv close_on_drop: bool, + priv inner: UnsafeArc } impl FileDesc { @@ -70,7 +75,10 @@ impl FileDesc { /// Note that all I/O operations done on this object will be *blocking*, but /// they do not require the runtime to be active. pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { fd: fd, close_on_drop: close_on_drop } + FileDesc { inner: UnsafeArc::new(Inner { + fd: fd, + close_on_drop: close_on_drop + }) } } // FIXME(#10465) these functions should not be public, but anything in @@ -80,7 +88,7 @@ impl FileDesc { #[cfg(windows)] type rlen = libc::c_uint; #[cfg(not(windows))] type rlen = libc::size_t; let ret = retry(|| unsafe { - libc::read(self.fd, + libc::read(self.fd(), buf.as_ptr() as *mut libc::c_void, buf.len() as rlen) as libc::c_int }); @@ -97,7 +105,7 @@ impl FileDesc { #[cfg(not(windows))] type wlen = libc::size_t; let ret = keep_going(buf, |buf, len| { unsafe { - libc::write(self.fd, buf as *libc::c_void, len as wlen) as i64 + libc::write(self.fd(), buf as *libc::c_void, len as wlen) as i64 } }); if ret < 0 { @@ -107,7 +115,11 @@ impl FileDesc { } } - pub fn fd(&self) -> fd_t { self.fd } + pub fn fd(&self) -> fd_t { + // This unsafety is fine because we're just reading off the file + // descriptor, no one is modifying this. + unsafe { (*self.inner.get()).fd } + } } impl io::Reader for FileDesc { @@ -130,7 +142,7 @@ impl rtio::RtioFileStream for FileDesc { self.inner_write(buf) } fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { - return os_pread(self.fd, buf.as_ptr(), buf.len(), offset); + return os_pread(self.fd(), buf.as_ptr(), buf.len(), offset); #[cfg(windows)] fn os_pread(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult { @@ -162,7 +174,7 @@ impl rtio::RtioFileStream for FileDesc { } } fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { - return os_pwrite(self.fd, buf.as_ptr(), buf.len(), offset); + return os_pwrite(self.fd(), buf.as_ptr(), buf.len(), offset); #[cfg(windows)] fn os_pwrite(fd: c_int, buf: *u8, amt: uint, offset: u64) -> IoResult<()> { @@ -197,7 +209,7 @@ impl rtio::RtioFileStream for FileDesc { io::SeekCur => libc::FILE_CURRENT, }; unsafe { - let handle = libc::get_osfhandle(self.fd) as libc::HANDLE; + let handle = libc::get_osfhandle(self.fd()) as libc::HANDLE; let mut newpos = 0; match libc::SetFilePointerEx(handle, pos, &mut newpos, whence) { 0 => Err(super::last_error()), @@ -212,7 +224,7 @@ impl rtio::RtioFileStream for FileDesc { io::SeekEnd => libc::SEEK_END, io::SeekCur => libc::SEEK_CUR, }; - let n = unsafe { libc::lseek(self.fd, pos as libc::off_t, whence) }; + let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; if n < 0 { Err(super::last_error()) } else { @@ -220,7 +232,7 @@ impl rtio::RtioFileStream for FileDesc { } } fn tell(&self) -> Result { - let n = unsafe { libc::lseek(self.fd, 0, libc::SEEK_CUR) }; + let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; if n < 0 { Err(super::last_error()) } else { @@ -228,7 +240,7 @@ impl rtio::RtioFileStream for FileDesc { } } fn fsync(&mut self) -> Result<(), IoError> { - return os_fsync(self.fd); + return os_fsync(self.fd()); #[cfg(windows)] fn os_fsync(fd: c_int) -> IoResult<()> { @@ -247,7 +259,7 @@ impl rtio::RtioFileStream for FileDesc { #[cfg(not(windows))] fn datasync(&mut self) -> Result<(), IoError> { - return super::mkerr_libc(os_datasync(self.fd)); + return super::mkerr_libc(os_datasync(self.fd())); #[cfg(target_os = "macos")] fn os_datasync(fd: c_int) -> c_int { @@ -270,7 +282,7 @@ impl rtio::RtioFileStream for FileDesc { Ok(_) => {}, Err(e) => return Err(e), }; let ret = unsafe { - let handle = libc::get_osfhandle(self.fd) as libc::HANDLE; + let handle = libc::get_osfhandle(self.fd()) as libc::HANDLE; match libc::SetEndOfFile(handle) { 0 => Err(super::last_error()), _ => Ok(()) @@ -282,7 +294,7 @@ impl rtio::RtioFileStream for FileDesc { #[cfg(unix)] fn truncate(&mut self, offset: i64) -> Result<(), IoError> { super::mkerr_libc(retry(|| unsafe { - libc::ftruncate(self.fd, offset as libc::off_t) + libc::ftruncate(self.fd(), offset as libc::off_t) })) } } @@ -294,6 +306,9 @@ impl rtio::RtioPipe for FileDesc { fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { self.inner_write(buf) } + fn clone(&self) -> ~rtio::RtioPipe { + ~FileDesc { inner: self.inner.clone() } as ~rtio::RtioPipe + } } impl rtio::RtioTTY for FileDesc { @@ -312,7 +327,7 @@ impl rtio::RtioTTY for FileDesc { fn isatty(&self) -> bool { false } } -impl Drop for FileDesc { +impl Drop for Inner { fn drop(&mut self) { // closing stdio file handles makes no sense, so never do it. Also, note // that errors are ignored when closing a file descriptor. The reason diff --git a/src/libnative/io/net.rs b/src/libnative/io/net.rs index dd916c8f3c4b9..32cd6337f993d 100644 --- a/src/libnative/io/net.rs +++ b/src/libnative/io/net.rs @@ -14,6 +14,7 @@ use std::io; use std::libc; use std::mem; use std::rt::rtio; +use std::sync::arc::UnsafeArc; use std::unstable::intrinsics; use super::{IoResult, retry}; @@ -108,10 +109,27 @@ fn setsockopt(fd: sock_t, opt: libc::c_int, val: libc::c_int, let ret = libc::setsockopt(fd, opt, val, payload, mem::size_of::() as libc::socklen_t); - super::mkerr_libc(ret) + if ret != 0 { + Err(last_error()) + } else { + Ok(()) + } } } +#[cfg(windows)] +fn last_error() -> io::IoError { + extern "system" { + fn WSAGetLastError() -> libc::c_int; + } + super::translate_error(unsafe { WSAGetLastError() }, true) +} + +#[cfg(not(windows))] +fn last_error() -> io::IoError { + super::last_error() +} + #[cfg(windows)] unsafe fn close(sock: sock_t) { let _ = libc::closesocket(sock); } #[cfg(unix)] unsafe fn close(sock: sock_t) { let _ = libc::close(sock); } @@ -128,7 +146,7 @@ fn sockname(fd: sock_t, storage as *mut libc::sockaddr, &mut len as *mut libc::socklen_t); if ret != 0 { - return Err(super::last_error()) + return Err(last_error()) } } return sockaddr_to_addr(&storage, len as uint); @@ -222,7 +240,11 @@ pub fn init() { //////////////////////////////////////////////////////////////////////////////// pub struct TcpStream { - priv fd: sock_t, + priv inner: UnsafeArc, +} + +struct Inner { + fd: sock_t, } impl TcpStream { @@ -231,27 +253,31 @@ impl TcpStream { socket(addr, libc::SOCK_STREAM).and_then(|fd| { let (addr, len) = addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; - let ret = TcpStream { fd: fd }; + let inner = Inner { fd: fd }; + let ret = TcpStream { inner: UnsafeArc::new(inner) }; match retry(|| { libc::connect(fd, addrp as *libc::sockaddr, len as libc::socklen_t) }) { - -1 => Err(super::last_error()), + -1 => Err(last_error()), _ => Ok(ret), } }) } } - pub fn fd(&self) -> sock_t { self.fd } + pub fn fd(&self) -> sock_t { + // This unsafety is fine because it's just a read-only arc + unsafe { (*self.inner.get()).fd } + } fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_TCP, libc::TCP_NODELAY, + setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as libc::c_int) } fn set_keepalive(&mut self, seconds: Option) -> IoResult<()> { - let ret = setsockopt(self.fd, libc::SOL_SOCKET, libc::SO_KEEPALIVE, + let ret = setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_KEEPALIVE, seconds.is_some() as libc::c_int); match seconds { Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)), @@ -261,12 +287,12 @@ impl TcpStream { #[cfg(target_os = "macos")] fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, + setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPALIVE, seconds as libc::c_int) } #[cfg(target_os = "freebsd")] fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, + setsockopt(self.fd(), libc::IPPROTO_TCP, libc::TCP_KEEPIDLE, seconds as libc::c_int) } #[cfg(not(target_os = "macos"), not(target_os = "freebsd"))] @@ -282,7 +308,7 @@ impl rtio::RtioTcpStream for TcpStream { fn read(&mut self, buf: &mut [u8]) -> IoResult { let ret = retry(|| { unsafe { - libc::recv(self.fd, + libc::recv(self.fd(), buf.as_ptr() as *mut libc::c_void, buf.len() as wrlen, 0) as libc::c_int @@ -291,7 +317,7 @@ impl rtio::RtioTcpStream for TcpStream { if ret == 0 { Err(io::standard_error(io::EndOfFile)) } else if ret < 0 { - Err(super::last_error()) + Err(last_error()) } else { Ok(ret as uint) } @@ -299,20 +325,20 @@ impl rtio::RtioTcpStream for TcpStream { fn write(&mut self, buf: &[u8]) -> IoResult<()> { let ret = keep_going(buf, |buf, len| { unsafe { - libc::send(self.fd, + libc::send(self.fd(), buf as *mut libc::c_void, len as wrlen, 0) as i64 } }); if ret < 0 { - Err(super::last_error()) + Err(last_error()) } else { Ok(()) } } fn peer_name(&mut self) -> IoResult { - sockname(self.fd, libc::getpeername) + sockname(self.fd(), libc::getpeername) } fn control_congestion(&mut self) -> IoResult<()> { self.set_nodelay(false) @@ -326,15 +352,19 @@ impl rtio::RtioTcpStream for TcpStream { fn letdie(&mut self) -> IoResult<()> { self.set_keepalive(None) } + + fn clone(&self) -> ~rtio::RtioTcpStream { + ~TcpStream { inner: self.inner.clone() } as ~rtio::RtioTcpStream + } } impl rtio::RtioSocket for TcpStream { fn socket_name(&mut self) -> IoResult { - sockname(self.fd, libc::getsockname) + sockname(self.fd(), libc::getsockname) } } -impl Drop for TcpStream { +impl Drop for Inner { fn drop(&mut self) { unsafe { close(self.fd); } } } @@ -343,7 +373,7 @@ impl Drop for TcpStream { //////////////////////////////////////////////////////////////////////////////// pub struct TcpListener { - priv fd: sock_t, + priv inner: UnsafeArc, } impl TcpListener { @@ -352,7 +382,8 @@ impl TcpListener { socket(addr, libc::SOCK_STREAM).and_then(|fd| { let (addr, len) = addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; - let ret = TcpListener { fd: fd }; + let inner = Inner { fd: fd }; + let ret = TcpListener { inner: UnsafeArc::new(inner) }; // On platforms with Berkeley-derived sockets, this allows // to quickly rebind a socket, without needing to wait for // the OS to clean up the previous one. @@ -366,18 +397,21 @@ impl TcpListener { } match libc::bind(fd, addrp as *libc::sockaddr, len as libc::socklen_t) { - -1 => Err(super::last_error()), + -1 => Err(last_error()), _ => Ok(ret), } }) } } - pub fn fd(&self) -> sock_t { self.fd } + pub fn fd(&self) -> sock_t { + // This is just a read-only arc so the unsafety is fine + unsafe { (*self.inner.get()).fd } + } pub fn native_listen(self, backlog: int) -> IoResult { - match unsafe { libc::listen(self.fd, backlog as libc::c_int) } { - -1 => Err(super::last_error()), + match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { + -1 => Err(last_error()), _ => Ok(TcpAcceptor { listener: self }) } } @@ -391,20 +425,16 @@ impl rtio::RtioTcpListener for TcpListener { impl rtio::RtioSocket for TcpListener { fn socket_name(&mut self) -> IoResult { - sockname(self.fd, libc::getsockname) + sockname(self.fd(), libc::getsockname) } } -impl Drop for TcpListener { - fn drop(&mut self) { unsafe { close(self.fd); } } -} - pub struct TcpAcceptor { priv listener: TcpListener, } impl TcpAcceptor { - pub fn fd(&self) -> sock_t { self.listener.fd } + pub fn fd(&self) -> sock_t { self.listener.fd() } pub fn native_accept(&mut self) -> IoResult { unsafe { @@ -417,8 +447,8 @@ impl TcpAcceptor { storagep as *mut libc::sockaddr, &mut size as *mut libc::socklen_t) as libc::c_int }) as sock_t { - -1 => Err(super::last_error()), - fd => Ok(TcpStream { fd: fd }) + -1 => Err(last_error()), + fd => Ok(TcpStream { inner: UnsafeArc::new(Inner { fd: fd })}) } } } @@ -444,7 +474,7 @@ impl rtio::RtioTcpAcceptor for TcpAcceptor { //////////////////////////////////////////////////////////////////////////////// pub struct UdpSocket { - priv fd: sock_t, + priv inner: UnsafeArc, } impl UdpSocket { @@ -453,25 +483,29 @@ impl UdpSocket { socket(addr, libc::SOCK_DGRAM).and_then(|fd| { let (addr, len) = addr_to_sockaddr(addr); let addrp = &addr as *libc::sockaddr_storage; - let ret = UdpSocket { fd: fd }; + let inner = Inner { fd: fd }; + let ret = UdpSocket { inner: UnsafeArc::new(inner) }; match libc::bind(fd, addrp as *libc::sockaddr, len as libc::socklen_t) { - -1 => Err(super::last_error()), + -1 => Err(last_error()), _ => Ok(ret), } }) } } - pub fn fd(&self) -> sock_t { self.fd } + pub fn fd(&self) -> sock_t { + // unsafety is fine because it's just a read-only arc + unsafe { (*self.inner.get()).fd } + } pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> { - setsockopt(self.fd, libc::SOL_SOCKET, libc::SO_BROADCAST, + setsockopt(self.fd(), libc::SOL_SOCKET, libc::SO_BROADCAST, on as libc::c_int) } pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, + setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_LOOP, on as libc::c_int) } @@ -484,14 +518,14 @@ impl UdpSocket { // interface == INADDR_ANY imr_interface: libc::in_addr { s_addr: 0x0 }, }; - setsockopt(self.fd, libc::IPPROTO_IP, opt, mreq) + setsockopt(self.fd(), libc::IPPROTO_IP, opt, mreq) } In6Addr(addr) => { let mreq = libc::ip6_mreq { ipv6mr_multiaddr: addr, ipv6mr_interface: 0, }; - setsockopt(self.fd, libc::IPPROTO_IPV6, opt, mreq) + setsockopt(self.fd(), libc::IPPROTO_IPV6, opt, mreq) } } } @@ -514,14 +548,14 @@ impl rtio::RtioUdpSocket for UdpSocket { let mut addrlen: libc::socklen_t = mem::size_of::() as libc::socklen_t; let ret = retry(|| { - libc::recvfrom(self.fd, + libc::recvfrom(self.fd(), buf.as_ptr() as *mut libc::c_void, buf.len() as msglen_t, 0, storagep as *mut libc::sockaddr, &mut addrlen) as libc::c_int }); - if ret < 0 { return Err(super::last_error()) } + if ret < 0 { return Err(last_error()) } sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| { Ok((ret as uint, addr)) }) @@ -532,7 +566,7 @@ impl rtio::RtioUdpSocket for UdpSocket { let dstp = &dst as *libc::sockaddr_storage; unsafe { let ret = retry(|| { - libc::sendto(self.fd, + libc::sendto(self.fd(), buf.as_ptr() as *libc::c_void, buf.len() as msglen_t, 0, @@ -540,7 +574,7 @@ impl rtio::RtioUdpSocket for UdpSocket { len as libc::socklen_t) as libc::c_int }); match ret { - -1 => Err(super::last_error()), + -1 => Err(last_error()), n if n as uint != buf.len() => { Err(io::IoError { kind: io::OtherIoError, @@ -582,11 +616,11 @@ impl rtio::RtioUdpSocket for UdpSocket { } fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, + setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_MULTICAST_TTL, ttl as libc::c_int) } fn time_to_live(&mut self, ttl: int) -> IoResult<()> { - setsockopt(self.fd, libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int) + setsockopt(self.fd(), libc::IPPROTO_IP, libc::IP_TTL, ttl as libc::c_int) } fn hear_broadcasts(&mut self) -> IoResult<()> { @@ -595,8 +629,8 @@ impl rtio::RtioUdpSocket for UdpSocket { fn ignore_broadcasts(&mut self) -> IoResult<()> { self.set_broadcast(false) } -} -impl Drop for UdpSocket { - fn drop(&mut self) { unsafe { close(self.fd) } } + fn clone(&self) -> ~rtio::RtioUdpSocket { + ~UdpSocket { inner: self.inner.clone() } as ~rtio::RtioUdpSocket + } } diff --git a/src/librustuv/access.rs b/src/librustuv/access.rs new file mode 100644 index 0000000000000..9d06593a6eafd --- /dev/null +++ b/src/librustuv/access.rs @@ -0,0 +1,109 @@ +// Copyright 2014 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 exclusive access primitive +/// +/// This primitive is used to gain exclusive access to read() and write() in uv. +/// It is assumed that all invocations of this struct happen on the same thread +/// (the uv event loop). + +use std::cast; +use std::sync::arc::UnsafeArc; +use std::rt::task::{BlockedTask, Task}; +use std::rt::local::Local; + +use homing::HomingMissile; + +pub struct Access { + priv inner: UnsafeArc, +} + +pub struct Guard<'a> { + priv access: &'a mut Access, + priv missile: Option, +} + +struct Inner { + queue: ~[BlockedTask], + held: bool, +} + +impl Access { + pub fn new() -> Access { + Access { + inner: UnsafeArc::new(Inner { + queue: ~[], + held: false, + }) + } + } + + pub fn grant<'a>(&'a mut self, missile: HomingMissile) -> Guard<'a> { + // This unsafety is actually OK because the homing missile argument + // guarantees that we're on the same event loop as all the other objects + // attempting to get access granted. + let inner: &mut Inner = unsafe { cast::transmute(self.inner.get()) }; + + if inner.held { + let t: ~Task = Local::take(); + t.deschedule(1, |task| { + inner.queue.push(task); + Ok(()) + }); + assert!(inner.held); + } else { + inner.held = true; + } + + Guard { access: self, missile: Some(missile) } + } +} + +impl Clone for Access { + fn clone(&self) -> Access { + Access { inner: self.inner.clone() } + } +} + +#[unsafe_destructor] +impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { + // This guard's homing missile is still armed, so we're guaranteed to be + // on the same I/O event loop, so this unsafety should be ok. + assert!(self.missile.is_some()); + let inner: &mut Inner = unsafe { + cast::transmute(self.access.inner.get()) + }; + + match inner.queue.shift() { + // Here we have found a task that was waiting for access, and we + // current have the "access lock" we need to relinquish access to + // this sleeping task. + // + // To do so, we first drop out homing missile and we then reawaken + // the task. In reawakening the task, it will be immediately + // scheduled on this scheduler. Because we might be woken up on some + // other scheduler, we drop our homing missile before we reawaken + // the task. + Some(task) => { + drop(self.missile.take()); + let _ = task.wake().map(|t| t.reawaken()); + } + None => { inner.held = false; } + } + } +} + +impl Drop for Inner { + fn drop(&mut self) { + assert!(!self.held); + assert_eq!(self.queue.len(), 0); + } +} diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index a2f3457a9430c..25c929c995de7 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -125,8 +125,8 @@ pub trait HomingIO { /// After a homing operation has been completed, this will return the current /// task back to its appropriate home (if applicable). The field is used to /// assert that we are where we think we are. -struct HomingMissile { - io_home: uint, +pub struct HomingMissile { + priv io_home: uint, } impl HomingMissile { diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 39d6f851e1722..b463bb7fd733d 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -68,8 +68,10 @@ pub use self::tty::TtyWatcher; mod macros; -mod queue; +mod access; mod homing; +mod queue; +mod rc; /// The implementation of `rtio` for libuv pub mod uvio; diff --git a/src/librustuv/net.rs b/src/librustuv/net.rs index 5461fc6272d35..7660d2c4f2b3e 100644 --- a/src/librustuv/net.rs +++ b/src/librustuv/net.rs @@ -19,7 +19,9 @@ use std::rt::rtio; use std::rt::task::BlockedTask; use std::unstable::intrinsics; +use access::Access; use homing::{HomingIO, HomeHandle}; +use rc::Refcount; use stream::StreamWatcher; use super::{Loop, Request, UvError, Buf, status_to_io_result, uv_error_to_io_error, UvHandle, slice_to_uv_buf, @@ -152,6 +154,14 @@ pub struct TcpWatcher { handle: *uvll::uv_tcp_t, stream: StreamWatcher, home: HomeHandle, + priv refcount: Refcount, + + // libuv can't support concurrent reads and concurrent writes of the same + // stream object, so we use these access guards in order to arbitrate among + // multiple concurrent reads and writes. Note that libuv *can* read and + // write simultaneously, it just can't read and read simultaneously. + priv read_access: Access, + priv write_access: Access, } pub struct TcpListener { @@ -183,6 +193,9 @@ impl TcpWatcher { home: home, handle: handle, stream: StreamWatcher::new(handle), + refcount: Refcount::new(), + read_access: Access::new(), + write_access: Access::new(), } } @@ -238,12 +251,14 @@ impl rtio::RtioSocket for TcpWatcher { impl rtio::RtioTcpStream for TcpWatcher { fn read(&mut self, buf: &mut [u8]) -> Result { - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.read_access.grant(m); self.stream.read(buf).map_err(uv_error_to_io_error) } fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.write_access.grant(m); self.stream.write(buf).map_err(uv_error_to_io_error) } @@ -280,6 +295,17 @@ impl rtio::RtioTcpStream for TcpWatcher { uvll::uv_tcp_keepalive(self.handle, 0 as c_int, 0 as c_uint) }) } + + fn clone(&self) -> ~rtio::RtioTcpStream { + ~TcpWatcher { + handle: self.handle, + stream: StreamWatcher::new(self.handle), + home: self.home.clone(), + refcount: self.refcount.clone(), + write_access: self.write_access.clone(), + read_access: self.read_access.clone(), + } as ~rtio::RtioTcpStream + } } impl UvHandle for TcpWatcher { @@ -289,7 +315,9 @@ impl UvHandle for TcpWatcher { impl Drop for TcpWatcher { fn drop(&mut self) { let _m = self.fire_homing_missile(); - self.close(); + if self.refcount.decrement() { + self.close(); + } } } @@ -415,6 +443,11 @@ impl rtio::RtioTcpAcceptor for TcpAcceptor { pub struct UdpWatcher { handle: *uvll::uv_udp_t, home: HomeHandle, + + // See above for what these fields are + priv refcount: Refcount, + priv read_access: Access, + priv write_access: Access, } impl UdpWatcher { @@ -423,6 +456,9 @@ impl UdpWatcher { let udp = UdpWatcher { handle: unsafe { uvll::malloc_handle(uvll::UV_UDP) }, home: io.make_handle(), + refcount: Refcount::new(), + read_access: Access::new(), + write_access: Access::new(), }; assert_eq!(unsafe { uvll::uv_udp_init(io.uv_loop(), udp.handle) @@ -463,7 +499,8 @@ impl rtio::RtioUdpSocket for UdpWatcher { buf: Option, result: Option<(ssize_t, Option)>, } - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.read_access.grant(m); let a = match unsafe { uvll::uv_udp_recv_start(self.handle, alloc_cb, recv_cb) @@ -533,7 +570,8 @@ impl rtio::RtioUdpSocket for UdpWatcher { fn sendto(&mut self, buf: &[u8], dst: ip::SocketAddr) -> Result<(), IoError> { struct Ctx { task: Option, result: c_int } - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.write_access.grant(m); let mut req = Request::new(uvll::UV_UDP_SEND); let buf = slice_to_uv_buf(buf); @@ -636,13 +674,25 @@ impl rtio::RtioUdpSocket for UdpWatcher { 0 as c_int) }) } + + fn clone(&self) -> ~rtio::RtioUdpSocket { + ~UdpWatcher { + handle: self.handle, + home: self.home.clone(), + refcount: self.refcount.clone(), + write_access: self.write_access.clone(), + read_access: self.read_access.clone(), + } as ~rtio::RtioUdpSocket + } } impl Drop for UdpWatcher { fn drop(&mut self) { // Send ourselves home to close this handle (blocking while doing so). let _m = self.fire_homing_missile(); - self.close(); + if self.refcount.decrement() { + self.close(); + } } } diff --git a/src/librustuv/pipe.rs b/src/librustuv/pipe.rs index a021a13e2d98d..c312f112d28b4 100644 --- a/src/librustuv/pipe.rs +++ b/src/librustuv/pipe.rs @@ -14,7 +14,9 @@ use std::libc; use std::rt::rtio::{RtioPipe, RtioUnixListener, RtioUnixAcceptor}; use std::rt::task::BlockedTask; +use access::Access; use homing::{HomingIO, HomeHandle}; +use rc::Refcount; use stream::StreamWatcher; use super::{Loop, UvError, UvHandle, Request, uv_error_to_io_error, wait_until_woken_after, wakeup}; @@ -25,6 +27,11 @@ pub struct PipeWatcher { stream: StreamWatcher, home: HomeHandle, priv defused: bool, + priv refcount: Refcount, + + // see comments in TcpWatcher for why these exist + priv write_access: Access, + priv read_access: Access, } pub struct PipeListener { @@ -61,6 +68,9 @@ impl PipeWatcher { stream: StreamWatcher::new(handle), home: home, defused: false, + refcount: Refcount::new(), + read_access: Access::new(), + write_access: Access::new(), } } @@ -118,14 +128,27 @@ impl PipeWatcher { impl RtioPipe for PipeWatcher { fn read(&mut self, buf: &mut [u8]) -> Result { - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.read_access.grant(m); self.stream.read(buf).map_err(uv_error_to_io_error) } fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let _m = self.fire_homing_missile(); + let m = self.fire_homing_missile(); + let _g = self.write_access.grant(m); self.stream.write(buf).map_err(uv_error_to_io_error) } + + fn clone(&self) -> ~RtioPipe { + ~PipeWatcher { + stream: StreamWatcher::new(self.stream.handle), + defused: false, + home: self.home.clone(), + refcount: self.refcount.clone(), + read_access: self.read_access.clone(), + write_access: self.write_access.clone(), + } as ~RtioPipe + } } impl HomingIO for PipeWatcher { @@ -138,8 +161,8 @@ impl UvHandle for PipeWatcher { impl Drop for PipeWatcher { fn drop(&mut self) { - if !self.defused { - let _m = self.fire_homing_missile(); + let _m = self.fire_homing_missile(); + if !self.defused && self.refcount.decrement() { self.close(); } } diff --git a/src/librustuv/rc.rs b/src/librustuv/rc.rs new file mode 100644 index 0000000000000..f43cf72236109 --- /dev/null +++ b/src/librustuv/rc.rs @@ -0,0 +1,49 @@ +// Copyright 2014 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. + +/// Simple refcount structure for cloning handles +/// +/// This is meant to be an unintrusive solution to cloning handles in rustuv. +/// The handles themselves shouldn't be sharing memory because there are bits of +/// state in the rust objects which shouldn't be shared across multiple users of +/// the same underlying uv object, hence Rc is not used and this simple counter +/// should suffice. + +use std::sync::arc::UnsafeArc; + +pub struct Refcount { + priv rc: UnsafeArc, +} + +impl Refcount { + /// Creates a new refcount of 1 + pub fn new() -> Refcount { + Refcount { rc: UnsafeArc::new(1) } + } + + fn increment(&self) { + unsafe { *self.rc.get() += 1; } + } + + /// Returns whether the refcount just hit 0 or not + pub fn decrement(&self) -> bool { + unsafe { + *self.rc.get() -= 1; + *self.rc.get() == 0 + } + } +} + +impl Clone for Refcount { + fn clone(&self) -> Refcount { + self.increment(); + Refcount { rc: self.rc.clone() } + } +} diff --git a/src/libstd/io/net/tcp.rs b/src/libstd/io/net/tcp.rs index a0bdc193d980c..66ceb03082f4b 100644 --- a/src/libstd/io/net/tcp.rs +++ b/src/libstd/io/net/tcp.rs @@ -8,11 +8,42 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! TCP network connections +//! +//! This module contains the ability to open a TCP stream to a socket address, +//! as well as creating a socket server to accept incoming connections. The +//! destination and binding addresses can either be an IPv4 or IPv6 address. +//! +//! A TCP connection implements the `Reader` and `Writer` traits, while the TCP +//! listener (socket server) implements the `Listener` and `Acceptor` traits. + +#[deny(missing_doc)]; + +use clone::Clone; use io::net::ip::SocketAddr; -use io::{Reader, Writer, Listener, Acceptor, IoResult}; +use io::{Reader, Writer, Listener, Acceptor}; +use io::IoResult; use rt::rtio::{IoFactory, LocalIo, RtioSocket, RtioTcpListener}; use rt::rtio::{RtioTcpAcceptor, RtioTcpStream}; +/// A structure which represents a TCP stream between a local socket and a +/// remote socket. +/// +/// # Example +/// +/// ```rust +/// # #[allow(unused_must_use)]; +/// use std::io::net::tcp::TcpStream; +/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; +/// +/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 34254 }; +/// let mut stream = TcpStream::connect(addr); +/// +/// stream.write([1]); +/// let mut buf = [0]; +/// stream.read(buf); +/// drop(stream); // close the connection +/// ``` pub struct TcpStream { priv obj: ~RtioTcpStream } @@ -22,21 +53,40 @@ impl TcpStream { TcpStream { obj: s } } + /// Creates a TCP connection to a remote socket address. + /// + /// If no error is encountered, then `Ok(stream)` is returned. pub fn connect(addr: SocketAddr) -> IoResult { LocalIo::maybe_raise(|io| { io.tcp_connect(addr).map(TcpStream::new) }) } + /// Returns the socket address of the remote peer of this TCP connection. pub fn peer_name(&mut self) -> IoResult { self.obj.peer_name() } + /// Returns the socket address of the local half of this TCP connection. pub fn socket_name(&mut self) -> IoResult { self.obj.socket_name() } } +impl Clone for TcpStream { + /// Creates a new handle to this TCP stream, allowing for simultaneous reads + /// and writes of this connection. + /// + /// The underlying TCP stream will not be closed until all handles to the + /// stream have been deallocated. All handles will also follow the same + /// stream, but two concurrent reads will not receive the same data. + /// Instead, the first read will receive the first packet received, and the + /// second read will receive the second packet. + fn clone(&self) -> TcpStream { + TcpStream { obj: self.obj.clone() } + } +} + impl Reader for TcpStream { fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } } @@ -45,17 +95,56 @@ impl Writer for TcpStream { fn write(&mut self, buf: &[u8]) -> IoResult<()> { self.obj.write(buf) } } +/// A structure representing a socket server. This listener is used to create a +/// `TcpAcceptor` which can be used to accept sockets on a local port. +/// +/// # Example +/// +/// ```rust +/// # fn main() {} +/// # fn foo() { +/// # #[allow(unused_must_use, dead_code)]; +/// use std::io::net::tcp::TcpListener; +/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; +/// use std::io::{Acceptor, Listener}; +/// +/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 80 }; +/// let listener = TcpListener::bind(addr); +/// +/// // bind the listener to the specified address +/// let mut acceptor = listener.listen(); +/// +/// // accept connections and process them +/// # fn handle_client(_: T) {} +/// for stream in acceptor.incoming() { +/// spawn(proc() { +/// handle_client(stream); +/// }); +/// } +/// +/// // close the socket server +/// drop(acceptor); +/// # } +/// ``` pub struct TcpListener { priv obj: ~RtioTcpListener } impl TcpListener { + /// Creates a new `TcpListener` which will be bound to the specified local + /// socket address. This listener is not ready for accepting connections, + /// `listen` must be called on it before that's possible. + /// + /// Binding with a port number of 0 will request that the OS assigns a port + /// to this listener. The port allocated can be queried via the + /// `socket_name` function. pub fn bind(addr: SocketAddr) -> IoResult { LocalIo::maybe_raise(|io| { io.tcp_bind(addr).map(|l| TcpListener { obj: l }) }) } + /// Returns the local socket address of this listener. pub fn socket_name(&mut self) -> IoResult { self.obj.socket_name() } @@ -67,6 +156,9 @@ impl Listener for TcpListener { } } +/// The accepting half of a TCP socket server. This structure is created through +/// a `TcpListener`'s `listen` method, and this object can be used to accept new +/// `TcpStream` instances. pub struct TcpAcceptor { priv obj: ~RtioTcpAcceptor } @@ -573,4 +665,91 @@ mod test { } let _listener = TcpListener::bind(addr); }) + + iotest!(fn tcp_clone_smoke() { + let addr = next_test_ip4(); + let mut acceptor = TcpListener::bind(addr).listen(); + + spawn(proc() { + let mut s = TcpStream::connect(addr); + let mut buf = [0, 0]; + assert_eq!(s.read(buf), Ok(1)); + assert_eq!(buf[0], 1); + s.write([2]).unwrap(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p1, c1) = Chan::new(); + let (p2, c2) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + p1.recv(); + s2.write([1]).unwrap(); + c2.send(()); + }); + c1.send(()); + let mut buf = [0, 0]; + assert_eq!(s1.read(buf), Ok(1)); + p2.recv(); + }) + + iotest!(fn tcp_clone_two_read() { + let addr = next_test_ip6(); + let mut acceptor = TcpListener::bind(addr).listen(); + let (p, c) = SharedChan::new(); + let c2 = c.clone(); + + spawn(proc() { + let mut s = TcpStream::connect(addr); + s.write([1]).unwrap(); + p.recv(); + s.write([2]).unwrap(); + p.recv(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p, done) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + let mut buf = [0, 0]; + s2.read(buf).unwrap(); + c2.send(()); + done.send(()); + }); + let mut buf = [0, 0]; + s1.read(buf).unwrap(); + c.send(()); + + p.recv(); + }) + + iotest!(fn tcp_clone_two_write() { + let addr = next_test_ip4(); + let mut acceptor = TcpListener::bind(addr).listen(); + + spawn(proc() { + let mut s = TcpStream::connect(addr); + let mut buf = [0, 1]; + s.read(buf).unwrap(); + s.read(buf).unwrap(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p, done) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + s2.write([1]).unwrap(); + done.send(()); + }); + s1.write([2]).unwrap(); + + p.recv(); + }) } + diff --git a/src/libstd/io/net/udp.rs b/src/libstd/io/net/udp.rs index 0ef62648afcb7..3c02f56384792 100644 --- a/src/libstd/io/net/udp.rs +++ b/src/libstd/io/net/udp.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use clone::Clone; use result::{Ok, Err}; use io::net::ip::SocketAddr; use io::{Reader, Writer, IoResult}; @@ -41,6 +42,19 @@ impl UdpSocket { } } +impl Clone for UdpSocket { + /// Creates a new handle to this UDP socket, allowing for simultaneous reads + /// and writes of the socket. + /// + /// The underlying UDP socket will not be closed until all handles to the + /// socket have been deallocated. Two concurrent reads will not receive the + /// same data. Instead, the first read will receive the first packet + /// received, and the second read will receive the second packet. + fn clone(&self) -> UdpSocket { + UdpSocket { obj: self.obj.clone() } + } +} + pub struct UdpStream { priv socket: UdpSocket, priv connectedTo: SocketAddr @@ -250,4 +264,107 @@ mod test { iotest!(fn socket_name_ip6() { socket_name(next_test_ip6()); }) + + iotest!(fn udp_clone_smoke() { + let addr1 = next_test_ip4(); + let addr2 = next_test_ip4(); + let mut sock1 = UdpSocket::bind(addr1).unwrap(); + let sock2 = UdpSocket::bind(addr2).unwrap(); + + spawn(proc() { + let mut sock2 = sock2; + let mut buf = [0, 0]; + assert_eq!(sock2.recvfrom(buf), Ok((1, addr1))); + assert_eq!(buf[0], 1); + sock2.sendto([2], addr1).unwrap(); + }); + + let sock3 = sock1.clone(); + + let (p1, c1) = Chan::new(); + let (p2, c2) = Chan::new(); + spawn(proc() { + let mut sock3 = sock3; + p1.recv(); + sock3.sendto([1], addr2).unwrap(); + c2.send(()); + }); + c1.send(()); + let mut buf = [0, 0]; + assert_eq!(sock1.recvfrom(buf), Ok((1, addr2))); + p2.recv(); + }) + + iotest!(fn udp_clone_two_read() { + let addr1 = next_test_ip4(); + let addr2 = next_test_ip4(); + let mut sock1 = UdpSocket::bind(addr1).unwrap(); + let sock2 = UdpSocket::bind(addr2).unwrap(); + let (p, c) = SharedChan::new(); + let c2 = c.clone(); + + spawn(proc() { + let mut sock2 = sock2; + sock2.sendto([1], addr1).unwrap(); + p.recv(); + sock2.sendto([2], addr1).unwrap(); + p.recv(); + }); + + let sock3 = sock1.clone(); + + let (p, done) = Chan::new(); + spawn(proc() { + let mut sock3 = sock3; + let mut buf = [0, 0]; + sock3.recvfrom(buf).unwrap(); + c2.send(()); + done.send(()); + }); + let mut buf = [0, 0]; + sock1.recvfrom(buf).unwrap(); + c.send(()); + + p.recv(); + }) + + iotest!(fn udp_clone_two_write() { + let addr1 = next_test_ip4(); + let addr2 = next_test_ip4(); + let mut sock1 = UdpSocket::bind(addr1).unwrap(); + let sock2 = UdpSocket::bind(addr2).unwrap(); + + let (p, c) = SharedChan::new(); + + spawn(proc() { + let mut sock2 = sock2; + let mut buf = [0, 1]; + + for _ in p.iter() { + match sock2.recvfrom(buf) { + Ok(..) => {} + Err(e) => fail!("failed receive: {}", e), + } + } + }); + + let sock3 = sock1.clone(); + + let (p, done) = Chan::new(); + let c2 = c.clone(); + spawn(proc() { + let mut sock3 = sock3; + match sock3.sendto([1], addr2) { + Ok(..) => c2.send(()), + Err(..) => {} + } + done.send(()); + }); + match sock1.sendto([2], addr2) { + Ok(..) => c.send(()), + Err(..) => {} + } + + p.recv(); + }) } diff --git a/src/libstd/io/net/unix.rs b/src/libstd/io/net/unix.rs index ce95b987663f7..3c7db9c868618 100644 --- a/src/libstd/io/net/unix.rs +++ b/src/libstd/io/net/unix.rs @@ -25,6 +25,7 @@ instances as clients. use prelude::*; use c_str::ToCStr; +use clone::Clone; use rt::rtio::{IoFactory, LocalIo, RtioUnixListener}; use rt::rtio::{RtioUnixAcceptor, RtioPipe}; use io::pipe::PipeStream; @@ -62,6 +63,12 @@ impl UnixStream { } } +impl Clone for UnixStream { + fn clone(&self) -> UnixStream { + UnixStream { obj: self.obj.clone() } + } +} + impl Reader for UnixStream { fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } } @@ -228,4 +235,93 @@ mod tests { let _acceptor = UnixListener::bind(&path).listen(); assert!(path.exists()); } + + #[test] + fn unix_clone_smoke() { + let addr = next_test_unix(); + let mut acceptor = UnixListener::bind(&addr).listen(); + + spawn(proc() { + let mut s = UnixStream::connect(&addr); + let mut buf = [0, 0]; + assert_eq!(s.read(buf), Ok(1)); + assert_eq!(buf[0], 1); + s.write([2]).unwrap(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p1, c1) = Chan::new(); + let (p2, c2) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + p1.recv(); + s2.write([1]).unwrap(); + c2.send(()); + }); + c1.send(()); + let mut buf = [0, 0]; + assert_eq!(s1.read(buf), Ok(1)); + p2.recv(); + } + + #[test] + fn unix_clone_two_read() { + let addr = next_test_unix(); + let mut acceptor = UnixListener::bind(&addr).listen(); + let (p, c) = SharedChan::new(); + let c2 = c.clone(); + + spawn(proc() { + let mut s = UnixStream::connect(&addr); + s.write([1]).unwrap(); + p.recv(); + s.write([2]).unwrap(); + p.recv(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p, done) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + let mut buf = [0, 0]; + s2.read(buf).unwrap(); + c2.send(()); + done.send(()); + }); + let mut buf = [0, 0]; + s1.read(buf).unwrap(); + c.send(()); + + p.recv(); + } + + #[test] + fn unix_clone_two_write() { + let addr = next_test_unix(); + let mut acceptor = UnixListener::bind(&addr).listen(); + + spawn(proc() { + let mut s = UnixStream::connect(&addr); + let mut buf = [0, 1]; + s.read(buf).unwrap(); + s.read(buf).unwrap(); + }); + + let mut s1 = acceptor.accept().unwrap(); + let s2 = s1.clone(); + + let (p, done) = Chan::new(); + spawn(proc() { + let mut s2 = s2; + s2.write([1]).unwrap(); + done.send(()); + }); + s1.write([2]).unwrap(); + + p.recv(); + } } diff --git a/src/libstd/io/pipe.rs b/src/libstd/io/pipe.rs index ca85707149b92..83250bdae7361 100644 --- a/src/libstd/io/pipe.rs +++ b/src/libstd/io/pipe.rs @@ -51,6 +51,12 @@ impl PipeStream { } } +impl Clone for PipeStream { + fn clone(&self) -> PipeStream { + PipeStream { obj: self.obj.clone() } + } +} + impl Reader for PipeStream { fn read(&mut self, buf: &mut [u8]) -> IoResult { self.obj.read(buf) } } diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 11a7b5dd19171..057d618f44490 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -960,6 +960,8 @@ pub mod types { } pub mod extra { use ptr; + use libc::consts::os::extra::{MAX_PROTOCOL_CHAIN, + WSAPROTOCOL_LEN}; use libc::types::common::c95::c_void; use libc::types::os::arch::c95::{c_char, c_int, c_uint, size_t}; use libc::types::os::arch::c95::{c_long, c_ulong}; @@ -1106,6 +1108,47 @@ pub mod types { } pub type LPFILETIME = *mut FILETIME; + + pub struct GUID { + Data1: DWORD, + Data2: DWORD, + Data3: DWORD, + Data4: [BYTE, ..8], + } + + struct WSAPROTOCOLCHAIN { + ChainLen: c_int, + ChainEntries: [DWORD, ..MAX_PROTOCOL_CHAIN], + } + + pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN; + + pub struct WSAPROTOCOL_INFO { + dwServiceFlags1: DWORD, + dwServiceFlags2: DWORD, + dwServiceFlags3: DWORD, + dwServiceFlags4: DWORD, + dwProviderFlags: DWORD, + ProviderId: GUID, + dwCatalogEntryId: DWORD, + ProtocolChain: WSAPROTOCOLCHAIN, + iVersion: c_int, + iAddressFamily: c_int, + iMaxSockAddr: c_int, + iMinSockAddr: c_int, + iSocketType: c_int, + iProtocol: c_int, + iProtocolMaxOffset: c_int, + iNetworkByteOrder: c_int, + iSecurityScheme: c_int, + dwMessageSize: DWORD, + dwProviderReserved: DWORD, + szProtocol: [u8, ..WSAPROTOCOL_LEN+1], + } + + pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; + + pub type GROUP = c_uint; } } } @@ -1721,6 +1764,10 @@ pub mod consts { pub static FILE_BEGIN: DWORD = 0; pub static FILE_CURRENT: DWORD = 1; pub static FILE_END: DWORD = 2; + + pub static MAX_PROTOCOL_CHAIN: DWORD = 7; + pub static WSAPROTOCOL_LEN: DWORD = 255; + pub static INVALID_SOCKET: DWORD = !0; } pub mod sysconf { } @@ -4098,6 +4145,8 @@ pub mod funcs { lpFrequency: *mut LARGE_INTEGER) -> BOOL; pub fn QueryPerformanceCounter( lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL; + + pub fn GetCurrentProcessId() -> DWORD; } } diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 39b516aeb12a7..7bb29fdfacf65 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -480,7 +480,6 @@ mod tests { use iter::range; use str::StrSlice; - use util; use kinds::marker; use vec::ImmutableVector; diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 35b1e21df0677..8d02048d55cf0 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -203,6 +203,7 @@ pub trait RtioTcpStream : RtioSocket { fn nodelay(&mut self) -> Result<(), IoError>; fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError>; fn letdie(&mut self) -> Result<(), IoError>; + fn clone(&self) -> ~RtioTcpStream; } pub trait RtioSocket { @@ -224,6 +225,8 @@ pub trait RtioUdpSocket : RtioSocket { fn hear_broadcasts(&mut self) -> Result<(), IoError>; fn ignore_broadcasts(&mut self) -> Result<(), IoError>; + + fn clone(&self) -> ~RtioUdpSocket; } pub trait RtioTimer { @@ -253,6 +256,7 @@ pub trait RtioProcess { pub trait RtioPipe { fn read(&mut self, buf: &mut [u8]) -> Result; fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; + fn clone(&self) -> ~RtioPipe; } pub trait RtioUnixListener { diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs index 4804de756876f..82957cd93ceb8 100644 --- a/src/libstd/unstable/mutex.rs +++ b/src/libstd/unstable/mutex.rs @@ -380,7 +380,6 @@ mod test { use super::{Mutex, MUTEX_INIT}; use rt::thread::Thread; - use task; #[test] fn somke_lock() { diff --git a/src/libstd/util.rs b/src/libstd/util.rs index c075f9b4ba84f..715a10b9112f9 100644 --- a/src/libstd/util.rs +++ b/src/libstd/util.rs @@ -69,7 +69,6 @@ impl Void { mod tests { use super::*; use prelude::*; - use mem::size_of; #[test] fn identity_crisis() { diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 4a6a4d54ae3e4..d53c2dceba248 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -4253,7 +4253,7 @@ mod tests { let h = x.mut_last(); assert_eq!(*h.unwrap(), 5); - let mut y: &mut [int] = []; + let y: &mut [int] = []; assert!(y.mut_last().is_none()); } } From 1e41da3839c6d6ea31d31778cca1aaeabe0d417b Mon Sep 17 00:00:00 2001 From: chromatic Date: Sun, 2 Feb 2014 16:32:52 -0800 Subject: [PATCH 09/10] Removed prelude::* from libstd files. This replaces the imports from the prelude with the re-exported symbols. --- src/libstd/ascii.rs | 4 ++-- src/libstd/cell.rs | 5 ++++- src/libstd/condition.rs | 4 +++- src/libstd/local_data.rs | 4 +++- src/libstd/os.rs | 20 ++++++++++++++++---- src/libstd/reference.rs | 2 +- src/libstd/run.rs | 8 +++++++- src/libstd/trie.rs | 6 +++++- src/libstd/unit.rs | 3 ++- src/libstd/vec_ng.rs | 8 ++++++-- 10 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index 83aec9d0aa639..4a43a00c5f5a9 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -18,9 +18,9 @@ use str::OwnedStr; use container::Container; use cast; use iter::Iterator; -use vec::{ImmutableVector, MutableVector, Vector}; +use vec::{ImmutableVector,MutableVector,Vector}; use to_bytes::IterBytes; -use option::{Option, Some, None}; +use option::{Option,Some,None}; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. #[deriving(Clone, Eq, Ord, TotalOrd, TotalEq)] diff --git a/src/libstd/cell.rs b/src/libstd/cell.rs index e19b8ae712f9a..6fab74cbc2fc2 100644 --- a/src/libstd/cell.rs +++ b/src/libstd/cell.rs @@ -10,7 +10,10 @@ //! Types dealing with dynamic mutability -use prelude::*; +use clone::{Clone,DeepClone}; +use cmp::Eq; +use ops::Drop; +use option::{None,Option,Some}; use cast; use kinds::{marker, Pod}; diff --git a/src/libstd/condition.rs b/src/libstd/condition.rs index e0dc5c8b65d69..587b444d59d5c 100644 --- a/src/libstd/condition.rs +++ b/src/libstd/condition.rs @@ -73,7 +73,9 @@ along with comparing and contrasting it with other error handling strategies. */ use local_data; -use prelude::*; +use clone::Clone; +use ops::Drop; +use option::{None, Option, Some}; use unstable::raw::Closure; #[doc(hidden)] diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 719cf2450c505..5c3ca07f128c4 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -41,7 +41,9 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4])); // magic. use cast; -use prelude::*; +use option::{None,Option,Some}; +use vec::{ImmutableVector,MutableVector,OwnedVector}; +use iter::{Iterator}; use rt::task::{Task, LocalStorage}; use util::replace; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 541db01f1484f..35fa4593a641f 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -28,20 +28,30 @@ #[allow(missing_doc)]; -use clone::Clone; -use container::Container; #[cfg(target_os = "macos")] +#[cfg(windows)] use iter::range; + +use clone::Clone; +use container::Container; use libc; use libc::{c_char, c_void, c_int}; -use option::{Some, None}; +use option::{Some, None, Option}; use os; -use prelude::*; +use ops::Drop; +use result::{Err, Ok, Result}; use ptr; use str; +use str::{Str, StrSlice}; +use cmp::Equiv; use fmt; use unstable::finally::Finally; use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; +use path::{Path, GenericPath}; +use iter::Iterator; +use vec::{Vector, CloneableVector, ImmutableVector, MutableVector, OwnedVector}; +use ptr::RawPtr; +use c_str::ToCStr; /// Delegates to the libc close() function, returning the same return value. pub fn close(fd: int) -> int { @@ -396,6 +406,8 @@ pub fn self_exe_name() -> Option { #[cfg(windows)] fn load_self() -> Option<~[u8]> { + use str::OwnedStr; + unsafe { use os::win32::fill_utf16_buf_and_decode; fill_utf16_buf_and_decode(|buf, sz| { diff --git a/src/libstd/reference.rs b/src/libstd/reference.rs index 91f03f02892e3..7584d07ed6423 100644 --- a/src/libstd/reference.rs +++ b/src/libstd/reference.rs @@ -11,7 +11,7 @@ //! Utilities for references #[cfg(not(test))] -use prelude::*; +use cmp::{Eq,Ord,Ordering,TotalEq,TotalOrd}; // Equality for region pointers #[cfg(not(test))] diff --git a/src/libstd/run.rs b/src/libstd/run.rs index 04e42b3eedfc5..1b880bc43ee82 100644 --- a/src/libstd/run.rs +++ b/src/libstd/run.rs @@ -20,7 +20,13 @@ use io::process; use io; use libc::{pid_t, c_int}; use libc; -use prelude::*; +use option::{None,Option,Some}; +use task::spawn; +use path::{Path,GenericPath}; +use result::Ok; +use str::Str; +use vec::Vector; +use clone::Clone; /** * A value representing a child process. diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index ef0930fabf1cd..7530c5e338aad 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -10,12 +10,16 @@ //! Ordered containers with integer keys, implemented as radix tries (`TrieSet` and `TrieMap` types) -use prelude::*; +use option::{None,Option,Some}; +use container::{Container,Map,Mutable,MutableMap}; +use iter::{Extendable,FromIterator,Iterator}; use mem; use uint; use util::replace; use unstable::intrinsics::init; use vec; +use ptr::RawPtr; +use vec::{ImmutableVector,Items,MutableVector,MutItems,OwnedVector}; // FIXME: #5244: need to manually update the TrieNode constructor static SHIFT: uint = 4; diff --git a/src/libstd/unit.rs b/src/libstd/unit.rs index 786a7f42bb394..d62fcca63a49e 100644 --- a/src/libstd/unit.rs +++ b/src/libstd/unit.rs @@ -11,7 +11,8 @@ //! Functions for the unit type. #[cfg(not(test))] -use prelude::*; +use default::Default; +use cmp::{Eq,Equal,Ord,Ordering,TotalEq,TotalOrd}; #[cfg(not(test))] impl Eq for () { diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs index e503497d95dff..c49a7302e729d 100644 --- a/src/libstd/vec_ng.rs +++ b/src/libstd/vec_ng.rs @@ -11,12 +11,16 @@ // Migrate documentation over from `std::vec` when it is removed. #[doc(hidden)]; -use prelude::*; +use ops::Drop; +use option::{None, Option, Some}; +use clone::Clone; +use iter::{DoubleEndedIterator, Iterator}; +use num::CheckedMul; use container::Container; use mem::size_of; use cast::{forget, transmute}; use rt::global_heap::{malloc_raw, realloc_raw}; -use vec::Items; +use vec::{ImmutableVector, Items, MutableVector}; use unstable::raw::Slice; use ptr::{offset, read_ptr}; use libc::{free, c_void}; From 29e56cc592072ca736e03e325a9e4a356a4fed04 Mon Sep 17 00:00:00 2001 From: chromatic Date: Tue, 4 Feb 2014 13:48:25 -0800 Subject: [PATCH 10/10] Cleaned up a lint warning. --- src/libstd/result.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 846bba7533fed..81c337198ca75 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -20,6 +20,7 @@ use to_str::ToStr; /// `Result` is a type that represents either success (`Ok`) or failure (`Err`). #[deriving(Clone, DeepClone, Eq, Ord, TotalEq, TotalOrd, ToStr)] +#[deny(unused_must_use)] #[must_use] pub enum Result { /// Contains the success value