From 41771d3973343a4c627a4bd45f66c7b230bff1f8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 28 Nov 2014 17:21:19 +0100 Subject: [PATCH 01/65] keep factored out and early: bug fix to avoid hitting region resolution errors during regionck. --- src/librustc/middle/typeck/check/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d38c5bc0ca9cf..1869d2668a953 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -393,8 +393,8 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, decl, id, body, &inh); vtable::select_all_fcx_obligations_or_error(&fcx); - regionck::regionck_fn(&fcx, id, body); fcx.default_diverging_type_variables_to_nil(); + regionck::regionck_fn(&fcx, id, body); writeback::resolve_type_vars_in_fn(&fcx, decl, body); } _ => ccx.tcx.sess.impossible_case(body.span, From 315d181a2803c5e317a481fae9974c07692a4709 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:03:43 +0100 Subject: [PATCH 02/65] add debug output for region_inference, gather_loans, mem_categorization. --- src/librustc/middle/borrowck/gather_loans/lifetime.rs | 5 ++++- .../middle/borrowck/gather_loans/restrictions.rs | 2 ++ .../middle/typeck/infer/region_inference/mod.rs | 10 +++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 5b8cb0608b39c..6447b214bc6b5 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -96,6 +96,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { fn check_scope(&self, max_scope: ty::Region) -> R { //! Reports an error if `loan_region` is larger than `max_scope` + debug!("check_scope max_scope: {} self.loan_region: {}", + max_scope.repr(self.bccx.tcx), + self.loan_region.repr(self.bccx.tcx)); if !self.bccx.is_subregion_of(self.loan_region, max_scope) { Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) } else { @@ -103,7 +106,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - fn scope(&self, cmt: &mc::cmt) -> ty::Region { + fn scope(&self, cmt: &mc::cmt<'tcx>) -> ty::Region { //! Returns the maximal region scope for the which the //! lvalue `cmt` is guaranteed to be valid without any //! rooting etc, and presuming `cmt` is not mutated. diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 9b9a5e61393f8..64b8bb4f92ee3 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -105,6 +105,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { } mc::cat_deref(cmt_base, _, pk) => { + debug!("restrict cat_deref (cmt={}) pk: {}", + cmt.repr(self.bccx.tcx), pk); match pk { mc::OwnedPtr => { // R-Deref-Send-Pointer diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 6a447d467cfce..6f0d18431f8a0 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -1146,6 +1146,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { a_region: Region, b_region: Region) -> bool { + debug!("check_node a_region: {} b_region: {}", + a_region.repr(this.tcx), b_region.repr(this.tcx)); if !this.is_subregion_of(a_region, b_region) { debug!("Setting {} to ErrorValue: {} not subregion of {}", a_vid, @@ -1192,7 +1194,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { errors: &mut Vec>) { let mut reg_reg_dups = FnvHashSet::new(); - for verify in self.verifys.borrow().iter() { + for (i, verify) in self.verifys.borrow().iter().enumerate() { + debug!("collect_concrete_region_errors i: {}", i); match *verify { VerifyRegSubReg(ref origin, sub, sup) => { if self.is_subregion_of(sub, sup) { @@ -1385,8 +1388,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { lower_bounds.sort_by(|a, b| { free_regions_first(a, b) }); upper_bounds.sort_by(|a, b| { free_regions_first(a, b) }); - for lower_bound in lower_bounds.iter() { - for upper_bound in upper_bounds.iter() { + for (i, lower_bound) in lower_bounds.iter().enumerate() { + for (j, upper_bound) in upper_bounds.iter().enumerate() { + debug!("collect_error_for_expanding_node {}", (i,j)); if !self.is_subregion_of(lower_bound.region, upper_bound.region) { errors.push(SubSupConflict( From 7d599e1c2a753f382f9d7e0d49470ebe5cbc1eef Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 27 Oct 2014 12:55:16 +0100 Subject: [PATCH 03/65] Checkpoint pcwalton's dtor checker with `SafeDestructor` in enum `infer::SubregionOrigin`. Must rename breadcrumbs, or at least improve its documentation. --- src/librustc/middle/typeck/check/regionck.rs | 224 ++++++++++++++++++ .../middle/typeck/infer/error_reporting.rs | 22 ++ src/librustc/middle/typeck/infer/mod.rs | 5 + 3 files changed, 251 insertions(+) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 1e92dc573a954..d146119b28116 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -121,6 +121,7 @@ and report an error, and it just seems like more mess in the end.) use middle::def; use middle::mem_categorization as mc; use middle::region::CodeExtent; +use middle::subst; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty}; @@ -234,6 +235,9 @@ pub struct Rcx<'a, 'tcx: 'a> { // id of innermost fn or loop repeating_scope: ast::NodeId, + /// Breadcrumbs used by the destructor checker. + breadcrumbs: Vec>, + // Possible region links we will establish if an upvar // turns out to be unique/mutable maybe_links: MaybeLinkMap<'tcx> @@ -270,6 +274,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { Rcx { fcx: fcx, repeating_scope: initial_repeating_scope, region_param_pairs: Vec::new(), + breadcrumbs: Vec::new(), maybe_links: RefCell::new(FnvHashMap::new()) } } @@ -577,6 +582,10 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { type_of_node_must_outlive( rcx, infer::BindingTypeIsNotValidAtDecl(span), id, var_region); + + let var_scope = tcx.region_maps.var_scope(id); + let typ = rcx.resolve_node_type(id); + check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); }) } @@ -625,8 +634,26 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { */ _ => {} } + + // If necessary, constrain destructors in the unadjusted form of this + // expression. + let head_cmt = { + let mc = mc::MemCategorizationContext::new(rcx); + ignore_err!(mc.cat_expr_unadjusted(expr)) + }; + check_safety_of_rvalue_destructor_if_necessary(rcx, + head_cmt, + expr.span); } + // If necessary, constrain destructors in this expression. This will be + // the adjusted form if there is an adjustment. + let head_cmt = { + let mc = mc::MemCategorizationContext::new(rcx); + ignore_err!(mc.cat_expr(expr)) + }; + check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span); + match expr.node { ast::ExprCall(ref callee, ref args) => { if has_method_map { @@ -1258,6 +1285,45 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, minimum_lifetime, maximum_lifetime) } +fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, + typ: ty::Ty<'tcx>, + span: Span, + scope: CodeExtent) { + iterate_over_potentially_unsafe_regions_in_type( + rcx, + typ, + span, + scope, + false) +} + +fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, + cmt: mc::cmt<'tcx>, + span: Span) { + match cmt.cat { + mc::cat_rvalue(region) => { + match region { + ty::ReScope(rvalue_scope) => { + let typ = rcx.resolve_type(cmt.ty); + check_safety_of_destructor_if_necessary(rcx, + typ, + span, + rvalue_scope); + } + ty::ReStatic => {} + region => { + rcx.tcx() + .sess + .span_bug(span, + format!("unexpected rvalue region in rvalue \ + destructor safety checking: `{}`", + region.repr(rcx.tcx())).as_slice()); + } + } + } + _ => {} + } +} fn constrain_index<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, index_expr: &ast::Expr, @@ -2006,3 +2072,161 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, region, param_bounds); } + +fn constrain_region_for_destructor_safety(rcx: &mut Rcx, + region: ty::Region, + inner_scope: CodeExtent, + span: Span) { + // Ignore bound regions. + match region { + ty::ReEarlyBound(..) | ty::ReLateBound(..) => return, + ty::ReFunction | ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | + ty::ReInfer(_) | ty::ReEmpty => {} + } + + // Get the parent scope. + let parent_inner_region = + match rcx.fcx.tcx().region_maps.opt_encl_scope(inner_scope) { + Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), + None => ty::ReFunction, + }; + + rcx.fcx.mk_subr(infer::SafeDestructor(span), + parent_inner_region, + region); +} + +fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( + rcx: &mut Rcx<'a, 'tcx>, + typ: ty::Ty<'tcx>, + span: Span, + scope: CodeExtent, + reachable_by_destructor: bool) { + ty::maybe_walk_ty(typ, |typ| { + // Avoid recursing forever. + if !rcx.breadcrumbs.contains(&typ) { + rcx.breadcrumbs.push(typ); + + let keep_going = match typ.sty { + ty::ty_struct(structure_id, ref substitutions) => { + let reachable_by_destructor = + reachable_by_destructor || + ty::has_dtor(rcx.fcx.tcx(), structure_id); + + let fields = + ty::lookup_struct_fields(rcx.fcx.tcx(), + structure_id); + for field in fields.iter() { + let field_type = + ty::lookup_field_type(rcx.fcx.tcx(), + structure_id, + field.id, + substitutions); + iterate_over_potentially_unsafe_regions_in_type( + rcx, + field_type, + span, + scope, + reachable_by_destructor) + } + + false + } + ty::ty_enum(enumeration_id, ref substitutions) => { + let reachable_by_destructor = reachable_by_destructor || + ty::has_dtor(rcx.fcx.tcx(), enumeration_id); + + let all_variant_info = + ty::substd_enum_variants(rcx.fcx.tcx(), + enumeration_id, + substitutions); + for variant_info in all_variant_info.iter() { + for argument_type in variant_info.args.iter() { + iterate_over_potentially_unsafe_regions_in_type( + rcx, + *argument_type, + span, + scope, + reachable_by_destructor) + } + } + + false + } + ty::ty_rptr(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + // Don't recurse, since references do not own their + // contents. + false + } + ty::ty_unboxed_closure(..) => { + true + } + ty::ty_closure(ref closure_type) => { + match closure_type.store { + ty::RegionTraitStore(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + } + ty::UniqTraitStore => {} + } + // Don't recurse, since closures don't own the types + // appearing in their signature. + false + } + ty::ty_trait(ref trait_type) => { + if reachable_by_destructor { + match trait_type.principal.substs.regions { + subst::NonerasedRegions(ref regions) => { + for region in regions.iter() { + constrain_region_for_destructor_safety( + rcx, + *region, + scope, + span) + } + } + subst::ErasedRegions => {} + } + + // FIXME (pnkfelix): Added by pnkfelix, but + // need to double-check that this additional + // constraint is necessary. + constrain_region_for_destructor_safety( + rcx, + trait_type.bounds.region_bound, + scope, + span) + } + true + } + ty::ty_ptr(_) | ty::ty_bare_fn(_) => { + // Don't recurse, since pointers, boxes, and bare + // functions don't own instances of the types appearing + // within them. + false + } + ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | + ty::ty_float(_) | ty::ty_uniq(_) | ty::ty_str | + ty::ty_vec(..) | ty::ty_tup(_) | ty::ty_param(_) | + ty::ty_infer(_) | ty::ty_open(_) | ty::ty_err => true, + }; + + let top_t = rcx.breadcrumbs.pop(); + assert_eq!(top_t, Some(typ)); + keep_going + } else { + false + } + }); +} + diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index bc36a2bd801b4..345fe2533f5be 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -754,6 +754,22 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { sup, ""); } + infer::SafeDestructor(span) => { + self.tcx.sess.span_err( + span, + "unsafe use of destructor: destructor might be called \ + while references are dead"); + note_and_explain_region( + self.tcx, + "superregion: ", + sup, + ""); + note_and_explain_region( + self.tcx, + "subregion: ", + sub, + ""); + } infer::BindingTypeIsNotValidAtDecl(span) => { self.tcx.sess.span_err( span, @@ -1670,6 +1686,12 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> { format!("...so that the declared lifetime parameter bounds \ are satisfied").as_slice()); } + infer::SafeDestructor(span) => { + self.tcx.sess.span_note( + span, + "...so that references are valid when the destructor \ + runs") + } } } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 93c11693091c2..3439c0e28d447 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -225,6 +225,9 @@ pub enum SubregionOrigin<'tcx> { // An auto-borrow that does not enclose the expr where it occurs AutoBorrow(Span), + + // Region constraint arriving from destructor safety + SafeDestructor(Span), } /// Times when we replace late-bound regions with variables: @@ -1083,6 +1086,7 @@ impl<'tcx> SubregionOrigin<'tcx> { CallReturn(a) => a, AddrOf(a) => a, AutoBorrow(a) => a, + SafeDestructor(a) => a, } } } @@ -1154,6 +1158,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> { CallReturn(a) => format!("CallReturn({})", a.repr(tcx)), AddrOf(a) => format!("AddrOf({})", a.repr(tcx)), AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)), + SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)), } } } From 26a114424afe111c9f4f5571e9e102aaac2389b0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:04:24 +0100 Subject: [PATCH 04/65] add debug output to check_safey_of_destructor (just for drop-lts). --- src/librustc/middle/typeck/check/regionck.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index d146119b28116..2306ba0cb7230 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1289,12 +1289,15 @@ fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, typ: ty::Ty<'tcx>, span: Span, scope: CodeExtent) { + debug!("check_safety_of_destructor_if_necessary typ: {} scope: {}", + typ.repr(rcx.tcx()), scope); iterate_over_potentially_unsafe_regions_in_type( rcx, typ, span, scope, - false) + false, + 0) } fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, @@ -2101,12 +2104,18 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( typ: ty::Ty<'tcx>, span: Span, scope: CodeExtent, - reachable_by_destructor: bool) { + reachable_by_destructor: bool, + depth: uint) { ty::maybe_walk_ty(typ, |typ| { // Avoid recursing forever. if !rcx.breadcrumbs.contains(&typ) { rcx.breadcrumbs.push(typ); + debug!("iterate_over_potentially_unsafe_regions_in_type \ + {}typ: {} scope: {} reachable_by_destructor: {}", + String::from_char(depth, ' '), + typ.repr(rcx.tcx()), scope, reachable_by_destructor); + let keep_going = match typ.sty { ty::ty_struct(structure_id, ref substitutions) => { let reachable_by_destructor = @@ -2127,7 +2136,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( field_type, span, scope, - reachable_by_destructor) + reachable_by_destructor, depth+1) } false @@ -2147,7 +2156,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( *argument_type, span, scope, - reachable_by_destructor) + reachable_by_destructor, depth+1) } } From 8489d3dc98f50dd797c6d252c9be9a0cf9c4c0d1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 26 Nov 2014 16:09:23 +0100 Subject: [PATCH 05/65] factored drop-checking code out into dropck module. --- src/librustc/middle/typeck/check/dropck.rs | 189 ++++++++++++++++ src/librustc/middle/typeck/check/mod.rs | 1 + src/librustc/middle/typeck/check/regionck.rs | 222 +++---------------- 3 files changed, 226 insertions(+), 186 deletions(-) create mode 100644 src/librustc/middle/typeck/check/dropck.rs diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs new file mode 100644 index 0000000000000..b79fe2e0f547c --- /dev/null +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -0,0 +1,189 @@ +use middle::region; +use middle::subst; +use middle::ty; +use middle::typeck::check::regionck::{Rcx}; +use middle::typeck::infer; +use util::ppaux::{Repr}; + +use syntax::codemap::Span; + +pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, + typ: ty::Ty<'tcx>, + span: Span, + scope: region::CodeExtent) { + debug!("check_safety_of_destructor_if_necessary typ: {} scope: {}", + typ.repr(rcx.tcx()), scope); + iterate_over_potentially_unsafe_regions_in_type( + rcx, + typ, + span, + scope, + false, + 0) +} + +fn constrain_region_for_destructor_safety(rcx: &mut Rcx, + region: ty::Region, + inner_scope: region::CodeExtent, + span: Span) { + debug!("constrain_region_for_destructor_safety region: {} inner_scope: {}", + region, inner_scope); + + // Ignore bound regions. + match region { + ty::ReEarlyBound(..) | ty::ReLateBound(..) => return, + ty::ReFunction | ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | + ty::ReInfer(_) | ty::ReEmpty => {} + } + + // Get the parent scope. + let parent_inner_region = + match rcx.tcx().region_maps.opt_encl_scope(inner_scope) { + Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), + None => ty::ReFunction, + }; + + rcx.tcx().sess.span_note( + span, + format!("constrain_region_for_destructor_safety \ + region: {} sub/inner_scope: {} sup/parent_inner_region: {}", + region, inner_scope, parent_inner_region).as_slice()); + + rcx.mk_subr(infer::SafeDestructor(span), + parent_inner_region, + region); +} + +fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( + rcx: &mut Rcx<'a, 'tcx>, + typ: ty::Ty<'tcx>, + span: Span, + scope: region::CodeExtent, + reachable_by_destructor: bool, + depth: uint) { + ty::maybe_walk_ty(typ, |typ| { + // Avoid recursing forever. + rcx.traverse_type_if_unseen(typ, |rcx| { + debug!("iterate_over_potentially_unsafe_regions_in_type \ + {}typ: {} scope: {} reachable_by_destructor: {}", + String::from_char(depth, ' '), + typ.repr(rcx.tcx()), scope, reachable_by_destructor); + + let keep_going = match typ.sty { + ty::ty_struct(structure_id, ref substitutions) => { + let reachable_by_destructor = + reachable_by_destructor || + ty::has_dtor(rcx.tcx(), structure_id); + + let fields = + ty::lookup_struct_fields(rcx.tcx(), + structure_id); + for field in fields.iter() { + let field_type = + ty::lookup_field_type(rcx.tcx(), + structure_id, + field.id, + substitutions); + iterate_over_potentially_unsafe_regions_in_type( + rcx, + field_type, + span, + scope, + reachable_by_destructor, depth+1) + } + + false + } + ty::ty_enum(enumeration_id, ref substitutions) => { + let reachable_by_destructor = reachable_by_destructor || + ty::has_dtor(rcx.tcx(), enumeration_id); + + let all_variant_info = + ty::substd_enum_variants(rcx.tcx(), + enumeration_id, + substitutions); + for variant_info in all_variant_info.iter() { + for argument_type in variant_info.args.iter() { + iterate_over_potentially_unsafe_regions_in_type( + rcx, + *argument_type, + span, + scope, + reachable_by_destructor, depth+1) + } + } + + false + } + ty::ty_rptr(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + // Don't recurse, since references do not own their + // contents. + false + } + ty::ty_unboxed_closure(..) => { + true + } + ty::ty_closure(ref closure_type) => { + match closure_type.store { + ty::RegionTraitStore(region, _) => { + if reachable_by_destructor { + constrain_region_for_destructor_safety(rcx, + region, + scope, + span) + } + } + ty::UniqTraitStore => {} + } + // Don't recurse, since closures don't own the types + // appearing in their signature. + false + } + ty::ty_trait(ref trait_type) => { + if reachable_by_destructor { + match trait_type.principal.substs.regions { + subst::NonerasedRegions(ref regions) => { + for region in regions.iter() { + constrain_region_for_destructor_safety( + rcx, + *region, + scope, + span) + } + } + subst::ErasedRegions => {} + } + + // FIXME (pnkfelix): Added by pnkfelix, but + // need to double-check that this additional + // constraint is necessary. + constrain_region_for_destructor_safety( + rcx, + trait_type.bounds.region_bound, + scope, + span) + } + true + } + ty::ty_ptr(_) | ty::ty_bare_fn(_) => { + // Don't recurse, since pointers, boxes, and bare + // functions don't own instances of the types appearing + // within them. + false + } + ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | + ty::ty_float(_) | ty::ty_uniq(_) | ty::ty_str | + ty::ty_vec(..) | ty::ty_tup(_) | ty::ty_param(_) | + ty::ty_infer(_) | ty::ty_open(_) | ty::ty_err => true, + }; + + keep_going + }) + }); +} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 1869d2668a953..cb6ed5b9d08ce 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -119,6 +119,7 @@ use syntax::print::pprust; use syntax::ptr::P; use syntax::visit::{mod, Visitor}; +pub mod dropck; pub mod _match; pub mod vtable; pub mod writeback; diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 2306ba0cb7230..0f13719f03b74 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -129,6 +129,7 @@ use middle::typeck::astconv::AstConv; use middle::typeck::check::FnCtxt; use middle::typeck::check::regionmanip; use middle::typeck::check::vtable; +use middle::typeck::check::dropck; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; use middle::typeck::infer; @@ -278,16 +279,45 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { maybe_links: RefCell::new(FnvHashMap::new()) } } + pub fn traverse_type_if_unseen(&mut self, + typ: ty::Ty<'tcx>, + keep_going: |&mut Rcx<'a, 'tcx>| -> bool) -> bool { + let rcx = self; + + // Avoid recursing forever. + if !rcx.breadcrumbs.contains(&typ) { + rcx.breadcrumbs.push(typ); + let keep_going = keep_going(rcx); + let top_t = rcx.breadcrumbs.pop(); + assert_eq!(top_t, Some(typ)); + keep_going + } else { + false + } + } + pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fcx.ccx.tcx } + pub fn mk_subr(&self, + origin: infer::SubregionOrigin<'tcx>, + sub: ty::Region, + sup: ty::Region) { + self.fcx.mk_subr(origin, sub, sup) + } + pub fn set_repeating_scope(&mut self, scope: ast::NodeId) -> ast::NodeId { let old_scope = self.repeating_scope; self.repeating_scope = scope; old_scope } + pub fn try_resolve_type(&self, unresolved_ty: Ty<'tcx>) -> fres> { + resolve_type(self.fcx.infcx(), None, unresolved_ty, + resolve_and_force_all_but_regions) + } + pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { /*! * Try to resolve the type for the given node, returning @@ -317,8 +347,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { * bigger than the let and the `*b` expression, so we will * effectively resolve `` to be the block B. */ - match resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) { + self.try_resolve_type(unresolved_ty) { Ok(t) => t, Err(_) => ty::mk_err() } @@ -585,7 +614,7 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { let var_scope = tcx.region_maps.var_scope(id); let typ = rcx.resolve_node_type(id); - check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); + dropck::check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); }) } @@ -1285,21 +1314,6 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, minimum_lifetime, maximum_lifetime) } -fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, - typ: ty::Ty<'tcx>, - span: Span, - scope: CodeExtent) { - debug!("check_safety_of_destructor_if_necessary typ: {} scope: {}", - typ.repr(rcx.tcx()), scope); - iterate_over_potentially_unsafe_regions_in_type( - rcx, - typ, - span, - scope, - false, - 0) -} - fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, cmt: mc::cmt<'tcx>, span: Span) { @@ -1308,10 +1322,10 @@ fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 't match region { ty::ReScope(rvalue_scope) => { let typ = rcx.resolve_type(cmt.ty); - check_safety_of_destructor_if_necessary(rcx, - typ, - span, - rvalue_scope); + dropck::check_safety_of_destructor_if_necessary(rcx, + typ, + span, + rvalue_scope); } ty::ReStatic => {} region => { @@ -2075,167 +2089,3 @@ fn param_must_outlive<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>, region, param_bounds); } - -fn constrain_region_for_destructor_safety(rcx: &mut Rcx, - region: ty::Region, - inner_scope: CodeExtent, - span: Span) { - // Ignore bound regions. - match region { - ty::ReEarlyBound(..) | ty::ReLateBound(..) => return, - ty::ReFunction | ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | - ty::ReInfer(_) | ty::ReEmpty => {} - } - - // Get the parent scope. - let parent_inner_region = - match rcx.fcx.tcx().region_maps.opt_encl_scope(inner_scope) { - Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), - None => ty::ReFunction, - }; - - rcx.fcx.mk_subr(infer::SafeDestructor(span), - parent_inner_region, - region); -} - -fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( - rcx: &mut Rcx<'a, 'tcx>, - typ: ty::Ty<'tcx>, - span: Span, - scope: CodeExtent, - reachable_by_destructor: bool, - depth: uint) { - ty::maybe_walk_ty(typ, |typ| { - // Avoid recursing forever. - if !rcx.breadcrumbs.contains(&typ) { - rcx.breadcrumbs.push(typ); - - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}typ: {} scope: {} reachable_by_destructor: {}", - String::from_char(depth, ' '), - typ.repr(rcx.tcx()), scope, reachable_by_destructor); - - let keep_going = match typ.sty { - ty::ty_struct(structure_id, ref substitutions) => { - let reachable_by_destructor = - reachable_by_destructor || - ty::has_dtor(rcx.fcx.tcx(), structure_id); - - let fields = - ty::lookup_struct_fields(rcx.fcx.tcx(), - structure_id); - for field in fields.iter() { - let field_type = - ty::lookup_field_type(rcx.fcx.tcx(), - structure_id, - field.id, - substitutions); - iterate_over_potentially_unsafe_regions_in_type( - rcx, - field_type, - span, - scope, - reachable_by_destructor, depth+1) - } - - false - } - ty::ty_enum(enumeration_id, ref substitutions) => { - let reachable_by_destructor = reachable_by_destructor || - ty::has_dtor(rcx.fcx.tcx(), enumeration_id); - - let all_variant_info = - ty::substd_enum_variants(rcx.fcx.tcx(), - enumeration_id, - substitutions); - for variant_info in all_variant_info.iter() { - for argument_type in variant_info.args.iter() { - iterate_over_potentially_unsafe_regions_in_type( - rcx, - *argument_type, - span, - scope, - reachable_by_destructor, depth+1) - } - } - - false - } - ty::ty_rptr(region, _) => { - if reachable_by_destructor { - constrain_region_for_destructor_safety(rcx, - region, - scope, - span) - } - // Don't recurse, since references do not own their - // contents. - false - } - ty::ty_unboxed_closure(..) => { - true - } - ty::ty_closure(ref closure_type) => { - match closure_type.store { - ty::RegionTraitStore(region, _) => { - if reachable_by_destructor { - constrain_region_for_destructor_safety(rcx, - region, - scope, - span) - } - } - ty::UniqTraitStore => {} - } - // Don't recurse, since closures don't own the types - // appearing in their signature. - false - } - ty::ty_trait(ref trait_type) => { - if reachable_by_destructor { - match trait_type.principal.substs.regions { - subst::NonerasedRegions(ref regions) => { - for region in regions.iter() { - constrain_region_for_destructor_safety( - rcx, - *region, - scope, - span) - } - } - subst::ErasedRegions => {} - } - - // FIXME (pnkfelix): Added by pnkfelix, but - // need to double-check that this additional - // constraint is necessary. - constrain_region_for_destructor_safety( - rcx, - trait_type.bounds.region_bound, - scope, - span) - } - true - } - ty::ty_ptr(_) | ty::ty_bare_fn(_) => { - // Don't recurse, since pointers, boxes, and bare - // functions don't own instances of the types appearing - // within them. - false - } - ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | - ty::ty_float(_) | ty::ty_uniq(_) | ty::ty_str | - ty::ty_vec(..) | ty::ty_tup(_) | ty::ty_param(_) | - ty::ty_infer(_) | ty::ty_open(_) | ty::ty_err => true, - }; - - let top_t = rcx.breadcrumbs.pop(); - assert_eq!(top_t, Some(typ)); - keep_going - } else { - false - } - }); -} - From bda56d40727659baccd63a0e2f2aef07ee481a21 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 27 Oct 2014 12:56:41 +0100 Subject: [PATCH 06/65] FIXME checkpoint pcwalton factoring out of `fn mem_categorization::scope`. This version has a debug statement that I should remove. also adds lifetime param to mem_categorization::scope to get repr working. --- .../middle/borrowck/gather_loans/lifetime.rs | 27 +--------------- src/librustc/middle/mem_categorization.rs | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 6447b214bc6b5..619ffc1ae1438 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -113,32 +113,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { // See the SCOPE(LV) function in doc.rs - match cmt.cat { - mc::cat_rvalue(temp_scope) => { - temp_scope - } - mc::cat_upvar(..) => { - ty::ReScope(self.item_scope) - } - mc::cat_static_item => { - ty::ReStatic - } - mc::cat_local(local_id) => { - ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id)) - } - mc::cat_deref(_, _, mc::UnsafePtr(..)) => { - ty::ReStatic - } - mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) | - mc::cat_deref(_, _, mc::Implicit(_, r)) => { - r - } - mc::cat_downcast(ref cmt) | - mc::cat_deref(ref cmt, _, mc::OwnedPtr) | - mc::cat_interior(ref cmt, _) => { - self.scope(cmt) - } - } + mc::scope(self.bccx.tcx, cmt, self.item_scope) } fn report_error(&self, code: bckerr_code) { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index e9986e47e4a21..bdd32feaa0055 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -80,7 +80,7 @@ use middle::typeck; use util::nodemap::{DefIdMap, NodeMap}; use util::ppaux::{ty_to_string, Repr}; -use syntax::ast::{MutImmutable, MutMutable}; +use syntax::ast::{MutImmutable, MutMutable, NodeId}; use syntax::ast; use syntax::ast_map; use syntax::codemap::Span; @@ -1543,3 +1543,32 @@ fn element_kind(t: Ty) -> ElementKind { _ => OtherElement } } + + +/// Returns the maximal region scope for the which the lvalue `cmt` is +/// guaranteed to be valid without any rooting etc, and presuming `cmt` +/// is not mutated. See the `SCOPE(LV)` function in `borrowck/doc.rs`. +pub fn scope<'tcx>(tcx: &ty::ctxt<'tcx>, cmt: &cmt<'tcx>, extent: region::CodeExtent) -> ty::Region { + let ret = match cmt.cat { + cat_rvalue(temp_scope) => temp_scope, + cat_upvar(..) => ty::ReScope(extent), + + cat_static_item => ty::ReStatic, + + cat_local(local_id) => { + ty::ReScope(tcx.region_maps.var_scope(local_id)) + } + + cat_deref(_, _, UnsafePtr(..)) => ty::ReStatic, + + cat_deref(_, _, BorrowedPtr(_, r)) | + cat_deref(_, _, Implicit(_, r)) => r, + + cat_downcast(ref cmt) | + cat_deref(ref cmt, _, OwnedPtr) | + cat_interior(ref cmt, _) => scope(tcx, cmt, extent), + }; + debug!("scope cmt: {} {} return: {}", cmt, cmt.repr(tcx), ret); + return ret; +} + From 1efff702bd7a633db9e0a501afdfac3065d83b21 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 27 Oct 2014 12:57:14 +0100 Subject: [PATCH 07/65] checkpoint pcwalton removal of `#[unsafe_destructor]` check. --- src/librustc/middle/typeck/check/wf.rs | 46 -------------------------- src/libsyntax/feature_gate.rs | 5 ++- 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index d9c6c3cb6262a..515c3dd7520b4 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -198,22 +198,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); let trait_ref = liberate_late_bound_regions(fcx.tcx(), item_scope, &trait_ref); - // There are special rules that apply to drop. - if - fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) && - !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") - { - match self_ty.sty { - ty::ty_struct(def_id, _) | - ty::ty_enum(def_id, _) => { - check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id); - } - _ => { - // Coherence already reports an error in this case. - } - } - } - // We are stricter on the trait-ref in an impl than the // self-type. In particular, we enforce region // relationships. The reason for this is that (at least @@ -470,33 +454,3 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }) .collect() } - -/////////////////////////////////////////////////////////////////////////// -// Special drop trait checking - -fn check_struct_safe_for_destructor<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, - span: Span, - self_ty: Ty<'tcx>, - struct_did: ast::DefId) { - let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did); - if !struct_tpt.generics.has_type_params(subst::TypeSpace) - && !struct_tpt.generics.has_region_params(subst::TypeSpace) - { - let cause = traits::ObligationCause::new(span, traits::DropTrait); - let obligation = traits::obligation_for_builtin_bound(fcx.tcx(), - cause, - self_ty, - ty::BoundSend); - match obligation { - Ok(obligation) => fcx.register_obligation(obligation), - _ => {} - } - } else { - span_err!(fcx.tcx().sess, span, E0141, - "cannot implement a destructor on a structure \ - with type parameters"); - span_note!(fcx.tcx().sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } -} diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 9635f0175f075..340c3667a26b9 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -220,9 +220,8 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { "unsafe_destructor") { self.gate_feature("unsafe_destructor", i.span, - "`#[unsafe_destructor]` allows too \ - many unsafe patterns and may be \ - removed in the future"); + "`#[unsafe_destructor]` does nothing \ + anymore") } for item in items.iter() { From 6ca149c4da2d283f1464785cf24796d19b56202a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 27 Oct 2014 12:58:30 +0100 Subject: [PATCH 08/65] checkpoint pcwalton test of new destructor static semantics. --- .../compile-fail/destructor-restrictions.rs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/compile-fail/destructor-restrictions.rs diff --git a/src/test/compile-fail/destructor-restrictions.rs b/src/test/compile-fail/destructor-restrictions.rs new file mode 100644 index 0000000000000..02887d18a681b --- /dev/null +++ b/src/test/compile-fail/destructor-restrictions.rs @@ -0,0 +1,21 @@ +// 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. + +// Tests the new destructor semantics. + +use std::cell::RefCell; + +fn main() { + let b = { + let a = box RefCell::new(4i); + *a.borrow() + 1i //~ ERROR `*a` does not live long enough + }; + println!("{}", b); +} From 7b475d3ed1ad27b36f212285b38fbe1f10aa1043 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:02:20 +0100 Subject: [PATCH 09/65] Add `CodeExtent::Remainder` variant to track a suffix of a block. --- src/librustc/metadata/tydecode.rs | 8 ++++++++ src/librustc/metadata/tyencode.rs | 4 +++- src/librustc/middle/region.rs | 14 +++++++++++++- src/librustc/middle/ty.rs | 4 +++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 00d12ad6a382d..39df257923ef4 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -344,6 +344,14 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Misc(node_id) } + 'B' => { + let node_id = parse_uint(st) as ast::NodeId; + let first_stmt_index = parse_uint(st); + let block_remainder = region::BlockRemainder { + block: node_id, first_statement_index: first_stmt_index, + }; + region::CodeExtent::Remainder(block_remainder) + } _ => panic!("parse_scope: bad input") } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index bbb2faaae0691..aa0ab589c0e5c 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -170,7 +170,9 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) { match scope { - region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id) + region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), + region::CodeExtent::Remainder(region::BlockRemainder { + block: block, first_statement_index: i }) => mywrite!(w, "B{}{}", block, i), } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index c5511f995bc68..01f2abe929f53 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -43,7 +43,16 @@ use syntax::visit::{Visitor, FnKind}; /// generated via deriving here. #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub enum CodeExtent { - Misc(ast::NodeId) + Misc(ast::NodeId), + Remainder(BlockRemainder) +} + +/// Represents a subscope of `block` that starts at +/// `block.stmts[first_statement_index]` (inclusive). +#[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] +pub struct BlockRemainder { + pub block: ast::NodeId, + pub first_statement_index: uint, } impl CodeExtent { @@ -60,6 +69,7 @@ impl CodeExtent { pub fn node_id(&self) -> ast::NodeId { match *self { CodeExtent::Misc(node_id) => node_id, + CodeExtent::Remainder(br) => br.block, } } @@ -68,6 +78,8 @@ impl CodeExtent { pub fn map_id(&self, f_id: |ast::NodeId| -> ast::NodeId) -> CodeExtent { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), + CodeExtent::Remainder(br) => + CodeExtent::Remainder(BlockRemainder { block: f_id(br.block), ..br }), } } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 47b296e46cd30..8be9ed37ca757 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -837,7 +837,9 @@ pub enum Region { /// region parameters. ReFree(FreeRegion), - /// A concrete region naming some expression within the current function. + /// A concrete region naming some statically determined extent + /// (e.g. an expression or sequence of statements) within the + /// current function. ReScope(region::CodeExtent), /// Static data that has an "infinite" lifetime. Top in the region lattice. From 079dab3fef14f735621f4c4490876cc0bee2f906 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:55:31 +0100 Subject: [PATCH 10/65] add debug output to gather_loans. --- src/librustc/middle/borrowck/gather_loans/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index c36a466919b45..13c735b820440 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -474,6 +474,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for StaticInitializerCtxt<'a, 'tcx> { fn visit_expr(&mut self, ex: &Expr) { match ex.node { ast::ExprAddrOf(mutbl, ref base) => { + debug!("StaticInitializerCtxt visit_expr ex: {}", + ex.repr(self.bccx.tcx)); let base_cmt = self.bccx.cat_expr(&**base); let borrow_kind = ty::BorrowKind::from_mutbl(mutbl); // Check that we don't allow borrows of unsafe static items. From 15b11e4fff94f89b4a25054009d732c909a6a4b6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:55:55 +0100 Subject: [PATCH 11/65] Add debug output to expr_use_visitor. --- src/librustc/middle/expr_use_visitor.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index fa0f59f686049..238f2575af601 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -285,6 +285,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { assignment_expr: &ast::Expr, expr: &ast::Expr, mode: MutateMode) { + debug!("mutate_expr(expr={})", expr.repr(self.tcx())); let cmt = return_if_err!(self.mc.cat_expr(expr)); self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode); self.walk_expr(expr); @@ -601,6 +602,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } fn walk_local(&mut self, local: &ast::Local) { + debug!("walk_local(local.id={})", local.id); match local.init { None => { let delegate = &mut self.delegate; @@ -643,6 +645,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { _expr: &ast::Expr, fields: &Vec, opt_with: &Option>) { + debug!("walk_struct_expr(_expr.id={})", _expr.id); + // Consume the expressions supplying values for each field. for field in fields.iter() { self.consume_expr(&*field.expr); From 46bd59a4ebfabafe07a4836070abd86766b2e0cd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:56:17 +0100 Subject: [PATCH 12/65] add debug output to regionck --- src/librustc/middle/typeck/check/regionck.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 0f13719f03b74..a380d05ecb182 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1146,6 +1146,8 @@ fn constrain_callee(rcx: &mut Rcx, callee_id: ast::NodeId, call_expr: &ast::Expr, callee_expr: &ast::Expr) { + debug!("constrain_callee callee_id: {} call_expr.id: {}", + callee_id, call_expr.id); let call_region = ty::ReScope(CodeExtent::from_node_id(call_expr.id)); let callee_ty = rcx.resolve_node_type(callee_id); @@ -1805,6 +1807,7 @@ fn adjust_borrow_kind_for_assignment_lhs(rcx: &Rcx, * for upvars that are assigned to in an assignment * expression. */ + debug!("adjust_borrow_kind_for_assignment_lhs lhs.id: {}", lhs.id); let mc = mc::MemCategorizationContext::new(rcx); let cmt = ignore_err!(mc.cat_expr(lhs)); From 2193a6e2de38686fe84ec3b3f977e52187265a40 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 20:17:29 +0100 Subject: [PATCH 13/65] add more debug instrumentation to mem_categorization. --- src/librustc/middle/mem_categorization.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index bdd32feaa0055..315ce64fc48cb 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -414,6 +414,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_expr(&self, expr: &ast::Expr) -> McResult> { + debug!("cat_expr expr.id: {}", expr.id); match self.typer.adjustments().borrow().get(&expr.id) { None => { // No adjustments. @@ -457,6 +458,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { expr: &ast::Expr, autoderefs: uint) -> McResult> { + debug!("cat_expr_autoderefd: autoderefs={}", autoderefs); let mut cmt = if_ok!(self.cat_expr_unadjusted(expr)); debug!("cat_expr_autoderefd: autoderefs={}, cmt={}", autoderefs, @@ -468,7 +470,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult> { - debug!("cat_expr: id={} expr={}", expr.id, expr.repr(self.tcx())); + debug!("cat_expr_unadjusted: id={} expr={}", expr.id, expr.repr(self.tcx())); let expr_ty = if_ok!(self.expr_ty(expr)); match expr.node { From f8ccbc048ade99ffe5a24b69b3db192cbf2bacb5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 20:43:37 +0100 Subject: [PATCH 14/65] instrument the new cat_expr calls that were added to middle::typeck::check::regionck. --- src/librustc/middle/typeck/check/regionck.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index a380d05ecb182..91f12c3522b54 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -666,6 +666,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in the unadjusted form of this // expression. + debug!("visit_expr constrain destructors \ + unadjusted expr.id: {}", expr.id); let head_cmt = { let mc = mc::MemCategorizationContext::new(rcx); ignore_err!(mc.cat_expr_unadjusted(expr)) @@ -677,6 +679,8 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. + debug!("visit_expr constrain destructors \ + potentially adjusted expr.id: {}", expr.id); let head_cmt = { let mc = mc::MemCategorizationContext::new(rcx); ignore_err!(mc.cat_expr(expr)) From 47dd7c53f14a6611331dbdef793b44a2bf42710d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 26 Nov 2014 14:07:53 +0100 Subject: [PATCH 15/65] more debug instrumentation in mem_categorization. --- src/librustc/middle/mem_categorization.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 315ce64fc48cb..5556b1132695a 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -414,7 +414,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } pub fn cat_expr(&self, expr: &ast::Expr) -> McResult> { - debug!("cat_expr expr.id: {}", expr.id); + debug!("cat_expr expr.id: {} {}", expr.id, expr); match self.typer.adjustments().borrow().get(&expr.id) { None => { // No adjustments. @@ -472,7 +472,14 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult> { debug!("cat_expr_unadjusted: id={} expr={}", expr.id, expr.repr(self.tcx())); - let expr_ty = if_ok!(self.expr_ty(expr)); + // let expr_ty = if_ok!(self.expr_ty(expr)); + let expr_ty = match self.expr_ty(expr) { + Ok(expr_ty) => expr_ty, + Err(e) => { + debug!("cat_expr_unadjusted expr_ty errd"); + return Err(e); + } + }; match expr.node { ast::ExprUnary(ast::UnDeref, ref e_base) => { let base_cmt = if_ok!(self.cat_expr(&**e_base)); From b459fe2e215a363e3dbb78a51d2d42ccc8cbbfb5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 26 Nov 2014 14:09:04 +0100 Subject: [PATCH 16/65] more debug instrumentation in regionck --- src/librustc/middle/typeck/check/regionck.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 91f12c3522b54..3d84208d1222f 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -349,7 +349,10 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { */ self.try_resolve_type(unresolved_ty) { Ok(t) => t, - Err(_) => ty::mk_err() + Err(e) => { + debug!("Rcx::resolved_type resolve_type err: {}", e); + ty::mk_err() + } } } @@ -495,7 +498,12 @@ impl<'fcx, 'tcx> mc::Typer<'tcx> for Rcx<'fcx, 'tcx> { fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { let t = self.resolve_node_type(id); - if ty::type_is_error(t) {Err(())} else {Ok(t)} + if ty::type_is_error(t) { + debug!("Rcx::node_ty Errd because type_is_error t: {}", t); + Err(()) + } else { + Ok(t) + } } fn node_method_ty(&self, method_call: MethodCall) -> Option> { @@ -612,6 +620,8 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) { rcx, infer::BindingTypeIsNotValidAtDecl(span), id, var_region); + debug!("constrain_bindings_in_pat pat.id: {} calling var_scope(id: {})", + pat.id, id); let var_scope = tcx.region_maps.var_scope(id); let typ = rcx.resolve_node_type(id); dropck::check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope); @@ -1323,6 +1333,8 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx, fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, cmt: mc::cmt<'tcx>, span: Span) { + debug!("check_safety_of_rvalue_destructor_if_necessary cmt: {}", + cmt.repr(rcx.tcx())); match cmt.cat { mc::cat_rvalue(region) => { match region { From 587f300a16a487293fcf2257f6c24f36cb8e26bb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 26 Nov 2014 14:10:54 +0100 Subject: [PATCH 17/65] "fix" pcwalton changes to avoid premature return from regionck::visit_expr. includes still more debug instrumentation, as well as a span_note in the case that use to return prematurely. --- src/librustc/middle/typeck/check/regionck.rs | 32 +++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 3d84208d1222f..4ec3f1d0530fd 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -678,24 +678,40 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) { // expression. debug!("visit_expr constrain destructors \ unadjusted expr.id: {}", expr.id); - let head_cmt = { + let cmt_result = { let mc = mc::MemCategorizationContext::new(rcx); - ignore_err!(mc.cat_expr_unadjusted(expr)) + mc.cat_expr_unadjusted(expr) }; - check_safety_of_rvalue_destructor_if_necessary(rcx, - head_cmt, - expr.span); + match cmt_result { + Ok(head_cmt) => { + check_safety_of_rvalue_destructor_if_necessary(rcx, + head_cmt, + expr.span); + } + Err(..) => { + rcx.fcx.tcx().sess.span_note(expr.span, + "cat_expr_unadjusted Errd during dtor check"); + } + } } // If necessary, constrain destructors in this expression. This will be // the adjusted form if there is an adjustment. debug!("visit_expr constrain destructors \ potentially adjusted expr.id: {}", expr.id); - let head_cmt = { + let cmt_result = { let mc = mc::MemCategorizationContext::new(rcx); - ignore_err!(mc.cat_expr(expr)) + mc.cat_expr(expr) }; - check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span); + match cmt_result { + Ok(head_cmt) => { + check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span); + } + Err(..) => { + rcx.fcx.tcx().sess.span_note(expr.span, + "cat_expr Errd during dtor check"); + } + } match expr.node { ast::ExprCall(ref callee, ref args) => { From 04003a44da23f94a2190aa4da5f407a446b2a0e4 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 28 Nov 2014 17:19:27 +0100 Subject: [PATCH 18/65] region_inference: debug instrumentation of other sites where RegionResolutionError is pushed. --- .../typeck/infer/region_inference/mod.rs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 6f0d18431f8a0..d1179a8db91cf 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -1221,8 +1221,11 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { continue; } - let sups = sups.iter().map(|&sup| normalize(values, sup)) - .collect(); + let sups : Vec<_> = sups.iter().map(|&sup| normalize(values, sup)) + .collect(); + debug!("ParamBoundFailrue: all sup in sups !(sub <= sup): sub={}, sups={}", + sub.repr(self.tcx), + sups.repr(self.tcx)); errors.push( ParamBoundFailure( (*origin).clone(), *param_ty, sub, sups)); @@ -1393,6 +1396,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { debug!("collect_error_for_expanding_node {}", (i,j)); if !self.is_subregion_of(lower_bound.region, upper_bound.region) { + debug!("SubSupConflict: !(sub.region <= sup.region): sub={}, sup={}", + lower_bound.repr(self.tcx), + upper_bound.repr(self.tcx)); errors.push(SubSupConflict( (*self.var_origins.borrow())[node_idx.index].clone(), lower_bound.origin.clone(), @@ -1437,13 +1443,16 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { upper_bound_2.region) { Ok(_) => {} Err(_) => { - errors.push(SupSupConflict( - (*self.var_origins.borrow())[node_idx.index].clone(), - upper_bound_1.origin.clone(), - upper_bound_1.region, - upper_bound_2.origin.clone(), - upper_bound_2.region)); - return; + debug!("SubSupConflict: no glb for upper_bound_1: {} upper_bound_2: {}", + upper_bound_1.repr(self.tcx), + upper_bound_2.repr(self.tcx)); + errors.push(SupSupConflict( + (*self.var_origins.borrow())[node_idx.index].clone(), + upper_bound_1.origin.clone(), + upper_bound_1.region, + upper_bound_2.origin.clone(), + upper_bound_2.region)); + return; } } } From bb5c3fa8267d4b3bd50c3b1c4bae82f840453925 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 28 Nov 2014 17:20:26 +0100 Subject: [PATCH 19/65] regionck: bug fix to instrumentation I added in an earlier commit. --- src/librustc/middle/typeck/check/regionck.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 4ec3f1d0530fd..650e61489a604 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -313,11 +313,6 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { old_scope } - pub fn try_resolve_type(&self, unresolved_ty: Ty<'tcx>) -> fres> { - resolve_type(self.fcx.infcx(), None, unresolved_ty, - resolve_and_force_all_but_regions) - } - pub fn resolve_type(&self, unresolved_ty: Ty<'tcx>) -> Ty<'tcx> { /*! * Try to resolve the type for the given node, returning @@ -347,7 +342,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { * bigger than the let and the `*b` expression, so we will * effectively resolve `` to be the block B. */ - self.try_resolve_type(unresolved_ty) { + match resolve_type(self.fcx.infcx(), None, unresolved_ty, + resolve_and_force_all_but_regions) { Ok(t) => t, Err(e) => { debug!("Rcx::resolved_type resolve_type err: {}", e); From 713d755e62e9733488fae0b80c87b207641631e5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 28 Nov 2014 17:24:49 +0100 Subject: [PATCH 20/65] Add Closure variant to CodeExtent to lay foundation for special-case dropck handling of relationship of a closure to its enclosed block. --- src/librustc/metadata/tydecode.rs | 4 + src/librustc/metadata/tyencode.rs | 1 + src/librustc/middle/region.rs | 124 +++++++++++++++++++++++------- 3 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 39df257923ef4..806b7d42fbb97 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -344,6 +344,10 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Misc(node_id) } + 'C' => { + let node_id = parse_uint(st) as ast::NodeId; + region::CodeExtent::Closure(node_id) + } 'B' => { let node_id = parse_uint(st) as ast::NodeId; let first_stmt_index = parse_uint(st); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index aa0ab589c0e5c..25bb19286f3f9 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -171,6 +171,7 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) { fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) { match scope { region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), + region::CodeExtent::Closure(node_id) => mywrite!(w, "C{}", node_id), region::CodeExtent::Remainder(region::BlockRemainder { block: block, first_statement_index: i }) => mywrite!(w, "B{}{}", block, i), } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 01f2abe929f53..8d10829e4bb9a 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -44,7 +44,8 @@ use syntax::visit::{Visitor, FnKind}; #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub enum CodeExtent { Misc(ast::NodeId), - Remainder(BlockRemainder) + Closure(ast::NodeId), + Remainder(BlockRemainder), } /// Represents a subscope of `block` that starts at @@ -69,6 +70,7 @@ impl CodeExtent { pub fn node_id(&self) -> ast::NodeId { match *self { CodeExtent::Misc(node_id) => node_id, + CodeExtent::Closure(node_id) => node_id, CodeExtent::Remainder(br) => br.block, } } @@ -78,6 +80,7 @@ impl CodeExtent { pub fn map_id(&self, f_id: |ast::NodeId| -> ast::NodeId) -> CodeExtent { match *self { CodeExtent::Misc(node_id) => CodeExtent::Misc(f_id(node_id)), + CodeExtent::Closure(node_id) => CodeExtent::Closure(f_id(node_id)), CodeExtent::Remainder(br) => CodeExtent::Remainder(BlockRemainder { block: f_id(br.block), ..br }), } @@ -89,8 +92,10 @@ The region maps encode information about region relationships. - `scope_map` maps from a scope id to the enclosing scope id; this is usually corresponding to the lexical nesting, though in the case of - closures the parent scope is the innermost conditional expression or repeating - block + closures the parent scope of a closure expression is the innermost + conditional expression or repeating block. (Note that the enclosing + scope id for the block associated with a closure is the closure + itself.) - `var_map` maps from a variable or binding id to the block in which that variable is declared. @@ -132,11 +137,30 @@ pub struct RegionMaps { terminating_scopes: RefCell>, } +/// Carries the node id for the innermost block or match expression, +/// for building up the `var_map` which maps ids to the blocks in +/// which they were declared. +#[deriving(PartialEq, Eq, Show)] +enum InnermostDeclaringBlock { + None, + Some(ast::NodeId), +} + +#[deriving(PartialEq, Eq, Show)] +enum InnermostEnclosingExpr { + None, + Some(ast::NodeId), + /// A closure is treated as a separate case, because a closure and + /// its enclosed block do not have the same relationship with + /// respect to control-flow that most other expressions do. + Closure(ast::NodeId), +} + +#[deriving(PartialEq, Eq, Show)] pub struct Context { - var_parent: Option, + var_parent: InnermostDeclaringBlock, - // Innermost enclosing expression - parent: Option, + parent: InnermostEnclosingExpr, } struct RegionResolutionVisitor<'a> { @@ -165,25 +189,25 @@ impl RegionMaps { self.free_region_map.borrow_mut().insert(sub, vec!(sup)); } - pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { + fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { debug!("record_encl_scope(sub={}, sup={})", sub, sup); assert!(sub != sup); self.scope_map.borrow_mut().insert(sub, sup); } - pub fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + fn record_var_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_var_scope(sub={}, sup={})", var, lifetime); assert!(var != lifetime.node_id()); self.var_map.borrow_mut().insert(var, lifetime); } - pub fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { + fn record_rvalue_scope(&self, var: ast::NodeId, lifetime: CodeExtent) { debug!("record_rvalue_scope(sub={}, sup={})", var, lifetime); assert!(var != lifetime.node_id()); self.rvalue_scopes.borrow_mut().insert(var, lifetime); } - pub fn mark_as_terminating_scope(&self, scope_id: CodeExtent) { + fn mark_as_terminating_scope(&self, scope_id: CodeExtent) { /*! * Records that a scope is a TERMINATING SCOPE. Whenever we * create automatic temporaries -- e.g. by an @@ -421,13 +445,27 @@ impl RegionMaps { fn record_superlifetime(visitor: &mut RegionResolutionVisitor, child_id: ast::NodeId, _sp: Span) { + // FIXME (pnkfelix): currently this is redundantly adding entries + // for both a specific variant (Closure in this case) as well as + // the catch-all `CodeExtent::Misc`. This bloats the hashtable and + // is ugly to boot; we should instead consistently select the + // specific variant in all necessary contexts. match visitor.cx.parent { - Some(parent_id) => { - let child_scope = CodeExtent::from_node_id(child_id); + InnermostEnclosingExpr::Some(parent_id) => { let parent_scope = CodeExtent::from_node_id(parent_id); + let child_scope = CodeExtent::Misc(child_id); + visitor.region_maps.record_encl_scope(child_scope, parent_scope); + let child_scope = CodeExtent::Closure(child_id); visitor.region_maps.record_encl_scope(child_scope, parent_scope); } - None => {} + InnermostEnclosingExpr::Closure(closure_id) => { + let parent_scope = CodeExtent::Closure(closure_id); + let child_scope = CodeExtent::Misc(child_id); + visitor.region_maps.record_encl_scope(child_scope, parent_scope); + let child_scope = CodeExtent::Closure(child_id); + visitor.region_maps.record_encl_scope(child_scope, parent_scope); + } + InnermostEnclosingExpr::None => {} } } @@ -436,11 +474,11 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, var_id: ast::NodeId, _sp: Span) { match visitor.cx.var_parent { - Some(parent_id) => { + InnermostDeclaringBlock::Some(parent_id) => { let parent_scope = CodeExtent::from_node_id(parent_id); visitor.region_maps.record_var_scope(var_id, parent_scope); } - None => { + InnermostDeclaringBlock::None => { // this can happen in extern fn declarations like // // extern fn isalnum(c: c_int) -> c_int @@ -464,7 +502,10 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { // let prev_cx = visitor.cx; - visitor.cx = Context {var_parent: Some(blk.id), parent: Some(blk.id)}; + visitor.cx = Context { + var_parent: InnermostDeclaringBlock::Some(blk.id), + parent: InnermostEnclosingExpr::Some(blk.id) + }; visit::walk_block(visitor, blk); visitor.cx = prev_cx; } @@ -508,7 +549,7 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { record_superlifetime(visitor, stmt_id, stmt.span); let prev_parent = visitor.cx.parent; - visitor.cx.parent = Some(stmt_id); + visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id); visit::walk_stmt(visitor, stmt); visitor.cx.parent = prev_parent; } @@ -519,7 +560,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { record_superlifetime(visitor, expr.id, expr.span); let prev_cx = visitor.cx; - visitor.cx.parent = Some(expr.id); + visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id); { let region_maps = &mut visitor.region_maps; let terminating = |id| { @@ -562,11 +603,11 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { // The variable parent of everything inside (most importantly, the // pattern) is the body. - visitor.cx.var_parent = Some(body.id); + visitor.cx.var_parent = InnermostDeclaringBlock::Some(body.id); } ast::ExprMatch(..) => { - visitor.cx.var_parent = Some(expr.id); + visitor.cx.var_parent = InnermostDeclaringBlock::Some(expr.id); } ast::ExprAssignOp(..) | ast::ExprIndex(..) | @@ -604,8 +645,8 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { local.id,local.init.is_some()); let blk_id = match visitor.cx.var_parent { - Some(id) => id, - None => { + InnermostDeclaringBlock::Some(id) => id, + InnermostDeclaringBlock::None => { visitor.sess.span_bug( local.span, "local without enclosing block"); @@ -851,7 +892,10 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { fn resolve_item(visitor: &mut RegionResolutionVisitor, item: &ast::Item) { // Items create a new outer block scope as far as we're concerned. let prev_cx = visitor.cx; - visitor.cx = Context {var_parent: None, parent: None}; + visitor.cx = Context { + var_parent: InnermostDeclaringBlock::None, + parent: InnermostEnclosingExpr::None + }; visit::walk_item(visitor, item); visitor.cx = prev_cx; } @@ -877,15 +921,20 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, let outer_cx = visitor.cx; // The arguments and `self` are parented to the body of the fn. - visitor.cx = Context { parent: Some(body.id), - var_parent: Some(body.id) }; + visitor.cx = Context { + parent: InnermostEnclosingExpr::Some(body.id), + var_parent: InnermostDeclaringBlock::Some(body.id) + }; visit::walk_fn_decl(visitor, decl); // The body of the fn itself is either a root scope (top-level fn) // or it continues with the inherited scope (closures). match fk { visit::FkItemFn(..) | visit::FkMethod(..) => { - visitor.cx = Context { parent: None, var_parent: None }; + visitor.cx = Context { + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::None + }; visitor.visit_block(body); visitor.cx = outer_cx; } @@ -897,8 +946,19 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, // but the correct fix is a bit subtle, and I am also not sure // that the present approach is unsound -- it may not permit // any illegal programs. See issue for more details. - visitor.cx = outer_cx; + + if outer_cx.parent != InnermostEnclosingExpr::Some(id) { + visitor.sess.span_note( + sp, format!("resolve_fn id={} unexpected outer_cx: {}", + id, outer_cx).as_slice()); + } + visitor.cx = Context { + // parent: InnermostEnclosingExpr::Some(id), + parent: InnermostEnclosingExpr::Closure(id), + ..outer_cx + }; visitor.visit_block(body); + visitor.cx = outer_cx; } } } @@ -946,7 +1006,10 @@ pub fn resolve_crate(sess: &Session, krate: &ast::Crate) -> RegionMaps { let mut visitor = RegionResolutionVisitor { sess: sess, region_maps: &maps, - cx: Context { parent: None, var_parent: None } + cx: Context { + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::None, + } }; visit::walk_crate(&mut visitor, krate); } @@ -959,7 +1022,10 @@ pub fn resolve_inlined_item(sess: &Session, let mut visitor = RegionResolutionVisitor { sess: sess, region_maps: region_maps, - cx: Context { parent: None, var_parent: None } + cx: Context { + parent: InnermostEnclosingExpr::None, + var_parent: InnermostDeclaringBlock::None + } }; visit::walk_inlined_item(&mut visitor, item); } From f1fd35b40f84e75271162f37f9a0d5fe344d3481 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 28 Nov 2014 17:39:03 +0100 Subject: [PATCH 21/65] `fn constrain_region_for_destructor_safety`: Use `ReFunction` as parent-scope of closure's block. This is (hopefully) temporary fix for boot-strapping pcwalton's old 8861 work, since my goal is to eventually get rid of `ReFunction` entirely. --- src/librustc/middle/typeck/check/dropck.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index b79fe2e0f547c..8056a5dba3d5f 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -39,8 +39,8 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, // Get the parent scope. let parent_inner_region = match rcx.tcx().region_maps.opt_encl_scope(inner_scope) { + None | Some(region::CodeExtent::Closure(_)) => ty::ReFunction, Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), - None => ty::ReFunction, }; rcx.tcx().sess.span_note( From 00cfcb5ef72b59a865a182eb1f87924a954fb5a0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 25 Nov 2014 17:05:21 +0100 Subject: [PATCH 22/65] REMOVE ME: annotate core::panicking to avoid a problem downstream in drop-lts. --- src/libcore/panicking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index fd0526db411cb..b400f49857e91 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -64,6 +64,6 @@ pub fn panic_fmt(fmt: &fmt::Arguments, file_line: &(&'static str, uint)) -> ! { line: uint) -> !; } - let (file, line) = *file_line; + let (file, line) : (&'static str, uint) = *file_line; unsafe { panic_impl(fmt, file, line) } } From 977bc4bab5f65e70d212d615bbf9442a86ec8df0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 27 Nov 2014 15:26:17 +0100 Subject: [PATCH 23/65] added libst2 as libstd stubs. --- src/libst2/ascii.rs | 382 +++++++ src/libst2/bitflags.rs | 463 +++++++++ src/libst2/c_vec.rs | 118 +++ src/libst2/collections/hash/bench.rs | 0 src/libst2/collections/hash/map.rs | 880 ++++++++++++++++ src/libst2/collections/hash/mod.rs | 15 + src/libst2/collections/hash/set.rs | 519 ++++++++++ src/libst2/collections/hash/table.rs | 408 ++++++++ src/libst2/collections/lru_cache.rs | 245 +++++ src/libst2/collections/mod.rs | 354 +++++++ src/libst2/dynamic_lib.rs | 154 +++ src/libst2/error.rs | 106 ++ src/libst2/failure.rs | 37 + src/libst2/fmt.rs | 446 ++++++++ src/libst2/hash.rs | 94 ++ src/libst2/io/buffered.rs | 246 +++++ src/libst2/io/comm_adapters.rs | 88 ++ src/libst2/io/extensions.rs | 97 ++ src/libst2/io/fs.rs | 530 ++++++++++ src/libst2/io/mem.rs | 235 +++++ src/libst2/io/mod.rs | 1258 +++++++++++++++++++++++ src/libst2/io/net/addrinfo.rs | 96 ++ src/libst2/io/net/ip.rs | 231 +++++ src/libst2/io/net/mod.rs | 27 + src/libst2/io/net/pipe.rs | 206 ++++ src/libst2/io/net/tcp.rs | 400 +++++++ src/libst2/io/net/udp.rs | 182 ++++ src/libst2/io/pipe.rs | 93 ++ src/libst2/io/process.rs | 470 +++++++++ src/libst2/io/result.rs | 42 + src/libst2/io/stdio.rs | 396 +++++++ src/libst2/io/tempfile.rs | 69 ++ src/libst2/io/test.rs | 81 ++ src/libst2/io/timer.rs | 192 ++++ src/libst2/io/util.rs | 161 +++ src/libst2/lib.rs | 280 +++++ src/libst2/macros.rs | 626 +++++++++++ src/libst2/num/f32.rs | 261 +++++ src/libst2/num/f64.rs | 269 +++++ src/libst2/num/float_macros.rs | 22 + src/libst2/num/i16.rs | 18 + src/libst2/num/i32.rs | 18 + src/libst2/num/i64.rs | 18 + src/libst2/num/i8.rs | 18 + src/libst2/num/int.rs | 18 + src/libst2/num/int_macros.rs | 17 + src/libst2/num/mod.rs | 143 +++ src/libst2/num/strconv.rs | 558 ++++++++++ src/libst2/num/u16.rs | 18 + src/libst2/num/u32.rs | 18 + src/libst2/num/u64.rs | 18 + src/libst2/num/u8.rs | 18 + src/libst2/num/uint.rs | 18 + src/libst2/num/uint_macros.rs | 37 + src/libst2/os.rs | 894 ++++++++++++++++ src/libst2/path/mod.rs | 780 ++++++++++++++ src/libst2/path/posix.rs | 167 +++ src/libst2/path/windows.rs | 383 +++++++ src/libst2/prelude.rs | 94 ++ src/libst2/rand/mod.rs | 362 +++++++ src/libst2/rand/os.rs | 384 +++++++ src/libst2/rand/reader.rs | 123 +++ src/libst2/rt/backtrace.rs | 501 +++++++++ src/libst2/rt/mod.rs | 114 ++ src/libst2/rt/util.rs | 38 + src/libst2/rtdeps.rs | 52 + src/libst2/sync/future.rs | 67 ++ src/libst2/sync/mod.rs | 33 + src/libst2/sync/task_pool.rs | 80 ++ src/libst2/sys/common/helper_thread.rs | 78 ++ src/libst2/sys/common/mod.rs | 55 + src/libst2/sys/common/net.rs | 298 ++++++ src/libst2/sys/common/thread_local.rs | 215 ++++ src/libst2/sys/unix/c.rs | 257 +++++ src/libst2/sys/unix/fs.rs | 95 ++ src/libst2/sys/unix/helper_signal.rs | 22 + src/libst2/sys/unix/mod.rs | 82 ++ src/libst2/sys/unix/os.rs | 25 + src/libst2/sys/unix/pipe.rs | 140 +++ src/libst2/sys/unix/process.rs | 69 ++ src/libst2/sys/unix/tcp.rs | 71 ++ src/libst2/sys/unix/thread_local.rs | 40 + src/libst2/sys/unix/timer.rs | 110 ++ src/libst2/sys/unix/tty.rs | 29 + src/libst2/sys/unix/udp.rs | 11 + src/libst2/sys/windows/c.rs | 250 +++++ src/libst2/sys/windows/fs.rs | 460 +++++++++ src/libst2/sys/windows/helper_signal.rs | 38 + src/libst2/sys/windows/mod.rs | 85 ++ src/libst2/sys/windows/os.rs | 103 ++ src/libst2/sys/windows/pipe.rs | 751 ++++++++++++++ src/libst2/sys/windows/process.rs | 511 +++++++++ src/libst2/sys/windows/tcp.rs | 219 ++++ src/libst2/sys/windows/thread_local.rs | 238 +++++ src/libst2/sys/windows/timer.rs | 210 ++++ src/libst2/sys/windows/tty.rs | 166 +++ src/libst2/sys/windows/udp.rs | 11 + src/libst2/task.rs | 183 ++++ src/libst2/thread_local/mod.rs | 313 ++++++ src/libst2/thread_local/scoped.rs | 199 ++++ src/libst2/time/duration.rs | 557 ++++++++++ src/libst2/time/mod.rs | 46 + 102 files changed, 21723 insertions(+) create mode 100644 src/libst2/ascii.rs create mode 100644 src/libst2/bitflags.rs create mode 100644 src/libst2/c_vec.rs create mode 100644 src/libst2/collections/hash/bench.rs create mode 100644 src/libst2/collections/hash/map.rs create mode 100644 src/libst2/collections/hash/mod.rs create mode 100644 src/libst2/collections/hash/set.rs create mode 100644 src/libst2/collections/hash/table.rs create mode 100644 src/libst2/collections/lru_cache.rs create mode 100644 src/libst2/collections/mod.rs create mode 100644 src/libst2/dynamic_lib.rs create mode 100644 src/libst2/error.rs create mode 100644 src/libst2/failure.rs create mode 100644 src/libst2/fmt.rs create mode 100644 src/libst2/hash.rs create mode 100644 src/libst2/io/buffered.rs create mode 100644 src/libst2/io/comm_adapters.rs create mode 100644 src/libst2/io/extensions.rs create mode 100644 src/libst2/io/fs.rs create mode 100644 src/libst2/io/mem.rs create mode 100644 src/libst2/io/mod.rs create mode 100644 src/libst2/io/net/addrinfo.rs create mode 100644 src/libst2/io/net/ip.rs create mode 100644 src/libst2/io/net/mod.rs create mode 100644 src/libst2/io/net/pipe.rs create mode 100644 src/libst2/io/net/tcp.rs create mode 100644 src/libst2/io/net/udp.rs create mode 100644 src/libst2/io/pipe.rs create mode 100644 src/libst2/io/process.rs create mode 100644 src/libst2/io/result.rs create mode 100644 src/libst2/io/stdio.rs create mode 100644 src/libst2/io/tempfile.rs create mode 100644 src/libst2/io/test.rs create mode 100644 src/libst2/io/timer.rs create mode 100644 src/libst2/io/util.rs create mode 100644 src/libst2/lib.rs create mode 100644 src/libst2/macros.rs create mode 100644 src/libst2/num/f32.rs create mode 100644 src/libst2/num/f64.rs create mode 100644 src/libst2/num/float_macros.rs create mode 100644 src/libst2/num/i16.rs create mode 100644 src/libst2/num/i32.rs create mode 100644 src/libst2/num/i64.rs create mode 100644 src/libst2/num/i8.rs create mode 100644 src/libst2/num/int.rs create mode 100644 src/libst2/num/int_macros.rs create mode 100644 src/libst2/num/mod.rs create mode 100644 src/libst2/num/strconv.rs create mode 100644 src/libst2/num/u16.rs create mode 100644 src/libst2/num/u32.rs create mode 100644 src/libst2/num/u64.rs create mode 100644 src/libst2/num/u8.rs create mode 100644 src/libst2/num/uint.rs create mode 100644 src/libst2/num/uint_macros.rs create mode 100644 src/libst2/os.rs create mode 100644 src/libst2/path/mod.rs create mode 100644 src/libst2/path/posix.rs create mode 100644 src/libst2/path/windows.rs create mode 100644 src/libst2/prelude.rs create mode 100644 src/libst2/rand/mod.rs create mode 100644 src/libst2/rand/os.rs create mode 100644 src/libst2/rand/reader.rs create mode 100644 src/libst2/rt/backtrace.rs create mode 100644 src/libst2/rt/mod.rs create mode 100644 src/libst2/rt/util.rs create mode 100644 src/libst2/rtdeps.rs create mode 100644 src/libst2/sync/future.rs create mode 100644 src/libst2/sync/mod.rs create mode 100644 src/libst2/sync/task_pool.rs create mode 100644 src/libst2/sys/common/helper_thread.rs create mode 100644 src/libst2/sys/common/mod.rs create mode 100644 src/libst2/sys/common/net.rs create mode 100644 src/libst2/sys/common/thread_local.rs create mode 100644 src/libst2/sys/unix/c.rs create mode 100644 src/libst2/sys/unix/fs.rs create mode 100644 src/libst2/sys/unix/helper_signal.rs create mode 100644 src/libst2/sys/unix/mod.rs create mode 100644 src/libst2/sys/unix/os.rs create mode 100644 src/libst2/sys/unix/pipe.rs create mode 100644 src/libst2/sys/unix/process.rs create mode 100644 src/libst2/sys/unix/tcp.rs create mode 100644 src/libst2/sys/unix/thread_local.rs create mode 100644 src/libst2/sys/unix/timer.rs create mode 100644 src/libst2/sys/unix/tty.rs create mode 100644 src/libst2/sys/unix/udp.rs create mode 100644 src/libst2/sys/windows/c.rs create mode 100644 src/libst2/sys/windows/fs.rs create mode 100644 src/libst2/sys/windows/helper_signal.rs create mode 100644 src/libst2/sys/windows/mod.rs create mode 100644 src/libst2/sys/windows/os.rs create mode 100644 src/libst2/sys/windows/pipe.rs create mode 100644 src/libst2/sys/windows/process.rs create mode 100644 src/libst2/sys/windows/tcp.rs create mode 100644 src/libst2/sys/windows/thread_local.rs create mode 100644 src/libst2/sys/windows/timer.rs create mode 100644 src/libst2/sys/windows/tty.rs create mode 100644 src/libst2/sys/windows/udp.rs create mode 100644 src/libst2/task.rs create mode 100644 src/libst2/thread_local/mod.rs create mode 100644 src/libst2/thread_local/scoped.rs create mode 100644 src/libst2/time/duration.rs create mode 100644 src/libst2/time/mod.rs diff --git a/src/libst2/ascii.rs b/src/libst2/ascii.rs new file mode 100644 index 0000000000000..272851218f370 --- /dev/null +++ b/src/libst2/ascii.rs @@ -0,0 +1,382 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15679 + +//! Operations on ASCII strings and characters + +#![unstable = "unsure about placement and naming"] +#![allow(deprecated)] + +use core::kinds::Sized; +use fmt; +use iter::Iterator; +use mem; +use option::{Option, Some, None}; +use slice::{SlicePrelude, AsSlice}; +use str::{Str, StrPrelude}; +use string::{String, IntoString}; +use vec::Vec; + +/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. +#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] +pub struct Ascii { chr: u8 } + +impl Ascii { + /// Converts an ascii character into a `u8`. + #[inline] + #[unstable = "recently renamed"] + pub fn as_byte(&self) -> u8 { unimplemented!() } + + /// Deprecated: use `as_byte` isntead. + #[deprecated = "use as_byte"] + pub fn to_byte(self) -> u8 { unimplemented!() } + + /// Converts an ascii character into a `char`. + #[inline] + #[unstable = "recently renamed"] + pub fn as_char(&self) -> char { unimplemented!() } + + /// Deprecated: use `as_char` isntead. + #[deprecated = "use as_char"] + pub fn to_char(self) -> char { unimplemented!() } + + /// Convert to lowercase. + #[inline] + #[stable] + pub fn to_lowercase(&self) -> Ascii { unimplemented!() } + + /// Convert to uppercase. + #[inline] + #[stable] + pub fn to_uppercase(&self) -> Ascii { unimplemented!() } + + /// Compares two ascii characters of equality, ignoring case. + #[inline] + #[deprecated = "normalize with to_lowercase"] + pub fn eq_ignore_case(self, other: Ascii) -> bool { unimplemented!() } + + // the following methods are like ctype, and the implementation is inspired by musl + + /// Check if the character is a letter (a-z, A-Z) + #[inline] + #[stable] + pub fn is_alphabetic(&self) -> bool { unimplemented!() } + + /// Check if the character is a number (0-9) + #[inline] + #[unstable = "may be renamed"] + pub fn is_digit(&self) -> bool { unimplemented!() } + + /// Check if the character is a letter or number + #[inline] + #[stable] + pub fn is_alphanumeric(&self) -> bool { unimplemented!() } + + /// Check if the character is a space or horizontal tab + #[inline] + #[experimental = "likely to be removed"] + pub fn is_blank(&self) -> bool { unimplemented!() } + + /// Check if the character is a control character + #[inline] + #[stable] + pub fn is_control(&self) -> bool { unimplemented!() } + + /// Checks if the character is printable (except space) + #[inline] + #[experimental = "unsure about naming, or whether this is needed"] + pub fn is_graph(&self) -> bool { unimplemented!() } + + /// Checks if the character is printable (including space) + #[inline] + #[unstable = "unsure about naming"] + pub fn is_print(&self) -> bool { unimplemented!() } + + /// Checks if the character is alphabetic and lowercase + #[inline] + #[stable] + pub fn is_lowercase(&self) -> bool { unimplemented!() } + + /// Checks if the character is alphabetic and uppercase + #[inline] + #[stable] + pub fn is_uppercase(&self) -> bool { unimplemented!() } + + /// Checks if the character is punctuation + #[inline] + #[stable] + pub fn is_punctuation(&self) -> bool { unimplemented!() } + + /// Checks if the character is a valid hex digit + #[inline] + #[stable] + pub fn is_hex(&self) -> bool { unimplemented!() } +} + +impl<'a> fmt::Show for Ascii { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +/// Trait for converting into an ascii type. +#[experimental = "may be replaced by generic conversion traits"] +pub trait AsciiCast { + /// Convert to an ascii type, panic on non-ASCII input. + #[inline] + fn to_ascii(&self) -> T { unimplemented!() } + + /// Convert to an ascii type, return None on non-ASCII input. + #[inline] + fn to_ascii_opt(&self) -> Option { unimplemented!() } + + /// Convert to an ascii type, not doing any range asserts + unsafe fn to_ascii_nocheck(&self) -> T; + + /// Check if convertible to ascii + fn is_ascii(&self) -> bool; +} + +#[experimental = "may be replaced by generic conversion traits"] +impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] { + #[inline] + unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] { unimplemented!() } + + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } +} + +#[experimental = "may be replaced by generic conversion traits"] +impl<'a> AsciiCast<&'a [Ascii]> for &'a str { + #[inline] + unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] { unimplemented!() } + + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } +} + +#[experimental = "may be replaced by generic conversion traits"] +impl AsciiCast for u8 { + #[inline] + unsafe fn to_ascii_nocheck(&self) -> Ascii { unimplemented!() } + + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } +} + +#[experimental = "may be replaced by generic conversion traits"] +impl AsciiCast for char { + #[inline] + unsafe fn to_ascii_nocheck(&self) -> Ascii { unimplemented!() } + + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } +} + +/// Trait for copyless casting to an ascii vector. +#[experimental = "may be replaced by generic conversion traits"] +pub trait OwnedAsciiCast { + /// Check if convertible to ascii + fn is_ascii(&self) -> bool; + + /// Take ownership and cast to an ascii vector. + /// # Panics + /// + /// Panic on non-ASCII input. + #[inline] + fn into_ascii(self) -> Vec { unimplemented!() } + + /// Take ownership and cast to an ascii vector. Return None on non-ASCII input. + #[inline] + fn into_ascii_opt(self) -> Option> { unimplemented!() } + + /// Take ownership and cast to an ascii vector. + /// Does not perform validation checks. + unsafe fn into_ascii_nocheck(self) -> Vec; +} + +#[experimental = "may be replaced by generic conversion traits"] +impl OwnedAsciiCast for String { + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } + + #[inline] + unsafe fn into_ascii_nocheck(self) -> Vec { unimplemented!() } +} + +#[experimental = "may be replaced by generic conversion traits"] +impl OwnedAsciiCast for Vec { + #[inline] + fn is_ascii(&self) -> bool { unimplemented!() } + + #[inline] + unsafe fn into_ascii_nocheck(self) -> Vec { unimplemented!() } +} + +/// Trait for converting an ascii type to a string. Needed to convert +/// `&[Ascii]` to `&str`. +#[experimental = "may be replaced by generic conversion traits"] +pub trait AsciiStr for Sized? { + /// Convert to a string. + fn as_str_ascii<'a>(&'a self) -> &'a str; + + /// Deprecated: use `to_lowercase` + #[deprecated="renamed `to_lowercase`"] + fn to_lower(&self) -> Vec; + + /// Convert to vector representing a lower cased ascii string. + #[deprecated = "use iterators instead"] + fn to_lowercase(&self) -> Vec; + + /// Deprecated: use `to_uppercase` + #[deprecated="renamed `to_uppercase`"] + fn to_upper(&self) -> Vec; + + /// Convert to vector representing a upper cased ascii string. + #[deprecated = "use iterators instead"] + fn to_uppercase(&self) -> Vec; + + /// Compares two Ascii strings ignoring case. + #[deprecated = "use iterators instead"] + fn eq_ignore_case(&self, other: &[Ascii]) -> bool; +} + +#[experimental = "may be replaced by generic conversion traits"] +impl AsciiStr for [Ascii] { + #[inline] + fn as_str_ascii<'a>(&'a self) -> &'a str { unimplemented!() } + + #[inline] + fn to_lower(&self) -> Vec { unimplemented!() } + + #[inline] + fn to_lowercase(&self) -> Vec { unimplemented!() } + + #[inline] + fn to_upper(&self) -> Vec { unimplemented!() } + + #[inline] + fn to_uppercase(&self) -> Vec { unimplemented!() } + + #[inline] + fn eq_ignore_case(&self, other: &[Ascii]) -> bool { unimplemented!() } +} + +impl IntoString for Vec { + #[inline] + fn into_string(self) -> String { unimplemented!() } +} + +/// Trait to convert to an owned byte vector by consuming self +#[experimental = "may be replaced by generic conversion traits"] +pub trait IntoBytes { + /// Converts to an owned byte vector by consuming self + fn into_bytes(self) -> Vec; +} + +#[experimental = "may be replaced by generic conversion traits"] +impl IntoBytes for Vec { + fn into_bytes(self) -> Vec { unimplemented!() } +} + + +/// Extension methods for ASCII-subset only operations on owned strings +#[experimental = "would prefer to do this in a more general way"] +pub trait OwnedAsciiExt { + /// Convert the string to ASCII upper case: + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + fn into_ascii_upper(self) -> Self; + + /// Convert the string to ASCII lower case: + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + fn into_ascii_lower(self) -> Self; +} + +/// Extension methods for ASCII-subset only operations on string slices +#[experimental = "would prefer to do this in a more general way"] +pub trait AsciiExt for Sized? { + /// Makes a copy of the string in ASCII upper case: + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + fn to_ascii_upper(&self) -> T; + + /// Makes a copy of the string in ASCII lower case: + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + fn to_ascii_lower(&self) -> T; + + /// Check that two strings are an ASCII case-insensitive match. + /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`, + /// but without allocating and copying temporary strings. + fn eq_ignore_ascii_case(&self, other: &Self) -> bool; +} + +#[experimental = "would prefer to do this in a more general way"] +impl AsciiExt for str { + #[inline] + fn to_ascii_upper(&self) -> String { unimplemented!() } + + #[inline] + fn to_ascii_lower(&self) -> String { unimplemented!() } + + #[inline] + fn eq_ignore_ascii_case(&self, other: &str) -> bool { unimplemented!() } +} + +#[experimental = "would prefer to do this in a more general way"] +impl OwnedAsciiExt for String { + #[inline] + fn into_ascii_upper(self) -> String { unimplemented!() } + + #[inline] + fn into_ascii_lower(self) -> String { unimplemented!() } +} + +#[experimental = "would prefer to do this in a more general way"] +impl AsciiExt> for [u8] { + #[inline] + fn to_ascii_upper(&self) -> Vec { unimplemented!() } + + #[inline] + fn to_ascii_lower(&self) -> Vec { unimplemented!() } + + #[inline] + fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { unimplemented!() } +} + +#[experimental = "would prefer to do this in a more general way"] +impl OwnedAsciiExt for Vec { + #[inline] + fn into_ascii_upper(mut self) -> Vec { unimplemented!() } + + #[inline] + fn into_ascii_lower(mut self) -> Vec { unimplemented!() } +} + +/// Returns a 'default' ASCII and C++11-like literal escape of a `u8` +/// +/// The default is chosen with a bias toward producing literals that are +/// legal in a variety of languages, including C++11 and similar C-family +/// languages. The exact rules are: +/// +/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. +/// - Single-quote, double-quote and backslash chars are backslash-escaped. +/// - Any other chars in the range [0x20,0x7e] are not escaped. +/// - Any other chars are given hex escapes. +/// - Unicode escapes are never generated by this function. +#[unstable = "needs to be updated to use an iterator"] +pub fn escape_default(c: u8, f: |u8|) { unimplemented!() } + +static ASCII_LOWER_MAP: [u8, ..0] = [ +]; + +static ASCII_UPPER_MAP: [u8, ..0] = [ +]; diff --git a/src/libst2/bitflags.rs b/src/libst2/bitflags.rs new file mode 100644 index 0000000000000..d8023dd3e4e3b --- /dev/null +++ b/src/libst2/bitflags.rs @@ -0,0 +1,463 @@ +// 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. + +#![experimental] +#![macro_escape] + +//! A typesafe bitmask flag generator. + +/// The `bitflags!` macro generates a `struct` that holds a set of C-style +/// bitmask flags. It is useful for creating typesafe wrappers for C APIs. +/// +/// The flags should only be defined for integer types, otherwise unexpected +/// type errors may occur at compile time. +/// +/// # Example +/// +/// ```{.rust} +/// bitflags! { +/// flags Flags: u32 { +/// const FLAG_A = 0x00000001, +/// const FLAG_B = 0x00000010, +/// const FLAG_C = 0x00000100, +/// const FLAG_ABC = FLAG_A.bits +/// | FLAG_B.bits +/// | FLAG_C.bits, +/// } +/// } +/// +/// fn main() { +/// let e1 = FLAG_A | FLAG_C; +/// let e2 = FLAG_B | FLAG_C; +/// assert!((e1 | e2) == FLAG_ABC); // union +/// assert!((e1 & e2) == FLAG_C); // intersection +/// assert!((e1 - e2) == FLAG_A); // set difference +/// assert!(!e2 == FLAG_A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait implementations: +/// +/// ```{.rust} +/// use std::fmt; +/// +/// bitflags! { +/// flags Flags: u32 { +/// const FLAG_A = 0x00000001, +/// const FLAG_B = 0x00000010, +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Show for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = FLAG_A | FLAG_B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags).as_slice(), "hi!"); +/// } +/// ``` +/// +/// # Attributes +/// +/// Attributes can be attached to the generated `struct` by placing them +/// before the `flags` keyword. +/// +/// # Derived traits +/// +/// The `PartialEq` and `Clone` traits are automatically derived for the `struct` using +/// the `deriving` attribute. Additional traits can be derived by providing an +/// explicit `deriving` attribute on `flags`. +/// +/// # Operators +/// +/// The following operator traits are implemented for the generated `struct`: +/// +/// - `BitOr`: union +/// - `BitAnd`: intersection +/// - `BitXor`: toggle +/// - `Sub`: set difference +/// - `Not`: set complement +/// +/// # Methods +/// +/// The following methods are defined for the generated `struct`: +/// +/// - `empty`: an empty set of flags +/// - `all`: the set of all flags +/// - `bits`: the raw value of the flags currently stored +/// - `is_empty`: `true` if no flags are currently stored +/// - `is_all`: `true` if all flags are currently set +/// - `intersects`: `true` if there are flags common to both `self` and `other` +/// - `contains`: `true` all of the flags in `other` are contained within `self` +/// - `insert`: inserts the specified flags in-place +/// - `remove`: removes the specified flags in-place +/// - `toggle`: the specified flags will be inserted if not present, and removed +/// if they are. +#[macro_export] +macro_rules! bitflags { + ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { + $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+ + }) => { + #[deriving(PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $(#[$attr])* + pub struct $BitFlags { + bits: $T, + } + + $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+ + + impl $BitFlags { + /// Returns an empty set of flags. + #[inline] + pub fn empty() -> $BitFlags { + $BitFlags { bits: 0 } + } + + /// Returns the set containing all flags. + #[inline] + pub fn all() -> $BitFlags { + $BitFlags { bits: $($value)|+ } + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub fn bits(&self) -> $T { + self.bits + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) != 0 { + ::std::option::None + } else { + ::std::option::Some($BitFlags { bits: bits }) + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits } & $BitFlags::all() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub fn is_empty(&self) -> bool { + *self == $BitFlags::empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub fn is_all(&self) -> bool { + *self == $BitFlags::all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub fn intersects(&self, other: $BitFlags) -> bool { + !(*self & other).is_empty() + } + + /// Returns `true` all of the flags in `other` are contained within `self`. + #[inline] + pub fn contains(&self, other: $BitFlags) -> bool { + (*self & other) == other + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: $BitFlags) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: $BitFlags) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: $BitFlags) { + self.bits ^= other.bits; + } + } + + impl BitOr<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(&self, other: &$BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits | other.bits } + } + } + + impl BitXor<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(&self, other: &$BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits ^ other.bits } + } + } + + impl BitAnd<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(&self, other: &$BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & other.bits } + } + } + + impl Sub<$BitFlags, $BitFlags> for $BitFlags { + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(&self, other: &$BitFlags) -> $BitFlags { + $BitFlags { bits: self.bits & !other.bits } + } + } + + impl Not<$BitFlags> for $BitFlags { + /// Returns the complement of this set of flags. + #[inline] + fn not(&self) -> $BitFlags { + $BitFlags { bits: !self.bits } & $BitFlags::all() + } + } + }; + ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { + $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+, + }) => { + bitflags! { + $(#[$attr])* + flags $BitFlags: $T { + $($(#[$Flag_attr])* const $Flag = $value),+ + } + } + }; +} + +#[cfg(test)] +#[allow(non_upper_case_globals)] +mod tests { + use hash; + use option::{Some, None}; + use ops::{BitOr, BitAnd, BitXor, Sub, Not}; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + flags Flags: u32 { + const FlagA = 0x00000001, + #[doc = " macros are way better at generating code than trans is"] + const FlagB = 0x00000010, + const FlagC = 0x00000100, + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const FlagABC = FlagA.bits + | FlagB.bits + | FlagC.bits, + } + } + + bitflags! { + flags AnotherSetOfFlags: i8 { + const AnotherFlag = -1_i8, + } + } + + #[test] + fn test_bits(){ + assert_eq!(Flags::empty().bits(), 0x00000000); + assert_eq!(FlagA.bits(), 0x00000001); + assert_eq!(FlagABC.bits(), 0x00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0x00); + assert_eq!(AnotherFlag.bits(), !0_i8); + } + + #[test] + fn test_from_bits() { + assert!(Flags::from_bits(0) == Some(Flags::empty())); + assert!(Flags::from_bits(0x1) == Some(FlagA)); + assert!(Flags::from_bits(0x10) == Some(FlagB)); + assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB)); + assert!(Flags::from_bits(0x1000) == None); + + assert!(AnotherSetOfFlags::from_bits(!0_i8) == Some(AnotherFlag)); + } + + #[test] + fn test_from_bits_truncate() { + assert!(Flags::from_bits_truncate(0) == Flags::empty()); + assert!(Flags::from_bits_truncate(0x1) == FlagA); + assert!(Flags::from_bits_truncate(0x10) == FlagB); + assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB)); + assert!(Flags::from_bits_truncate(0x1000) == Flags::empty()); + assert!(Flags::from_bits_truncate(0x1001) == FlagA); + + assert!(AnotherSetOfFlags::from_bits_truncate(0_i8) == AnotherSetOfFlags::empty()); + } + + #[test] + fn test_is_empty(){ + assert!(Flags::empty().is_empty()); + assert!(!FlagA.is_empty()); + assert!(!FlagABC.is_empty()); + + assert!(!AnotherFlag.is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!FlagA.is_all()); + assert!(FlagABC.is_all()); + + assert!(AnotherFlag.is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherFlag.intersects(AnotherFlag)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = FlagABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = FlagA; + let e2 = FlagB; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = FlagA; + let e2 = FlagA | FlagB; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = FlagA; + let e2 = FlagA | FlagB; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(FlagABC.contains(e2)); + + assert!(AnotherFlag.contains(AnotherFlag)); + } + + #[test] + fn test_insert(){ + let mut e1 = FlagA; + let e2 = FlagA | FlagB; + e1.insert(e2); + assert!(e1 == e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherFlag); + assert!(e3 == AnotherFlag); + } + + #[test] + fn test_remove(){ + let mut e1 = FlagA | FlagB; + let e2 = FlagA | FlagC; + e1.remove(e2); + assert!(e1 == FlagB); + + let mut e3 = AnotherFlag; + e3.remove(AnotherFlag); + assert!(e3 == AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = FlagA | FlagC; + let e2 = FlagB | FlagC; + assert!((e1 | e2) == FlagABC); // union + assert!((e1 & e2) == FlagC); // intersection + assert!((e1 - e2) == FlagA); // set difference + assert!(!e2 == FlagA); // set complement + assert!(e1 ^ e2 == FlagA | FlagB); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert!(e3 == FlagA | FlagB); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert!(m4 == AnotherSetOfFlags::empty()); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = FlagB; + assert!(a < b); + a = FlagC; + assert!(!(a < b) && b < a); + b = FlagC | FlagB; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = FlagA; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = FlagB; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert!(hash::hash(&x) == hash::hash(&y)); + x = Flags::all(); + y = FlagABC; + assert!(hash::hash(&x) == hash::hash(&y)); + } +} diff --git a/src/libst2/c_vec.rs b/src/libst2/c_vec.rs new file mode 100644 index 0000000000000..6e817956476e2 --- /dev/null +++ b/src/libst2/c_vec.rs @@ -0,0 +1,118 @@ +// 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. + +//! Library to interface with chunks of memory allocated in C. +//! +//! It is often desirable to safely interface with memory allocated from C, +//! encapsulating the unsafety into allocation and destruction time. Indeed, +//! allocating memory externally is currently the only way to give Rust shared +//! mut state with C programs that keep their own references; vectors are +//! unsuitable because they could be reallocated or moved at any time, and +//! importing C memory into a vector takes a one-time snapshot of the memory. +//! +//! This module simplifies the usage of such external blocks of memory. Memory +//! is encapsulated into an opaque object after creation; the lifecycle of the +//! memory can be optionally managed by Rust, if an appropriate destructor +//! closure is provided. Safety is ensured by bounds-checking accesses, which +//! are marshalled through get and set functions. +//! +//! There are three unsafe functions: the two constructors, and the +//! unwrap method. The constructors are unsafe for the +//! obvious reason (they act on a pointer that cannot be checked inside the +//! method), but `unwrap()` is somewhat more subtle in its unsafety. +//! It returns the contained pointer, but at the same time destroys the CVec +//! without running its destructor. This can be used to pass memory back to +//! C, but care must be taken that the ownership of underlying resources are +//! handled correctly, i.e. that allocated memory is eventually freed +//! if necessary. + +#![experimental] + +use kinds::Send; +use mem; +use ops::Drop; +use option::{Option, Some, None}; +use ptr::RawPtr; +use ptr; +use raw; +use slice::AsSlice; + +/// The type representing a foreign chunk of memory +pub struct CVec { + base: *mut T, + len: uint, + dtor: Option, +} + +#[unsafe_destructor] +impl Drop for CVec { + fn drop(&mut self) { unimplemented!() } +} + +impl CVec { + /// Create a `CVec` from a raw pointer to a buffer with a given length. + /// + /// Panics if the given pointer is null. The returned vector will not attempt + /// to deallocate the vector when dropped. + /// + /// # Arguments + /// + /// * base - A raw pointer to a buffer + /// * len - The number of elements in the buffer + pub unsafe fn new(base: *mut T, len: uint) -> CVec { unimplemented!() } + + /// Create a `CVec` from a foreign buffer, with a given length, + /// and a function to run upon destruction. + /// + /// Panics if the given pointer is null. + /// + /// # Arguments + /// + /// * base - A foreign pointer to a buffer + /// * len - The number of elements in the buffer + /// * dtor - A proc to run when the value is destructed, useful + /// for freeing the buffer, etc. + pub unsafe fn new_with_dtor(base: *mut T, len: uint, + dtor: proc():Send) -> CVec { unimplemented!() } + + /// View the stored data as a mutable slice. + pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { unimplemented!() } + + /// Retrieves an element at a given index, returning `None` if the requested + /// index is greater than the length of the vector. + pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> { unimplemented!() } + + /// Retrieves a mutable element at a given index, returning `None` if the + /// requested index is greater than the length of the vector. + pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> { unimplemented!() } + + /// Unwrap the pointer without running the destructor + /// + /// This method retrieves the underlying pointer, and in the process + /// destroys the CVec but without running the destructor. A use case + /// would be transferring ownership of the buffer to a C function, as + /// in this case you would not want to run the destructor. + /// + /// Note that if you want to access the underlying pointer without + /// cancelling the destructor, you can simply call `transmute` on the return + /// value of `get(0)`. + pub unsafe fn unwrap(mut self) -> *mut T { unimplemented!() } + + /// Returns the number of items in this vector. + pub fn len(&self) -> uint { unimplemented!() } + + /// Returns whether this vector is empty. + pub fn is_empty(&self) -> bool { unimplemented!() } +} + +impl AsSlice for CVec { + /// View the stored data as a slice. + fn as_slice<'a>(&'a self) -> &'a [T] { unimplemented!() } +} diff --git a/src/libst2/collections/hash/bench.rs b/src/libst2/collections/hash/bench.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/libst2/collections/hash/map.rs b/src/libst2/collections/hash/map.rs new file mode 100644 index 0000000000000..3c5d703a22e12 --- /dev/null +++ b/src/libst2/collections/hash/map.rs @@ -0,0 +1,880 @@ +// 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. +// +// ignore-lexer-test FIXME #15883 + +pub use self::Entry::*; +use self::SearchResult::*; +use self::VacantEntryState::*; + +use borrow::BorrowFrom; +use clone::Clone; +use cmp::{max, Eq, Equiv, PartialEq}; +use default::Default; +use fmt::{mod, Show}; +use hash::{Hash, Hasher, RandomSipHasher}; +use iter::{mod, Iterator, FromIterator, Extend}; +use kinds::Sized; +use mem::{mod, replace}; +use num::UnsignedInt; +use ops::{Deref, Index, IndexMut}; +use option::{Some, None, Option}; +use result::{Result, Ok, Err}; + +use super::table; +use super::table::{ + Bucket, + Empty, + EmptyBucket, + Full, + FullBucket, + FullBucketImm, + FullBucketMut, + RawTable, + SafeHash +}; + +// FIXME(conventions): update capacity management to match other collections (no auto-shrink) + +const INITIAL_LOG2_CAP: uint = 5; +pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5 + +/// The default behavior of HashMap implements a load factor of 90.9%. +/// This behavior is characterized by the following conditions: +/// +/// - if size > 0.909 * capacity: grow +/// - if size < 0.25 * capacity: shrink (if this won't bring capacity lower +/// than the minimum) +#[deriving(Clone)] +struct DefaultResizePolicy { + /// Doubled minimal capacity. The capacity must never drop below + /// the minimum capacity. (The check happens before the capacity + /// is potentially halved.) + minimum_capacity2: uint +} + +impl DefaultResizePolicy { + fn new(new_capacity: uint) -> DefaultResizePolicy { unimplemented!() } + + #[inline] + fn capacity_range(&self, new_size: uint) -> (uint, uint) { unimplemented!() } + + #[inline] + fn reserve(&mut self, new_capacity: uint) { unimplemented!() } +} + +// The main performance trick in this hashmap is called Robin Hood Hashing. +// It gains its excellent performance from one essential operation: +// +// If an insertion collides with an existing element, and that element's +// "probe distance" (how far away the element is from its ideal location) +// is higher than how far we've already probed, swap the elements. +// +// This massively lowers variance in probe distance, and allows us to get very +// high load factors with good performance. The 90% load factor I use is rather +// conservative. +// +// > Why a load factor of approximately 90%? +// +// In general, all the distances to initial buckets will converge on the mean. +// At a load factor of α, the odds of finding the target bucket after k +// probes is approximately 1-α^k. If we set this equal to 50% (since we converge +// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round +// this down to make the math easier on the CPU and avoid its FPU. +// Since on average we start the probing in the middle of a cache line, this +// strategy pulls in two cache lines of hashes on every lookup. I think that's +// pretty good, but if you want to trade off some space, it could go down to one +// cache line on average with an α of 0.84. +// +// > Wait, what? Where did you get 1-α^k from? +// +// On the first probe, your odds of a collision with an existing element is α. +// The odds of doing this twice in a row is approximately α^2. For three times, +// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT +// colliding after k tries is 1-α^k. +// +// The paper from 1986 cited below mentions an implementation which keeps track +// of the distance-to-initial-bucket histogram. This approach is not suitable +// for modern architectures because it requires maintaining an internal data +// structure. This allows very good first guesses, but we are most concerned +// with guessing entire cache lines, not individual indexes. Furthermore, array +// accesses are no longer linear and in one direction, as we have now. There +// is also memory and cache pressure that this would entail that would be very +// difficult to properly see in a microbenchmark. +// +// ## Future Improvements (FIXME!) +// +// Allow the load factor to be changed dynamically and/or at initialization. +// +// Also, would it be possible for us to reuse storage when growing the +// underlying table? This is exactly the use case for 'realloc', and may +// be worth exploring. +// +// ## Future Optimizations (FIXME!) +// +// Another possible design choice that I made without any real reason is +// parameterizing the raw table over keys and values. Technically, all we need +// is the size and alignment of keys and values, and the code should be just as +// efficient (well, we might need one for power-of-two size and one for not...). +// This has the potential to reduce code bloat in rust executables, without +// really losing anything except 4 words (key size, key alignment, val size, +// val alignment) which can be passed in to every call of a `RawTable` function. +// This would definitely be an avenue worth exploring if people start complaining +// about the size of rust executables. +// +// Annotate exceedingly likely branches in `table::make_hash` +// and `search_hashed` to reduce instruction cache pressure +// and mispredictions once it becomes possible (blocked on issue #11092). +// +// Shrinking the table could simply reallocate in place after moving buckets +// to the first half. +// +// The growth algorithm (fragment of the Proof of Correctness) +// -------------------- +// +// The growth algorithm is basically a fast path of the naive reinsertion- +// during-resize algorithm. Other paths should never be taken. +// +// Consider growing a robin hood hashtable of capacity n. Normally, we do this +// by allocating a new table of capacity `2n`, and then individually reinsert +// each element in the old table into the new one. This guarantees that the +// new table is a valid robin hood hashtable with all the desired statistical +// properties. Remark that the order we reinsert the elements in should not +// matter. For simplicity and efficiency, we will consider only linear +// reinsertions, which consist of reinserting all elements in the old table +// into the new one by increasing order of index. However we will not be +// starting our reinsertions from index 0 in general. If we start from index +// i, for the purpose of reinsertion we will consider all elements with real +// index j < i to have virtual index n + j. +// +// Our hash generation scheme consists of generating a 64-bit hash and +// truncating the most significant bits. When moving to the new table, we +// simply introduce a new bit to the front of the hash. Therefore, if an +// elements has ideal index i in the old table, it can have one of two ideal +// locations in the new table. If the new bit is 0, then the new ideal index +// is i. If the new bit is 1, then the new ideal index is n + i. Intutively, +// we are producing two independent tables of size n, and for each element we +// independently choose which table to insert it into with equal probability. +// However the rather than wrapping around themselves on overflowing their +// indexes, the first table overflows into the first, and the first into the +// second. Visually, our new table will look something like: +// +// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy] +// +// Where x's are elements inserted into the first table, y's are elements +// inserted into the second, and _'s are empty sections. We now define a few +// key concepts that we will use later. Note that this is a very abstract +// perspective of the table. A real resized table would be at least half +// empty. +// +// Theorem: A linear robin hood reinsertion from the first ideal element +// produces identical results to a linear naive reinsertion from the same +// element. +// +// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs + +/// A hash map implementation which uses linear probing with Robin +/// Hood bucket stealing. +/// +/// The hashes are all keyed by the task-local random number generator +/// on creation by default. This means that the ordering of the keys is +/// randomized, but makes the tables more resistant to +/// denial-of-service attacks (Hash DoS). This behaviour can be +/// overridden with one of the constructors. +/// +/// It is required that the keys implement the `Eq` and `Hash` traits, although +/// this can frequently be achieved by using `#[deriving(Eq, Hash)]`. +/// +/// Relevant papers/articles: +/// +/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf) +/// 2. Emmanuel Goossaert. ["Robin Hood +/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/) +/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift +/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/) +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// // type inference lets us omit an explicit type signature (which +/// // would be `HashMap<&str, &str>` in this example). +/// let mut book_reviews = HashMap::new(); +/// +/// // review some books. +/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); +/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); +/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); +/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); +/// +/// // check for a specific one. +/// if !book_reviews.contains_key(&("Les Misérables")) { +/// println!("We've got {} reviews, but Les Misérables ain't one.", +/// book_reviews.len()); +/// } +/// +/// // oops, this review has a lot of spelling mistakes, let's delete it. +/// book_reviews.remove(&("The Adventures of Sherlock Holmes")); +/// +/// // look up the values associated with some keys. +/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; +/// for book in to_find.iter() { +/// match book_reviews.get(book) { +/// Some(review) => println!("{}: {}", *book, *review), +/// None => println!("{} is unreviewed.", *book) +/// } +/// } +/// +/// // iterate over everything. +/// for (book, review) in book_reviews.iter() { +/// println!("{}: \"{}\"", *book, *review); +/// } +/// ``` +/// +/// The easiest way to use `HashMap` with a custom type is to derive `Eq` and `Hash`. +/// We must also derive `PartialEq`. +/// +/// ``` +/// use std::collections::HashMap; +/// +/// #[deriving(Hash, Eq, PartialEq, Show)] +/// struct Viking<'a> { +/// name: &'a str, +/// power: uint, +/// } +/// +/// let mut vikings = HashMap::new(); +/// +/// vikings.insert("Norway", Viking { name: "Einar", power: 9u }); +/// vikings.insert("Denmark", Viking { name: "Olaf", power: 4u }); +/// vikings.insert("Iceland", Viking { name: "Harald", power: 8u }); +/// +/// // Use derived implementation to print the vikings. +/// for (land, viking) in vikings.iter() { +/// println!("{} at {}", viking, land); +/// } +/// ``` +#[deriving(Clone)] +pub struct HashMap { + // All hashes are keyed on these values, to prevent hash collision attacks. + hasher: H, + + table: RawTable, + + // We keep this at the end since it might as well have tail padding. + resize_policy: DefaultResizePolicy, +} + +/// Search for a pre-hashed key. +fn search_hashed>>(table: M, + hash: &SafeHash, + is_match: |&K| -> bool) + -> SearchResult { unimplemented!() } + +fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { unimplemented!() } + +/// Perform robin hood bucket stealing at the given `bucket`. You must +/// also pass the position of that bucket's initial bucket so we don't have +/// to recalculate it. +/// +/// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable. +fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>, + mut ib: uint, + mut hash: SafeHash, + mut k: K, + mut v: V) + -> &'a mut V { unimplemented!() } + +/// A result that works like Option> but preserves +/// the reference that grants us access to the table in any case. +enum SearchResult { + // This is an entry that holds the given key: + FoundExisting(FullBucket), + + // There was no such entry. The reference is given back: + TableRef(M) +} + +impl SearchResult { + fn into_option(self) -> Option> { unimplemented!() } +} + +impl, V, S, H: Hasher> HashMap { + fn make_hash>(&self, x: &X) -> SafeHash { unimplemented!() } + + fn search_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, q: &Q) + -> Option> { unimplemented!() } + + fn search_equiv_mut<'a, Sized? Q: Hash + Equiv>(&'a mut self, q: &Q) + -> Option> { unimplemented!() } + + /// Search for a key, yielding the index if it's found in the hashtable. + /// If you already have the hash for the key lying around, use + /// search_hashed. + fn search<'a, Sized? Q>(&'a self, q: &Q) -> Option> + where Q: BorrowFrom + Eq + Hash + { unimplemented!() } + + fn search_mut<'a, Sized? Q>(&'a mut self, q: &Q) -> Option> + where Q: BorrowFrom + Eq + Hash + { unimplemented!() } + + // The caller should ensure that invariants by Robin Hood Hashing hold. + fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { unimplemented!() } +} + +impl HashMap { + /// Create an empty HashMap. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::new(); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn new() -> HashMap { unimplemented!() } + + /// Creates an empty hash map with the given initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::with_capacity(10); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn with_capacity(capacity: uint) -> HashMap { unimplemented!() } +} + +impl, V, S, H: Hasher> HashMap { + /// Creates an empty hashmap which will use the given hasher to hash keys. + /// + /// The creates map has the default initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut map = HashMap::with_hasher(h); + /// map.insert(1i, 2u); + /// ``` + #[inline] + pub fn with_hasher(hasher: H) -> HashMap { unimplemented!() } + + /// Create an empty HashMap with space for at least `capacity` + /// elements, using `hasher` to hash the keys. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow HashMaps to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut map = HashMap::with_capacity_and_hasher(10, h); + /// map.insert(1i, 2u); + /// ``` + #[inline] + pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashMap { unimplemented!() } + + /// The hashtable will never try to shrink below this size. You can use + /// this function to reduce reallocations if your hashtable frequently + /// grows and shrinks by large amounts. + /// + /// This function has no effect on the operational semantics of the + /// hashtable, only on performance. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// let mut map: HashMap<&str, int> = HashMap::new(); + /// map.reserve(10); + /// ``` + pub fn reserve(&mut self, new_minimum_capacity: uint) { unimplemented!() } + + /// Resizes the internal vectors to a new capacity. It's your responsibility to: + /// 1) Make sure the new capacity is enough for all the elements, accounting + /// for the load factor. + /// 2) Ensure new_capacity is a power of two. + fn resize(&mut self, new_capacity: uint) { unimplemented!() } + + /// Performs any necessary resize operations, such that there's space for + /// new_size elements. + fn make_some_room(&mut self, new_size: uint) { unimplemented!() } + + /// Insert a pre-hashed key-value pair, without first checking + /// that there's enough room in the buckets. Returns a reference to the + /// newly insert value. + /// + /// If the key already exists, the hashtable will be returned untouched + /// and a reference to the existing element will be returned. + fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V { unimplemented!() } + + fn insert_or_replace_with<'a>(&'a mut self, + hash: SafeHash, + k: K, + v: V, + found_existing: |&mut K, &mut V, V|) + -> &'a mut V { unimplemented!() } + + /// Deprecated: use `contains_key` and `BorrowFrom` instead. + #[deprecated = "use contains_key and BorrowFrom instead"] + pub fn contains_key_equiv + Equiv>(&self, key: &Q) -> bool { unimplemented!() } + + /// Deprecated: use `get` and `BorrowFrom` instead. + #[deprecated = "use get and BorrowFrom instead"] + pub fn find_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { unimplemented!() } + + /// Deprecated: use `remove` and `BorrowFrom` instead. + #[deprecated = "use remove and BorrowFrom instead"] + pub fn pop_equiv + Equiv>(&mut self, k: &Q) -> Option { unimplemented!() } + + /// An iterator visiting all keys in arbitrary order. + /// Iterator element type is `&'a K`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1i); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for key in map.keys() { + /// println!("{}", key); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn keys(&self) -> Keys { unimplemented!() } + + /// An iterator visiting all values in arbitrary order. + /// Iterator element type is `&'a V`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1i); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for key in map.values() { + /// println!("{}", key); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn values(&self) -> Values { unimplemented!() } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// Iterator element type is `(&'a K, &'a V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1i); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn iter(&self) -> Entries { unimplemented!() } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// Iterator element type is `(&'a K, &'a mut V)`. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1i); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Update all values + /// for (_, val) in map.iter_mut() { + /// *val *= 2; + /// } + /// + /// for (key, val) in map.iter() { + /// println!("key: {} val: {}", key, val); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn iter_mut(&mut self) -> MutEntries { unimplemented!() } + + /// Creates a consuming iterator, that is, one that moves each key-value + /// pair out of the map in arbitrary order. The map cannot be used after + /// calling this. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert("a", 1i); + /// map.insert("b", 2); + /// map.insert("c", 3); + /// + /// // Not possible with .iter() + /// let vec: Vec<(&str, int)> = map.into_iter().collect(); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn into_iter(self) -> MoveEntries { unimplemented!() } + + /// Gets the given key's corresponding entry in the map for in-place manipulation + pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { unimplemented!() } + + /// Return the number of elements in the map. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert_eq!(a.len(), 0); + /// a.insert(1u, "a"); + /// assert_eq!(a.len(), 1); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn len(&self) -> uint { unimplemented!() } + + /// Return true if the map contains no elements. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// assert!(a.is_empty()); + /// a.insert(1u, "a"); + /// assert!(!a.is_empty()); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_empty(&self) -> bool { unimplemented!() } + + /// Clears the map, removing all key-value pairs. Keeps the allocated memory + /// for reuse. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut a = HashMap::new(); + /// a.insert(1u, "a"); + /// a.clear(); + /// assert!(a.is_empty()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn clear(&mut self) { unimplemented!() } + + /// Deprecated: Renamed to `get`. + #[deprecated = "Renamed to `get`"] + pub fn find(&self, k: &K) -> Option<&V> { unimplemented!() } + + /// Returns a reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1u, "a"); + /// assert_eq!(map.get(&1), Some(&"a")); + /// assert_eq!(map.get(&2), None); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn get(&self, k: &Q) -> Option<&V> + where Q: Hash + Eq + BorrowFrom + { unimplemented!() } + + /// Returns true if the map contains a value for the specified key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1u, "a"); + /// assert_eq!(map.contains_key(&1), true); + /// assert_eq!(map.contains_key(&2), false); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn contains_key(&self, k: &Q) -> bool + where Q: Hash + Eq + BorrowFrom + { unimplemented!() } + + /// Deprecated: Renamed to `get_mut`. + #[deprecated = "Renamed to `get_mut`"] + pub fn find_mut(&mut self, k: &K) -> Option<&mut V> { unimplemented!() } + + /// Returns a mutable reference to the value corresponding to the key. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1u, "a"); + /// match map.get_mut(&1) { + /// Some(x) => *x = "b", + /// None => (), + /// } + /// assert_eq!(map[1], "b"); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> + where Q: Hash + Eq + BorrowFrom + { unimplemented!() } + + /// Deprecated: Renamed to `insert`. + #[deprecated = "Renamed to `insert`"] + pub fn swap(&mut self, k: K, v: V) -> Option { unimplemented!() } + + /// Inserts a key-value pair from the map. If the key already had a value + /// present in the map, that value is returned. Otherwise, `None` is returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// assert_eq!(map.insert(37u, "a"), None); + /// assert_eq!(map.is_empty(), false); + /// + /// map.insert(37, "b"); + /// assert_eq!(map.insert(37, "c"), Some("b")); + /// assert_eq!(map[37], "c"); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn insert(&mut self, k: K, v: V) -> Option { unimplemented!() } + + /// Deprecated: Renamed to `remove`. + #[deprecated = "Renamed to `remove`"] + pub fn pop(&mut self, k: &K) -> Option { unimplemented!() } + + /// Removes a key from the map, returning the value at the key if the key + /// was previously in the map. + /// + /// The key may be any borrowed form of the map's key type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the key type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut map = HashMap::new(); + /// map.insert(1u, "a"); + /// assert_eq!(map.remove(&1), Some("a")); + /// assert_eq!(map.remove(&1), None); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn remove(&mut self, k: &Q) -> Option + where Q: Hash + Eq + BorrowFrom + { unimplemented!() } +} + +fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHash, k: K) + -> Entry<'a, K, V> { unimplemented!() } + +impl, V: Clone, S, H: Hasher> HashMap { + /// Deprecated: Use `map.get(k).cloned()`. + /// + /// Return a copy of the value corresponding to the key. + #[deprecated = "Use `map.get(k).cloned()`"] + pub fn find_copy(&self, k: &K) -> Option { unimplemented!() } + + /// Deprecated: Use `map[k].clone()`. + /// + /// Return a copy of the value corresponding to the key. + #[deprecated = "Use `map[k].clone()`"] + pub fn get_copy(&self, k: &K) -> V { unimplemented!() } +} + +impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap { + fn eq(&self, other: &HashMap) -> bool { unimplemented!() } +} + +impl, V: Eq, S, H: Hasher> Eq for HashMap {} + +impl + Show, V: Show, S, H: Hasher> Show for HashMap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl, V, S, H: Hasher + Default> Default for HashMap { + fn default() -> HashMap { unimplemented!() } +} + +impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap + where Q: BorrowFrom + Hash + Eq +{ + #[inline] + fn index<'a>(&'a self, index: &Q) -> &'a V { unimplemented!() } +} + +impl + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap + where Q: BorrowFrom + Hash + Eq +{ + #[inline] + fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { unimplemented!() } +} + +/// HashMap iterator +pub struct Entries<'a, K: 'a, V: 'a> { + inner: table::Entries<'a, K, V> +} + +/// HashMap mutable values iterator +pub struct MutEntries<'a, K: 'a, V: 'a> { + inner: table::MutEntries<'a, K, V> +} + +/// HashMap move iterator +pub struct MoveEntries { + inner: iter::Map<'static, (SafeHash, K, V), (K, V), table::MoveEntries> +} + +/// A view into a single occupied location in a HashMap +pub struct OccupiedEntry<'a, K:'a, V:'a> { + elem: FullBucket>, +} + +/// A view into a single empty location in a HashMap +pub struct VacantEntry<'a, K:'a, V:'a> { + hash: SafeHash, + key: K, + elem: VacantEntryState>, +} + +/// A view into a single location in a map, which may be vacant or occupied +pub enum Entry<'a, K:'a, V:'a> { + /// An occupied Entry + Occupied(OccupiedEntry<'a, K, V>), + /// A vacant Entry + Vacant(VacantEntry<'a, K, V>), +} + +/// Possible states of a VacantEntry +enum VacantEntryState { + /// The index is occupied, but the key to insert has precedence, + /// and will kick the current one out on insertion + NeqElem(FullBucket, uint), + /// The index is genuinely vacant + NoElem(EmptyBucket), +} + +impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a V)> { unimplemented!() } + #[inline] + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { unimplemented!() } + #[inline] + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl Iterator<(K, V)> for MoveEntries { + #[inline] + fn next(&mut self) -> Option<(K, V)> { unimplemented!() } + #[inline] + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl<'a, K, V> OccupiedEntry<'a, K, V> { + /// Gets a reference to the value in the entry + pub fn get(&self) -> &V { unimplemented!() } + + /// Gets a mutable reference to the value in the entry + pub fn get_mut(&mut self) -> &mut V { unimplemented!() } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself + pub fn into_mut(self) -> &'a mut V { unimplemented!() } + + /// Sets the value of the entry, and returns the entry's old value + pub fn set(&mut self, mut value: V) -> V { unimplemented!() } + + /// Takes the value out of the entry, and returns it + pub fn take(self) -> V { unimplemented!() } +} + +impl<'a, K, V> VacantEntry<'a, K, V> { + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + pub fn set(self, value: V) -> &'a mut V { unimplemented!() } +} + +/// HashMap keys iterator +pub type Keys<'a, K, V> = + iter::Map<'static, (&'a K, &'a V), &'a K, Entries<'a, K, V>>; + +/// HashMap values iterator +pub type Values<'a, K, V> = + iter::Map<'static, (&'a K, &'a V), &'a V, Entries<'a, K, V>>; + +impl, V, S, H: Hasher + Default> FromIterator<(K, V)> for HashMap { + fn from_iter>(iter: T) -> HashMap { unimplemented!() } +} + +impl, V, S, H: Hasher + Default> Extend<(K, V)> for HashMap { + fn extend>(&mut self, mut iter: T) { unimplemented!() } +} diff --git a/src/libst2/collections/hash/mod.rs b/src/libst2/collections/hash/mod.rs new file mode 100644 index 0000000000000..fa3f2d15d9dc3 --- /dev/null +++ b/src/libst2/collections/hash/mod.rs @@ -0,0 +1,15 @@ +// 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. + +//! Unordered containers, implemented as hash-tables + +pub mod map; +pub mod set; +mod table; diff --git a/src/libst2/collections/hash/set.rs b/src/libst2/collections/hash/set.rs new file mode 100644 index 0000000000000..262e0f46ab25e --- /dev/null +++ b/src/libst2/collections/hash/set.rs @@ -0,0 +1,519 @@ +// 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. +// +// ignore-lexer-test FIXME #15883 + +use borrow::BorrowFrom; +use cmp::{Eq, Equiv, PartialEq}; +use core::kinds::Sized; +use default::Default; +use fmt::Show; +use fmt; +use hash::{Hash, Hasher, RandomSipHasher}; +use iter::{Iterator, FromIterator, FilterMap, Chain, Repeat, Zip, Extend}; +use iter; +use option::{Some, None}; +use result::{Ok, Err}; + +use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; + +// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub +// FIXME(conventions): update capacity management to match other collections (no auto-shrink) + + +// Future Optimization (FIXME!) +// ============================= +// +// Iteration over zero sized values is a noop. There is no need +// for `bucket.val` in the case of HashSet. I suppose we would need HKT +// to get rid of it properly. + +/// An implementation of a hash set using the underlying representation of a +/// HashMap where the value is (). As with the `HashMap` type, a `HashSet` +/// requires that the elements implement the `Eq` and `Hash` traits. +/// +/// # Example +/// +/// ``` +/// use std::collections::HashSet; +/// // Type inference lets us omit an explicit type signature (which +/// // would be `HashSet<&str>` in this example). +/// let mut books = HashSet::new(); +/// +/// // Add some books. +/// books.insert("A Dance With Dragons"); +/// books.insert("To Kill a Mockingbird"); +/// books.insert("The Odyssey"); +/// books.insert("The Great Gatsby"); +/// +/// // Check for a specific one. +/// if !books.contains(&("The Winds of Winter")) { +/// println!("We have {} books, but The Winds of Winter ain't one.", +/// books.len()); +/// } +/// +/// // Remove a book. +/// books.remove(&"The Odyssey"); +/// +/// // Iterate over everything. +/// for book in books.iter() { +/// println!("{}", *book); +/// } +/// ``` +/// +/// The easiest way to use `HashSet` with a custom type is to derive +/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the +/// future be implied by `Eq`. +/// +/// ``` +/// use std::collections::HashSet; +/// #[deriving(Hash, Eq, PartialEq, Show)] +/// struct Viking<'a> { +/// name: &'a str, +/// power: uint, +/// } +/// +/// let mut vikings = HashSet::new(); +/// +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Einar", power: 9u }); +/// vikings.insert(Viking { name: "Olaf", power: 4u }); +/// vikings.insert(Viking { name: "Harald", power: 8u }); +/// +/// // Use derived implementation to print the vikings. +/// for x in vikings.iter() { +/// println!("{}", x); +/// } +/// ``` +#[deriving(Clone)] +pub struct HashSet { + map: HashMap +} + +impl HashSet { + /// Create an empty HashSet. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn new() -> HashSet { unimplemented!() } + + /// Create an empty HashSet with space for at least `n` elements in + /// the hash table. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::with_capacity(10); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn with_capacity(capacity: uint) -> HashSet { unimplemented!() } +} + +impl, S, H: Hasher> HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_hasher(h); + /// set.insert(2u); + /// ``` + #[inline] + pub fn with_hasher(hasher: H) -> HashSet { unimplemented!() } + + /// Create an empty HashSet with space for at least `capacity` + /// elements in the hash table, using `hasher` to hash the keys. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// use std::hash::sip::SipHasher; + /// + /// let h = SipHasher::new(); + /// let mut set = HashSet::with_capacity_and_hasher(10u, h); + /// set.insert(1i); + /// ``` + #[inline] + pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet { unimplemented!() } + + /// Reserve space for at least `n` elements in the hash table. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set: HashSet = HashSet::new(); + /// set.reserve(10); + /// ``` + pub fn reserve(&mut self, n: uint) { unimplemented!() } + + /// Deprecated: use `contains` and `BorrowFrom`. + #[deprecated = "use contains and BorrowFrom"] + #[allow(deprecated)] + pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { unimplemented!() } + + /// An iterator visiting all elements in arbitrary order. + /// Iterator element type is &'a T. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a"); + /// set.insert("b"); + /// + /// // Will print in an arbitrary order. + /// for x in set.iter() { + /// println!("{}", x); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn iter<'a>(&'a self) -> SetItems<'a, T> { unimplemented!() } + + /// Creates a consuming iterator, that is, one that moves each value out + /// of the set in arbitrary order. The set cannot be used after calling + /// this. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let mut set = HashSet::new(); + /// set.insert("a".to_string()); + /// set.insert("b".to_string()); + /// + /// // Not possible to collect to a Vec with a regular `.iter()`. + /// let v: Vec = set.into_iter().collect(); + /// + /// // Will print in an arbitrary order. + /// for x in v.iter() { + /// println!("{}", x); + /// } + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn into_iter(self) -> SetMoveItems { unimplemented!() } + + /// Visit the values representing the difference. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Can be seen as `a - b`. + /// for x in a.difference(&b) { + /// println!("{}", x); // Print 1 + /// } + /// + /// let diff: HashSet = a.difference(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1i].iter().map(|&x| x).collect()); + /// + /// // Note that difference is not symmetric, + /// // and `b - a` means something else: + /// let diff: HashSet = b.difference(&a).map(|&x| x).collect(); + /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn difference<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, H> { unimplemented!() } + + /// Visit the values representing the symmetric difference. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 4 in arbitrary order. + /// for x in a.symmetric_difference(&b) { + /// println!("{}", x); + /// } + /// + /// let diff1: HashSet = a.symmetric_difference(&b).map(|&x| x).collect(); + /// let diff2: HashSet = b.symmetric_difference(&a).map(|&x| x).collect(); + /// + /// assert_eq!(diff1, diff2); + /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) + -> Chain, SetAlgebraItems<'a, T, H>> { unimplemented!() } + + /// Visit the values representing the intersection. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 2, 3 in arbitrary order. + /// for x in a.intersection(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet = a.intersection(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn intersection<'a>(&'a self, other: &'a HashSet) + -> SetAlgebraItems<'a, T, H> { unimplemented!() } + + /// Visit the values representing the union. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); + /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); + /// + /// // Print 1, 2, 3, 4 in arbitrary order. + /// for x in a.union(&b) { + /// println!("{}", x); + /// } + /// + /// let diff: HashSet = a.union(&b).map(|&x| x).collect(); + /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn union<'a>(&'a self, other: &'a HashSet) + -> Chain, SetAlgebraItems<'a, T, H>> { unimplemented!() } + + /// Return the number of elements in the set + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert_eq!(v.len(), 0); + /// v.insert(1u); + /// assert_eq!(v.len(), 1); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn len(&self) -> uint { unimplemented!() } + + /// Returns true if the set contains no elements + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// assert!(v.is_empty()); + /// v.insert(1u); + /// assert!(!v.is_empty()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_empty(&self) -> bool { unimplemented!() } + + /// Clears the set, removing all values. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut v = HashSet::new(); + /// v.insert(1u); + /// v.clear(); + /// assert!(v.is_empty()); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn clear(&mut self) { unimplemented!() } + + /// Returns `true` if the set contains a value. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let set: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// assert_eq!(set.contains(&1), true); + /// assert_eq!(set.contains(&4), false); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn contains(&self, value: &Q) -> bool + where Q: BorrowFrom + Hash + Eq + { unimplemented!() } + + /// Returns `true` if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let mut b: HashSet = HashSet::new(); + /// + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(4); + /// assert_eq!(a.is_disjoint(&b), true); + /// b.insert(1); + /// assert_eq!(a.is_disjoint(&b), false); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_disjoint(&self, other: &HashSet) -> bool { unimplemented!() } + + /// Returns `true` if the set is a subset of another. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sup: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); + /// let mut set: HashSet = HashSet::new(); + /// + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(2); + /// assert_eq!(set.is_subset(&sup), true); + /// set.insert(4); + /// assert_eq!(set.is_subset(&sup), false); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_subset(&self, other: &HashSet) -> bool { unimplemented!() } + + /// Returns `true` if the set is a superset of another. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let sub: HashSet = [1, 2].iter().map(|&x| x).collect(); + /// let mut set: HashSet = HashSet::new(); + /// + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(0); + /// set.insert(1); + /// assert_eq!(set.is_superset(&sub), false); + /// + /// set.insert(2); + /// assert_eq!(set.is_superset(&sub), true); + /// ``` + #[inline] + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_superset(&self, other: &HashSet) -> bool { unimplemented!() } + + /// Adds a value to the set. Returns `true` if the value was not already + /// present in the set. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// assert_eq!(set.insert(2u), true); + /// assert_eq!(set.insert(2), false); + /// assert_eq!(set.len(), 1); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn insert(&mut self, value: T) -> bool { unimplemented!() } + + /// Removes a value from the set. Returns `true` if the value was + /// present in the set. + /// + /// The value may be any borrowed form of the set's value type, but + /// `Hash` and `Eq` on the borrowed form *must* match those for + /// the value type. + /// + /// # Example + /// + /// ``` + /// use std::collections::HashSet; + /// + /// let mut set = HashSet::new(); + /// + /// set.insert(2u); + /// assert_eq!(set.remove(&2), true); + /// assert_eq!(set.remove(&2), false); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn remove(&mut self, value: &Q) -> bool + where Q: BorrowFrom + Hash + Eq + { unimplemented!() } +} + +impl, S, H: Hasher> PartialEq for HashSet { + fn eq(&self, other: &HashSet) -> bool { unimplemented!() } +} + +impl, S, H: Hasher> Eq for HashSet {} + +impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl, S, H: Hasher + Default> FromIterator for HashSet { + fn from_iter>(iter: I) -> HashSet { unimplemented!() } +} + +impl, S, H: Hasher + Default> Extend for HashSet { + fn extend>(&mut self, mut iter: I) { unimplemented!() } +} + +impl, S, H: Hasher + Default> Default for HashSet { + fn default() -> HashSet { unimplemented!() } +} + +/// HashSet iterator +pub type SetItems<'a, K> = + iter::Map<'static, (&'a K, &'a ()), &'a K, Entries<'a, K, ()>>; + +/// HashSet move iterator +pub type SetMoveItems = + iter::Map<'static, (K, ()), K, MoveEntries>; + +// `Repeat` is used to feed the filter closure an explicit capture +// of a reference to the other set +/// Set operations iterator +pub type SetAlgebraItems<'a, T, H> = + FilterMap<'static, (&'a HashSet, &'a T), &'a T, + Zip>, SetItems<'a, T>>>; diff --git a/src/libst2/collections/hash/table.rs b/src/libst2/collections/hash/table.rs new file mode 100644 index 0000000000000..00bb6ce775a89 --- /dev/null +++ b/src/libst2/collections/hash/table.rs @@ -0,0 +1,408 @@ +// 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. +// +// ignore-lexer-test FIXME #15883 + +pub use self::BucketState::*; + +use clone::Clone; +use cmp; +use hash::{Hash, Hasher}; +use iter::{Iterator, count}; +use kinds::{Sized, marker}; +use mem::{min_align_of, size_of}; +use mem; +use num::{Int, UnsignedInt}; +use ops::{Deref, DerefMut, Drop}; +use option::{Some, None, Option}; +use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; +use ptr; +use rt::heap::{allocate, deallocate}; + +const EMPTY_BUCKET: u64 = 0u64; + +/// The raw hashtable, providing safe-ish access to the unzipped and highly +/// optimized arrays of hashes, keys, and values. +/// +/// This design uses less memory and is a lot faster than the naive +/// `Vec>`, because we don't pay for the overhead of an +/// option on every element, and we get a generally more cache-aware design. +/// +/// Essential invariants of this structure: +/// +/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` +/// points to 'undefined' contents. Don't read from it. This invariant is +/// enforced outside this module with the `EmptyBucket`, `FullBucket`, +/// and `SafeHash` types. +/// +/// - An `EmptyBucket` is only constructed at an index with +/// a hash of EMPTY_BUCKET. +/// +/// - A `FullBucket` is only constructed at an index with a +/// non-EMPTY_BUCKET hash. +/// +/// - A `SafeHash` is only constructed for non-`EMPTY_BUCKET` hash. We get +/// around hashes of zero by changing them to 0x8000_0000_0000_0000, +/// which will likely map to the same bucket, while not being confused +/// with "empty". +/// +/// - All three "arrays represented by pointers" are the same length: +/// `capacity`. This is set at creation and never changes. The arrays +/// are unzipped to save space (we don't have to pay for the padding +/// between odd sized elements, such as in a map from u64 to u8), and +/// be more cache aware (scanning through 8 hashes brings in at most +/// 2 cache lines, since they're all right beside each other). +/// +/// You can kind of think of this module/data structure as a safe wrapper +/// around just the "table" part of the hashtable. It enforces some +/// invariants at the type level and employs some performance trickery, +/// but in general is just a tricked out `Vec>`. +#[unsafe_no_drop_flag] +pub struct RawTable { + capacity: uint, + size: uint, + hashes: *mut u64, + // Because K/V do not appear directly in any of the types in the struct, + // inform rustc that in fact instances of K and V are reachable from here. + marker: marker::CovariantType<(K,V)>, +} + +struct RawBucket { + hash: *mut u64, + key: *mut K, + val: *mut V +} + +pub struct Bucket { + raw: RawBucket, + idx: uint, + table: M +} + +pub struct EmptyBucket { + raw: RawBucket, + idx: uint, + table: M +} + +pub struct FullBucket { + raw: RawBucket, + idx: uint, + table: M +} + +pub type EmptyBucketImm<'table, K, V> = EmptyBucket>; +pub type FullBucketImm<'table, K, V> = FullBucket>; + +pub type EmptyBucketMut<'table, K, V> = EmptyBucket>; +pub type FullBucketMut<'table, K, V> = FullBucket>; + +pub enum BucketState { + Empty(EmptyBucket), + Full(FullBucket), +} + +// A GapThenFull encapsulates the state of two consecutive buckets at once. +// The first bucket, called the gap, is known to be empty. +// The second bucket is full. +struct GapThenFull { + gap: EmptyBucket, + full: FullBucket, +} + +/// A hash that is not zero, since we use a hash of zero to represent empty +/// buckets. +#[deriving(PartialEq)] +pub struct SafeHash { + hash: u64, +} + +impl SafeHash { + /// Peek at the hash value, which is guaranteed to be non-zero. + #[inline(always)] + pub fn inspect(&self) -> u64 { unimplemented!() } +} + +/// We need to remove hashes of 0. That's reserved for empty buckets. +/// This function wraps up `hash_keyed` to be the only way outside this +/// module to generate a SafeHash. +pub fn make_hash, S, H: Hasher>(hasher: &H, t: &T) -> SafeHash { unimplemented!() } + +// `replace` casts a `*u64` to a `*SafeHash`. Since we statically +// ensure that a `FullBucket` points to an index with a non-zero hash, +// and a `SafeHash` is just a `u64` with a different name, this is +// safe. +// +// This test ensures that a `SafeHash` really IS the same size as a +// `u64`. If you need to change the size of `SafeHash` (and +// consequently made this test fail), `replace` needs to be +// modified to no longer assume this. +#[test] +fn can_alias_safehash_as_u64() { unimplemented!() } + +impl RawBucket { + unsafe fn offset(self, count: int) -> RawBucket { unimplemented!() } +} + +// Buckets hold references to the table. +impl FullBucket { + /// Borrow a reference to the table. + pub fn table(&self) -> &M { unimplemented!() } + /// Move out the reference to the table. + pub fn into_table(self) -> M { unimplemented!() } + /// Get the raw index. + pub fn index(&self) -> uint { unimplemented!() } +} + +impl EmptyBucket { + /// Borrow a reference to the table. + pub fn table(&self) -> &M { unimplemented!() } + /// Move out the reference to the table. + pub fn into_table(self) -> M { unimplemented!() } +} + +impl Bucket { + /// Move out the reference to the table. + pub fn into_table(self) -> M { unimplemented!() } + /// Get the raw index. + pub fn index(&self) -> uint { unimplemented!() } +} + +impl>> Bucket { + pub fn new(table: M, hash: &SafeHash) -> Bucket { unimplemented!() } + + pub fn at_index(table: M, ib_index: uint) -> Bucket { unimplemented!() } + + pub fn first(table: M) -> Bucket { unimplemented!() } + + /// Reads a bucket at a given index, returning an enum indicating whether + /// it's initialized or not. You need to match on this enum to get + /// the appropriate types to call most of the other functions in + /// this module. + pub fn peek(self) -> BucketState { unimplemented!() } + + /// Modifies the bucket pointer in place to make it point to the next slot. + pub fn next(&mut self) { unimplemented!() } +} + +impl>> EmptyBucket { + #[inline] + pub fn next(self) -> Bucket { unimplemented!() } + + #[inline] + pub fn into_bucket(self) -> Bucket { unimplemented!() } + + pub fn gap_peek(self) -> Option> { unimplemented!() } +} + +impl>> EmptyBucket { + /// Puts given key and value pair, along with the key's hash, + /// into this bucket in the hashtable. Note how `self` is 'moved' into + /// this function, because this slot will no longer be empty when + /// we return! A `FullBucket` is returned for later use, pointing to + /// the newly-filled slot in the hashtable. + /// + /// Use `make_hash` to construct a `SafeHash` to pass to this function. + pub fn put(mut self, hash: SafeHash, key: K, value: V) + -> FullBucket { unimplemented!() } +} + +impl>> FullBucket { + #[inline] + pub fn next(self) -> Bucket { unimplemented!() } + + #[inline] + pub fn into_bucket(self) -> Bucket { unimplemented!() } + + /// Get the distance between this bucket and the 'ideal' location + /// as determined by the key's hash stored in it. + /// + /// In the cited blog posts above, this is called the "distance to + /// initial bucket", or DIB. Also known as "probe count". + pub fn distance(&self) -> uint { unimplemented!() } + + #[inline] + pub fn hash(&self) -> SafeHash { unimplemented!() } + + /// Gets references to the key and value at a given index. + pub fn read(&self) -> (&K, &V) { unimplemented!() } +} + +impl>> FullBucket { + /// Removes this bucket's key and value from the hashtable. + /// + /// This works similarly to `put`, building an `EmptyBucket` out of the + /// taken bucket. + pub fn take(mut self) -> (EmptyBucket, K, V) { unimplemented!() } + + pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unimplemented!() } + + /// Gets mutable references to the key and value at a given index. + pub fn read_mut(&mut self) -> (&mut K, &mut V) { unimplemented!() } +} + +impl<'t, K, V, M: Deref> + 't> FullBucket { + /// Exchange a bucket state for immutable references into the table. + /// Because the underlying reference to the table is also consumed, + /// no further changes to the structure of the table are possible; + /// in exchange for this, the returned references have a longer lifetime + /// than the references returned by `read()`. + pub fn into_refs(self) -> (&'t K, &'t V) { unimplemented!() } +} + +impl<'t, K, V, M: DerefMut> + 't> FullBucket { + /// This works similarly to `into_refs`, exchanging a bucket state + /// for mutable references into the table. + pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { unimplemented!() } +} + +impl BucketState { + // For convenience. + pub fn expect_full(self) -> FullBucket { unimplemented!() } +} + +impl>> GapThenFull { + #[inline] + pub fn full(&self) -> &FullBucket { unimplemented!() } + + pub fn shift(mut self) -> Option> { unimplemented!() } +} + + +/// Rounds up to a multiple of a power of two. Returns the closest multiple +/// of `target_alignment` that is higher or equal to `unrounded`. +/// +/// # Panics +/// +/// Panics if `target_alignment` is not a power of two. +fn round_up_to_next(unrounded: uint, target_alignment: uint) -> uint { unimplemented!() } + +#[test] +fn test_rounding() { unimplemented!() } + +// Returns a tuple of (key_offset, val_offset), +// from the start of a mallocated array. +fn calculate_offsets(hashes_size: uint, + keys_size: uint, keys_align: uint, + vals_align: uint) + -> (uint, uint) { unimplemented!() } + +// Returns a tuple of (minimum required malloc alignment, hash_offset, +// array_size), from the start of a mallocated array. +fn calculate_allocation(hash_size: uint, hash_align: uint, + keys_size: uint, keys_align: uint, + vals_size: uint, vals_align: uint) + -> (uint, uint, uint) { unimplemented!() } + +#[test] +fn test_offset_calculation() { unimplemented!() } + +impl RawTable { + /// Does not initialize the buckets. The caller should ensure they, + /// at the very least, set every hash to EMPTY_BUCKET. + unsafe fn new_uninitialized(capacity: uint) -> RawTable { unimplemented!() } + + fn first_bucket_raw(&self) -> RawBucket { unimplemented!() } + + /// Creates a new raw table from a given capacity. All buckets are + /// initially empty. + #[allow(experimental)] + pub fn new(capacity: uint) -> RawTable { unimplemented!() } + + /// The hashtable's capacity, similar to a vector's. + pub fn capacity(&self) -> uint { unimplemented!() } + + /// The number of elements ever `put` in the hashtable, minus the number + /// of elements ever `take`n. + pub fn size(&self) -> uint { unimplemented!() } + + fn raw_buckets(&self) -> RawBuckets { unimplemented!() } + + pub fn iter(&self) -> Entries { unimplemented!() } + + pub fn iter_mut(&mut self) -> MutEntries { unimplemented!() } + + pub fn into_iter(self) -> MoveEntries { unimplemented!() } + + /// Returns an iterator that copies out each entry. Used while the table + /// is being dropped. + unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets { unimplemented!() } +} + +/// A raw iterator. The basis for some other iterators in this module. Although +/// this interface is safe, it's not used outside this module. +struct RawBuckets<'a, K, V> { + raw: RawBucket, + hashes_end: *mut u64, + marker: marker::ContravariantLifetime<'a>, +} + +impl<'a, K, V> Iterator> for RawBuckets<'a, K, V> { + fn next(&mut self) -> Option> { unimplemented!() } +} + +/// An iterator that moves out buckets in reverse order. It leaves the table +/// in an inconsistent state and should only be used for dropping +/// the table's remaining entries. It's used in the implementation of Drop. +struct RevMoveBuckets<'a, K, V> { + raw: RawBucket, + hashes_end: *mut u64, + elems_left: uint, + marker: marker::ContravariantLifetime<'a>, +} + +impl<'a, K, V> Iterator<(K, V)> for RevMoveBuckets<'a, K, V> { + fn next(&mut self) -> Option<(K, V)> { unimplemented!() } +} + +/// Iterator over shared references to entries in a table. +pub struct Entries<'a, K: 'a, V: 'a> { + iter: RawBuckets<'a, K, V>, + elems_left: uint, +} + +/// Iterator over mutable references to entries in a table. +pub struct MutEntries<'a, K: 'a, V: 'a> { + iter: RawBuckets<'a, K, V>, + elems_left: uint, +} + +/// Iterator over the entries in a table, consuming the table. +pub struct MoveEntries { + table: RawTable, + iter: RawBuckets<'static, K, V> +} + +impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { + fn next(&mut self) -> Option<(&'a K, &'a V)> { unimplemented!() } + + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { + fn next(&mut self) -> Option<(&'a K, &'a mut V)> { unimplemented!() } + + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl Iterator<(SafeHash, K, V)> for MoveEntries { + fn next(&mut self) -> Option<(SafeHash, K, V)> { unimplemented!() } + + fn size_hint(&self) -> (uint, Option) { unimplemented!() } +} + +impl Clone for RawTable { + fn clone(&self) -> RawTable { unimplemented!() } +} + +#[unsafe_destructor] +impl Drop for RawTable { + fn drop(&mut self) { unimplemented!() } +} diff --git a/src/libst2/collections/lru_cache.rs b/src/libst2/collections/lru_cache.rs new file mode 100644 index 0000000000000..29535c0941e22 --- /dev/null +++ b/src/libst2/collections/lru_cache.rs @@ -0,0 +1,245 @@ +// Copyright 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. + + +//! A cache that holds a limited number of key-value pairs. When the +//! capacity of the cache is exceeded, the least-recently-used +//! (where "used" means a look-up or putting the pair into the cache) +//! pair is automatically removed. +//! +//! # Example +//! +//! ```rust +//! use std::collections::LruCache; +//! +//! let mut cache: LruCache = LruCache::new(2); +//! cache.insert(1, 10); +//! cache.insert(2, 20); +//! cache.insert(3, 30); +//! assert!(cache.get(&1).is_none()); +//! assert_eq!(*cache.get(&2).unwrap(), 20); +//! assert_eq!(*cache.get(&3).unwrap(), 30); +//! +//! cache.insert(2, 22); +//! assert_eq!(*cache.get(&2).unwrap(), 22); +//! +//! cache.insert(6, 60); +//! assert!(cache.get(&3).is_none()); +//! +//! cache.set_capacity(1); +//! assert!(cache.get(&2).is_none()); +//! ``` + +use cmp::{PartialEq, Eq}; +use collections::HashMap; +use fmt; +use hash::Hash; +use iter::{range, Iterator, Extend}; +use mem; +use ops::Drop; +use option::{Some, None, Option}; +use boxed::Box; +use ptr; +use result::{Ok, Err}; + +// FIXME(conventions): implement iterators? +// FIXME(conventions): implement indexing? + +struct KeyRef { k: *const K } + +struct LruEntry { + next: *mut LruEntry, + prev: *mut LruEntry, + key: K, + value: V, +} + +/// An LRU Cache. +pub struct LruCache { + map: HashMap, Box>>, + max_size: uint, + head: *mut LruEntry, +} + +impl> Hash for KeyRef { + fn hash(&self, state: &mut S) { unimplemented!() } +} + +impl PartialEq for KeyRef { + fn eq(&self, other: &KeyRef) -> bool { unimplemented!() } +} + +impl Eq for KeyRef {} + +impl LruEntry { + fn new(k: K, v: V) -> LruEntry { unimplemented!() } +} + +impl LruCache { + /// Create an LRU Cache that holds at most `capacity` items. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache: LruCache = LruCache::new(10); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn new(capacity: uint) -> LruCache { unimplemented!() } + + /// Deprecated: Replaced with `insert`. + #[deprecated = "Replaced with `insert`"] + pub fn put(&mut self, k: K, v: V) { unimplemented!() } + + /// Inserts a key-value pair into the cache. If the key already existed, the old value is + /// returned. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.insert(1i, "a"); + /// cache.insert(2, "b"); + /// assert_eq!(cache.get(&1), Some(&"a")); + /// assert_eq!(cache.get(&2), Some(&"b")); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn insert(&mut self, k: K, v: V) -> Option { unimplemented!() } + + /// Return a value corresponding to the key in the cache. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.insert(1i, "a"); + /// cache.insert(2, "b"); + /// cache.insert(2, "c"); + /// cache.insert(3, "d"); + /// + /// assert_eq!(cache.get(&1), None); + /// assert_eq!(cache.get(&2), Some(&"c")); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn get(&mut self, k: &K) -> Option<&V> { unimplemented!() } + + /// Deprecated: Renamed to `remove`. + #[deprecated = "Renamed to `remove`"] + pub fn pop(&mut self, k: &K) -> Option { unimplemented!() } + + /// Remove and return a value corresponding to the key from the cache. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.insert(2i, "a"); + /// + /// assert_eq!(cache.remove(&1), None); + /// assert_eq!(cache.remove(&2), Some("a")); + /// assert_eq!(cache.remove(&2), None); + /// assert_eq!(cache.len(), 0); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn remove(&mut self, k: &K) -> Option { unimplemented!() } + + /// Return the maximum number of key-value pairs the cache can hold. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache: LruCache = LruCache::new(2); + /// assert_eq!(cache.capacity(), 2); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn capacity(&self) -> uint { unimplemented!() } + + /// Deprecated: Renamed to `set_capacity`. + #[deprecated = "Renamed to `set_capacity`"] + pub fn change_capacity(&mut self, capacity: uint) { unimplemented!() } + + /// Change the number of key-value pairs the cache can hold. Remove + /// least-recently-used key-value pairs if necessary. + /// + /// # Example + /// + /// ``` + /// use std::collections::LruCache; + /// let mut cache = LruCache::new(2); + /// + /// cache.insert(1i, "a"); + /// cache.insert(2, "b"); + /// cache.insert(3, "c"); + /// + /// assert_eq!(cache.get(&1), None); + /// assert_eq!(cache.get(&2), Some(&"b")); + /// assert_eq!(cache.get(&3), Some(&"c")); + /// + /// cache.set_capacity(3); + /// cache.insert(1i, "a"); + /// cache.insert(2, "b"); + /// + /// assert_eq!(cache.get(&1), Some(&"a")); + /// assert_eq!(cache.get(&2), Some(&"b")); + /// assert_eq!(cache.get(&3), Some(&"c")); + /// + /// cache.set_capacity(1); + /// + /// assert_eq!(cache.get(&1), None); + /// assert_eq!(cache.get(&2), None); + /// assert_eq!(cache.get(&3), Some(&"c")); + /// ``` + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn set_capacity(&mut self, capacity: uint) { unimplemented!() } + + #[inline] + fn remove_lru(&mut self) { unimplemented!() } + + #[inline] + fn detach(&mut self, node: *mut LruEntry) { unimplemented!() } + + #[inline] + fn attach(&mut self, node: *mut LruEntry) { unimplemented!() } + + /// Return the number of key-value pairs in the cache. + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn len(&self) -> uint { unimplemented!() } + + /// Returns whether the cache is currently empty. + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn is_empty(&self) -> bool { unimplemented!() } + + /// Clear the cache of all key-value pairs. + #[unstable = "matches collection reform specification, waiting for dust to settle"] + pub fn clear(&mut self) { unimplemented!() } + +} + +impl Extend<(K, V)> for LruCache { + fn extend>(&mut self, mut iter: T) { unimplemented!() } +} + +impl fmt::Show for LruCache { + /// Return a string that lists the key-value pairs from most-recently + /// used to least-recently used. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +#[unsafe_destructor] +impl Drop for LruCache { + fn drop(&mut self) { unimplemented!() } +} diff --git a/src/libst2/collections/mod.rs b/src/libst2/collections/mod.rs new file mode 100644 index 0000000000000..3419a3d98a154 --- /dev/null +++ b/src/libst2/collections/mod.rs @@ -0,0 +1,354 @@ +// Copyright 2013-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. + +//! Collection types. +//! +//! Rust's standard collection library provides efficient implementations of the most common +//! general purpose programming data structures. By using the standard implementations, +//! it should be possible for two libraries to communicate without significant data conversion. +//! +//! To get this out of the way: you should probably just use `Vec` or `HashMap`. These two +//! collections cover most use cases for generic data storage and processing. They are +//! exceptionally good at doing what they do. All the other collections in the standard +//! library have specific use cases where they are the optimal choice, but these cases are +//! borderline *niche* in comparison. Even when `Vec` and `HashMap` are technically suboptimal, +//! they're probably a good enough choice to get started. +//! +//! Rust's collections can be grouped into four major categories: +//! +//! * Sequences: `Vec`, `RingBuf`, `DList`, `BitV` +//! * Maps: `HashMap`, `BTreeMap`, `TreeMap`, `TrieMap`, `VecMap`, `LruCache` +//! * Sets: `HashSet`, `BTreeSet`, `TreeSet`, `TrieSet`, `BitVSet`, `EnumSet` +//! * Misc: `BinaryHeap` +//! +//! # When Should You Use Which Collection? +//! +//! These are fairly high-level and quick break-downs of when each collection should be +//! considered. Detailed discussions of strengths and weaknesses of individual collections +//! can be found on their own documentation pages. +//! +//! ### Use a `Vec` when: +//! * You want to collect items up to be processed or sent elsewhere later, and don't care about +//! any properties of the actual values being stored. +//! * You want a sequence of elements in a particular order, and will only be appending to +//! (or near) the end. +//! * You want a stack. +//! * You want a resizable array. +//! * You want a heap-allocated array. +//! +//! ### Use a `RingBuf` when: +//! * You want a `Vec` that supports efficient insertion at both ends of the sequence. +//! * You want a queue. +//! * You want a double-ended queue (deque). +//! +//! ### Use a `DList` when: +//! * You want a `Vec` or `RingBuf` of unknown size, and can't tolerate inconsistent +//! performance during insertions. +//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked list. +//! +//! ### Use a `HashMap` when: +//! * You want to associate arbitrary keys with an arbitrary value. +//! * You want a cache. +//! * You want a map, with no extra functionality. +//! +//! ### Use a `BTreeMap` when: +//! * You're interested in what the smallest or largest key-value pair is. +//! * You want to find the largest or smallest key that is smaller or larger than something +//! * You want to be able to get all of the entries in order on-demand. +//! * You want a sorted map. +//! +//! ### Use a `TreeMap` when: +//! * You want a `BTreeMap`, but can't tolerate inconsistent performance. +//! * You want a `BTreeMap`, but have *very large* keys or values. +//! * You want a `BTreeMap`, but have keys that are expensive to compare. +//! * You want a `BTreeMap`, but you accept arbitrary untrusted inputs. +//! +//! ### Use a `TrieMap` when: +//! * You want a `HashMap`, but with many potentially large `uint` keys. +//! * You want a `BTreeMap`, but with potentially large `uint` keys. +//! +//! ### Use a `VecMap` when: +//! * You want a `HashMap` but with known to be small `uint` keys. +//! * You want a `BTreeMap`, but with known to be small `uint` keys. +//! +//! ### Use the `Set` variant of any of these `Map`s when: +//! * You just want to remember which keys you've seen. +//! * There is no meaningful value to associate with your keys. +//! * You just want a set. +//! +//! ### Use a `BitV` when: +//! * You want to store an unbounded number of booleans in a small space. +//! * You want a bitvector. +//! +//! ### Use a `BitVSet` when: +//! * You want a `VecSet`. +//! +//! ### Use an `EnumSet` when: +//! * You want a C-like enum, stored in a single `uint`. +//! +//! ### Use a `BinaryHeap` when: +//! * You want to store a bunch of elements, but only ever want to process the "biggest" +//! or "most important" one at any given time. +//! * You want a priority queue. +//! +//! ### Use an `LruCache` when: +//! * You want a cache that discards infrequently used items when it becomes full. +//! * You want a least-recently-used cache. +//! +//! # Correct and Efficient Usage of Collections +//! +//! Of course, knowing which collection is the right one for the job doesn't instantly +//! permit you to use it correctly. Here are some quick tips for efficient and correct +//! usage of the standard collections in general. If you're interested in how to use a +//! specific collection in particular, consult its documentation for detailed discussion +//! and code examples. +//! +//! ## Capacity Management +//! +//! Many collections provide several constructors and methods that refer to "capacity". +//! These collections are generally built on top of an array. Optimally, this array would be +//! exactly the right size to fit only the elements stored in the collection, but for the +//! collection to do this would be very inefficient. If the backing array was exactly the +//! right size at all times, then every time an element is inserted, the collection would +//! have to grow the array to fit it. Due to the way memory is allocated and managed on most +//! computers, this would almost surely require allocating an entirely new array and +//! copying every single element from the old one into the new one. Hopefully you can +//! see that this wouldn't be very efficient to do on every operation. +//! +//! Most collections therefore use an *amortized* allocation strategy. They generally let +//! themselves have a fair amount of unoccupied space so that they only have to grow +//! on occasion. When they do grow, they allocate a substantially larger array to move +//! the elements into so that it will take a while for another grow to be required. While +//! this strategy is great in general, it would be even better if the collection *never* +//! had to resize its backing array. Unfortunately, the collection itself doesn't have +//! enough information to do this itself. Therefore, it is up to us programmers to give it +//! hints. +//! +//! Any `with_capacity` constructor will instruct the collection to allocate enough space +//! for the specified number of elements. Ideally this will be for exactly that many +//! elements, but some implementation details may prevent this. `Vec` and `RingBuf` can +//! be relied on to allocate exactly the requested amount, though. Use `with_capacity` +//! when you know exactly how many elements will be inserted, or at least have a +//! reasonable upper-bound on that number. +//! +//! When anticipating a large influx of elements, the `reserve` family of methods can +//! be used to hint to the collection how much room it should make for the coming items. +//! As with `with_capacity`, the precise behavior of these methods will be specific to +//! the collection of interest. +//! +//! For optimal performance, collections will generally avoid shrinking themselves. +//! If you believe that a collection will not soon contain any more elements, or +//! just really need the memory, the `shrink_to_fit` method prompts the collection +//! to shrink the backing array to the minimum size capable of holding its elements. +//! +//! Finally, if ever you're interested in what the actual capacity of the collection is, +//! most collections provide a `capacity` method to query this information on demand. +//! This can be useful for debugging purposes, or for use with the `reserve` methods. +//! +//! ## Iterators +//! +//! Iterators are a powerful and robust mechanism used throughout Rust's standard +//! libraries. Iterators provide a sequence of values in a generic, safe, efficient +//! and convenient way. The contents of an iterator are usually *lazily* evaluated, +//! so that only the values that are actually needed are ever actually produced, and +//! no allocation need be done to temporarily store them. Iterators are primarily +//! consumed using a `for` loop, although many functions also take iterators where +//! a collection or sequence of values is desired. +//! +//! All of the standard collections provide several iterators for performing bulk +//! manipulation of their contents. The three primary iterators almost every collection +//! should provide are `iter`, `iter_mut`, and `into_iter`. Some of these are not +//! provided on collections where it would be unsound or unreasonable to provide them. +//! +//! `iter` provides an iterator of immutable references to all the contents of a +//! collection in the most "natural" order. For sequence collections like `Vec`, this +//! means the items will be yielded in increasing order of index starting at 0. For ordered +//! collections like `BTreeMap`, this means that the items will be yielded in sorted order. +//! For unordered collections like `HashMap`, the items will be yielded in whatever order +//! the internal representation made most convenient. This is great for reading through +//! all the contents of the collection. +//! +//! ``` +//! let vec = vec![1u, 2, 3, 4]; +//! for x in vec.iter() { +//! println!("vec contained {}", x); +//! } +//! ``` +//! +//! `iter_mut` provides an iterator of *mutable* references in the same order as `iter`. +//! This is great for mutating all the contents of the collection. +//! +//! ``` +//! let mut vec = vec![1u, 2, 3, 4]; +//! for x in vec.iter_mut() { +//! *x += 1; +//! } +//! ``` +//! +//! `into_iter` transforms the actual collection into an iterator over its contents +//! by-value. This is great when the collection itself is no longer needed, and the +//! values are needed elsewhere. Using `extend` with `into_iter` is the main way that +//! contents of one collection are moved into another. Calling `collect` on an iterator +//! itself is also a great way to convert one collection into another. Both of these +//! methods should internally use the capacity management tools discussed in the +//! previous section to do this as efficiently as possible. +//! +//! ``` +//! let mut vec1 = vec![1u, 2, 3, 4]; +//! let vec2 = vec![10u, 20, 30, 40]; +//! vec1.extend(vec2.into_iter()); +//! ``` +//! +//! ``` +//! use std::collections::RingBuf; +//! +//! let vec = vec![1u, 2, 3, 4]; +//! let buf: RingBuf = vec.into_iter().collect(); +//! ``` +//! +//! Iterators also provide a series of *adapter* methods for performing common tasks to +//! sequences. Among the adapters are functional favorites like `map`, `fold`, `skip`, +//! and `take`. Of particular interest to collections is the `rev` adapter, that +//! reverses any iterator that supports this operation. Most collections provide reversible +//! iterators as the way to iterate over them in reverse order. +//! +//! ``` +//! let vec = vec![1u, 2, 3, 4]; +//! for x in vec.iter().rev() { +//! println!("vec contained {}", x); +//! } +//! ``` +//! +//! Several other collection methods also return iterators to yield a sequence of results +//! but avoid allocating an entire collection to store the result in. This provides maximum +//! flexibility as `collect` or `extend` can be called to "pipe" the sequence into any +//! collection if desired. Otherwise, the sequence can be looped over with a `for` loop. The +//! iterator can also be discarded after partial use, preventing the computation of the unused +//! items. +//! +//! ## Entries +//! +//! The `entry` API is intended to provide an efficient mechanism for manipulating +//! the contents of a map conditionally on the presence of a key or not. The primary +//! motivating use case for this is to provide efficient accumulator maps. For instance, +//! if one wishes to maintain a count of the number of times each key has been seen, +//! they will have to perform some conditional logic on whether this is the first time +//! the key has been seen or not. Normally, this would require a `find` followed by an +//! `insert`, effectively duplicating the search effort on each insertion. +//! +//! When a user calls `map.entry(key)`, the map will search for the key and then yield +//! a variant of the `Entry` enum. +//! +//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the +//! only valid operation is to `set` the value of the entry. When this is done, +//! the vacant entry is consumed and converted into a mutable reference to the +//! the value that was inserted. This allows for further manipulation of the value +//! beyond the lifetime of the search itself. This is useful if complex logic needs to +//! be performed on the value regardless of whether the value was just inserted. +//! +//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, the user +//! has several options: they can `get`, `set`, or `take` the value of the occupied +//! entry. Additionally, they can convert the occupied entry into a mutable reference +//! to its value, providing symmetry to the vacant `set` case. +//! +//! ### Examples +//! +//! Here are the two primary ways in which `entry` is used. First, a simple example +//! where the logic performed on the values is trivial. +//! +//! #### Counting the number of times each character in a string occurs +//! +//! ``` +//! use std::collections::btree_map::{BTreeMap, Occupied, Vacant}; +//! +//! let mut count = BTreeMap::new(); +//! let message = "she sells sea shells by the sea shore"; +//! +//! for c in message.chars() { +//! match count.entry(c) { +//! Vacant(entry) => { entry.set(1u); }, +//! Occupied(mut entry) => *entry.get_mut() += 1, +//! } +//! } +//! +//! assert_eq!(count.get(&'s'), Some(&8)); +//! +//! println!("Number of occurences of each character"); +//! for (char, count) in count.iter() { +//! println!("{}: {}", char, count); +//! } +//! ``` +//! +//! When the logic to be performed on the value is more complex, we may simply use +//! the `entry` API to ensure that the value is initialized, and perform the logic +//! afterwards. +//! +//! #### Tracking the inebriation of customers at a bar +//! +//! ``` +//! use std::collections::btree_map::{BTreeMap, Occupied, Vacant}; +//! +//! // A client of the bar. They have an id and a blood alcohol level. +//! struct Person { id: u32, blood_alcohol: f32 }; +//! +//! // All the orders made to the bar, by client id. +//! let orders = vec![1,2,1,2,3,4,1,2,2,3,4,1,1,1]; +//! +//! // Our clients. +//! let mut blood_alcohol = BTreeMap::new(); +//! +//! for id in orders.into_iter() { +//! // If this is the first time we've seen this customer, initialize them +//! // with no blood alcohol. Otherwise, just retrieve them. +//! let person = match blood_alcohol.entry(id) { +//! Vacant(entry) => entry.set(Person{id: id, blood_alcohol: 0.0}), +//! Occupied(entry) => entry.into_mut(), +//! }; +//! +//! // Reduce their blood alcohol level. It takes time to order and drink a beer! +//! person.blood_alcohol *= 0.9; +//! +//! // Check if they're sober enough to have another beer. +//! if person.blood_alcohol > 0.3 { +//! // Too drunk... for now. +//! println!("Sorry {}, I have to cut you off", person.id); +//! } else { +//! // Have another! +//! person.blood_alcohol += 0.1; +//! } +//! } +//! ``` + +#![experimental] + +pub use core_collections::{BinaryHeap, Bitv, BitvSet, BTreeMap, BTreeSet}; +pub use core_collections::{DList, EnumSet, RingBuf}; +pub use core_collections::{TreeMap, TreeSet, TrieMap, TrieSet, VecMap}; + +pub use core_collections::{binary_heap, bitv, bitv_set, btree_map, btree_set, dlist, enum_set}; +pub use core_collections::{ring_buf, tree_map, tree_set, trie_map, trie_set, vec_map}; + +pub use self::hash_map::HashMap; +pub use self::hash_set::HashSet; +pub use self::lru_cache::LruCache; + +mod hash; + +pub mod hash_map { + //! A hashmap + pub use super::hash::map::*; +} + +pub mod hash_set { + //! A hashset + pub use super::hash::set::*; +} + +pub mod lru_cache; diff --git a/src/libst2/dynamic_lib.rs b/src/libst2/dynamic_lib.rs new file mode 100644 index 0000000000000..f84bedaabba0e --- /dev/null +++ b/src/libst2/dynamic_lib.rs @@ -0,0 +1,154 @@ +// Copyright 2013-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. + +/*! + +Dynamic library facilities. + +A simple wrapper over the platform's dynamic library facilities + +*/ + +#![experimental] +#![allow(missing_docs)] + +use clone::Clone; +use c_str::ToCStr; +use iter::Iterator; +use mem; +use ops::*; +use option::*; +use os; +use path::{Path,GenericPath}; +use result::*; +use slice::{AsSlice,SlicePrelude}; +use str; +use string::String; +use vec::Vec; + +pub struct DynamicLibrary { handle: *mut u8 } + +impl Drop for DynamicLibrary { + fn drop(&mut self) { unimplemented!() } +} + +impl DynamicLibrary { + // FIXME (#12938): Until DST lands, we cannot decompose &str into + // & and str, so we cannot usefully take ToCStr arguments by + // reference (without forcing an additional & around &str). So we + // are instead temporarily adding an instance for &Path, so that + // we can take ToCStr as owned. When DST lands, the &Path instance + // should be removed, and arguments bound by ToCStr should be + // passed by reference. (Here: in the `open` method.) + + /// Lazily open a dynamic library. When passed None it gives a + /// handle to the calling process + pub fn open(filename: Option) + -> Result { unimplemented!() } + + /// Prepends a path to this process's search path for dynamic libraries + pub fn prepend_search_path(path: &Path) { unimplemented!() } + + /// From a slice of paths, create a new vector which is suitable to be an + /// environment variable for this platforms dylib search path. + pub fn create_path(path: &[Path]) -> Vec { unimplemented!() } + + /// Returns the environment variable for this process's dynamic library + /// search path + pub fn envvar() -> &'static str { unimplemented!() } + + fn separator() -> u8 { unimplemented!() } + + /// Returns the current search path for dynamic libraries being used by this + /// process + pub fn search_path() -> Vec { unimplemented!() } + + /// Access the value at the symbol of the dynamic library + pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { unimplemented!() } +} + +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub mod dl { + pub use self::Rtld::*; + + use c_str::{CString, ToCStr}; + use libc; + use ptr; + use result::*; + use string::String; + + pub unsafe fn open_external(filename: T) -> *mut u8 { unimplemented!() } + + pub unsafe fn open_internal() -> *mut u8 { unimplemented!() } + + pub fn check_for_errors_in(f: || -> T) -> Result { unimplemented!() } + + pub unsafe fn symbol(handle: *mut u8, + symbol: *const libc::c_char) -> *mut u8 { unimplemented!() } + pub unsafe fn close(handle: *mut u8) { unimplemented!() } + + pub enum Rtld { + Lazy = 1, + Now = 2, + Global = 256, + Local = 0, + } + + #[link_name = "dl"] + extern { + fn dlopen(filename: *const libc::c_char, + flag: libc::c_int) -> *mut libc::c_void; + fn dlerror() -> *mut libc::c_char; + fn dlsym(handle: *mut libc::c_void, + symbol: *const libc::c_char) -> *mut libc::c_void; + fn dlclose(handle: *mut libc::c_void) -> libc::c_int; + } +} + +#[cfg(target_os = "windows")] +pub mod dl { + use c_str::ToCStr; + use iter::Iterator; + use libc; + use os; + use ptr; + use result::{Ok, Err, Result}; + use slice::SlicePrelude; + use str::StrPrelude; + use str; + use string::String; + use vec::Vec; + + pub unsafe fn open_external(filename: T) -> *mut u8 { unimplemented!() } + + pub unsafe fn open_internal() -> *mut u8 { unimplemented!() } + + pub fn check_for_errors_in(f: || -> T) -> Result { unimplemented!() } + + pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 { unimplemented!() } + pub unsafe fn close(handle: *mut u8) { unimplemented!() } + + #[allow(non_snake_case)] + extern "system" { + fn SetLastError(error: libc::size_t); + fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void; + fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16, + handle: *mut *mut libc::c_void) + -> *mut libc::c_void; + fn GetProcAddress(handle: *mut libc::c_void, + name: *const libc::c_char) -> *mut libc::c_void; + fn FreeLibrary(handle: *mut libc::c_void); + } +} diff --git a/src/libst2/error.rs b/src/libst2/error.rs new file mode 100644 index 0000000000000..8c224c479a18e --- /dev/null +++ b/src/libst2/error.rs @@ -0,0 +1,106 @@ +// 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. + +//! Traits for working with Errors. +//! +//! # The `Error` trait +//! +//! `Error` is a trait representing the basic expectations for error values, +//! i.e. values of type `E` in `Result`. At a minimum, errors must provide +//! a description, but they may optionally provide additional detail and cause +//! chain information: +//! +//! ``` +//! trait Error: Send { +//! fn description(&self) -> &str; +//! +//! fn detail(&self) -> Option { None } +//! fn cause(&self) -> Option<&Error> { None } +//! } +//! ``` +//! +//! The `cause` method is generally used when errors cross "abstraction +//! boundaries", i.e. when a one module must report an error that is "caused" +//! by an error from a lower-level module. This setup makes it possible for the +//! high-level module to provide its own errors that do not commit to any +//! particular implementation, but also reveal some of its implementation for +//! debugging via `cause` chains. +//! +//! # The `FromError` trait +//! +//! `FromError` is a simple trait that expresses conversions between different +//! error types. To provide maximum flexibility, it does not require either of +//! the types to actually implement the `Error` trait, although this will be the +//! common case. +//! +//! The main use of this trait is in the `try!` macro, which uses it to +//! automatically convert a given error to the error specified in a function's +//! return type. +//! +//! For example, +//! +//! ``` +//! use std::error::FromError; +//! use std::io::{File, IoError}; +//! use std::os::{MemoryMap, MapError}; +//! use std::path::Path; +//! +//! enum MyError { +//! Io(IoError), +//! Map(MapError) +//! } +//! +//! impl FromError for MyError { +//! fn from_error(err: IoError) -> MyError { +//! MyError::Io(err) +//! } +//! } +//! +//! impl FromError for MyError { +//! fn from_error(err: MapError) -> MyError { +//! MyError::Map(err) +//! } +//! } +//! +//! #[allow(unused_variables)] +//! fn open_and_map() -> Result<(), MyError> { +//! let f = try!(File::open(&Path::new("foo.txt"))); +//! let m = try!(MemoryMap::new(0, &[])); +//! // do something interesting here... +//! Ok(()) +//! } +//! ``` + +use option::{Option, None}; +use kinds::Send; +use string::String; + +/// Base functionality for all errors in Rust. +pub trait Error: Send { + /// A short description of the error; usually a static string. + fn description(&self) -> &str; + + /// A detailed description of the error, usually including dynamic information. + fn detail(&self) -> Option { unimplemented!() } + + /// The lower-level cause of this error, if any. + fn cause(&self) -> Option<&Error> { unimplemented!() } +} + +/// A trait for types that can be converted from a given error type `E`. +pub trait FromError { + /// Perform the conversion. + fn from_error(err: E) -> Self; +} + +// Any type is convertable from itself +impl FromError for E { + fn from_error(err: E) -> E { unimplemented!() } +} diff --git a/src/libst2/failure.rs b/src/libst2/failure.rs new file mode 100644 index 0000000000000..9dad72266db27 --- /dev/null +++ b/src/libst2/failure.rs @@ -0,0 +1,37 @@ +// 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. + +#![experimental] + +use alloc::boxed::Box; +use any::{Any, AnyRefExt}; +use cell::RefCell; +use fmt; +use io::{Writer, IoResult}; +use kinds::Send; +use option::{Some, None, Option}; +use result::Ok; +use rt::backtrace; +use rustrt::{Stderr, Stdio}; +use rustrt::local::Local; +use rustrt::task::Task; +use str::Str; +use string::String; + +// Defined in this module instead of io::stdio so that the unwinding +thread_local!(pub static LOCAL_STDERR: RefCell>> = { + RefCell::new(None) +}) + +impl Writer for Stdio { + fn write(&mut self, bytes: &[u8]) -> IoResult<()> { unimplemented!() } +} + +pub fn on_fail(obj: &Any + Send, file: &'static str, line: uint) { unimplemented!() } diff --git a/src/libst2/fmt.rs b/src/libst2/fmt.rs new file mode 100644 index 0000000000000..0c4d2b24558a3 --- /dev/null +++ b/src/libst2/fmt.rs @@ -0,0 +1,446 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15679 + +/*! + +Utilities for formatting and printing strings + +This module contains the runtime support for the `format!` syntax extension. +This macro is implemented in the compiler to emit calls to this module in order +to format arguments at runtime into strings and streams. + +The functions contained in this module should not normally be used in everyday +use cases of `format!`. The assumptions made by these functions are unsafe for +all inputs, and the compiler performs a large amount of validation on the +arguments to `format!` in order to ensure safety at runtime. While it is +possible to call these functions directly, it is not recommended to do so in the +general case. + +## Usage + +The `format!` macro is intended to be familiar to those coming from C's +printf/fprintf functions or Python's `str.format` function. In its current +revision, the `format!` macro returns a `String` type which is the result of +the formatting. In the future it will also be able to pass in a stream to +format arguments directly while performing minimal allocations. + +Some examples of the `format!` extension are: + +```rust +# fn main() { +format!("Hello"); // => "Hello" +format!("Hello, {}!", "world"); // => "Hello, world!" +format!("The number is {}", 1i); // => "The number is 1" +format!("{}", (3i, 4i)); // => "(3, 4)" +format!("{value}", value=4i); // => "4" +format!("{} {}", 1i, 2u); // => "1 2" +# } +``` + +From these, you can see that the first argument is a format string. It is +required by the compiler for this to be a string literal; it cannot be a +variable passed in (in order to perform validity checking). The compiler will +then parse the format string and determine if the list of arguments provided is +suitable to pass to this format string. + +### Positional parameters + +Each formatting argument is allowed to specify which value argument it's +referencing, and if omitted it is assumed to be "the next argument". For +example, the format string `{} {} {}` would take three parameters, and they +would be formatted in the same order as they're given. The format string +`{2} {1} {0}`, however, would format arguments in reverse order. + +Things can get a little tricky once you start intermingling the two types of +positional specifiers. The "next argument" specifier can be thought of as an +iterator over the argument. Each time a "next argument" specifier is seen, the +iterator advances. This leads to behavior like this: + +```rust +format!("{1} {} {0} {}", 1i, 2i); // => "2 1 1 2" +``` + +The internal iterator over the argument has not been advanced by the time the +first `{}` is seen, so it prints the first argument. Then upon reaching the +second `{}`, the iterator has advanced forward to the second argument. +Essentially, parameters which explicitly name their argument do not affect +parameters which do not name an argument in terms of positional specifiers. + +A format string is required to use all of its arguments, otherwise it is a +compile-time error. You may refer to the same argument more than once in the +format string, although it must always be referred to with the same type. + +### Named parameters + +Rust itself does not have a Python-like equivalent of named parameters to a +function, but the `format!` macro is a syntax extension which allows it to +leverage named parameters. Named parameters are listed at the end of the +argument list and have the syntax: + +```text +identifier '=' expression +``` + +For example, the following `format!` expressions all use named argument: + +```rust +# fn main() { +format!("{argument}", argument = "test"); // => "test" +format!("{name} {}", 1i, name = 2i); // => "2 1" +format!("{a} {c} {b}", a="a", b=(), c=3i); // => "a 3 ()" +# } +``` + +It is illegal to put positional parameters (those without names) after arguments +which have names. Like with positional parameters, it is illegal to provide +named parameters that are unused by the format string. + +### Argument types + +Each argument's type is dictated by the format string. It is a requirement that +every argument is only ever referred to by one type. For example, this is an +invalid format string: + +```text +{0:d} {0:s} +``` + +This is invalid because the first argument is both referred to as an integer as +well as a string. + +Because formatting is done via traits, there is no requirement that the +`d` format actually takes an `int`, but rather it simply requires a type which +ascribes to the `Signed` formatting trait. There are various parameters which do +require a particular type, however. Namely if the syntax `{:.*s}` is used, then +the number of characters to print from the string precedes the actual string and +must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is +illegal to reference an argument as such. For example, this is another invalid +format string: + +```text +{:.*s} {0:u} +``` + +### Formatting traits + +When requesting that an argument be formatted with a particular type, you are +actually requesting that an argument ascribes to a particular trait. This allows +multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`). +The current mapping of types to traits is: + +* *nothing* ⇒ `Show` +* `o` ⇒ `Octal` +* `x` ⇒ `LowerHex` +* `X` ⇒ `UpperHex` +* `p` ⇒ `Pointer` +* `b` ⇒ `Binary` +* `e` ⇒ `LowerExp` +* `E` ⇒ `UpperExp` + +What this means is that any type of argument which implements the +`std::fmt::Binary` trait can then be formatted with `{:b}`. Implementations are +provided for these traits for a number of primitive types by the standard +library as well. If no format is specified (as in `{}` or `{:6}`), then the +format trait used is the `Show` trait. This is one of the more commonly +implemented traits when formatting a custom type. + +When implementing a format trait for your own type, you will have to implement a +method of the signature: + +```rust +# use std; +# mod fmt { pub type Result = (); } +# struct T; +# trait SomeName { +fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result; +# } +``` + +Your type will be passed as `self` by-reference, and then the function should +emit output into the `f.buf` stream. It is up to each format trait +implementation to correctly adhere to the requested formatting parameters. The +values of these parameters will be listed in the fields of the `Formatter` +struct. In order to help with this, the `Formatter` struct also provides some +helper methods. + +Additionally, the return value of this function is `fmt::Result` which is a +typedef to `Result<(), IoError>` (also known as `IoResult<()>`). Formatting +implementations should ensure that they return errors from `write!` correctly +(propagating errors upward). + +An example of implementing the formatting traits would look +like: + +```rust +use std::fmt; +use std::f64; +use std::num::Float; + +struct Vector2D { + x: int, + y: int, +} + +impl fmt::Show for Vector2D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // The `f` value implements the `Writer` trait, which is what the + // write! macro is expecting. Note that this formatting ignores the + // various flags provided to format strings. + write!(f, "({}, {})", self.x, self.y) + } +} + +// Different traits allow different forms of output of a type. The meaning of +// this format is to print the magnitude of a vector. +impl fmt::Binary for Vector2D { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let magnitude = (self.x * self.x + self.y * self.y) as f64; + let magnitude = magnitude.sqrt(); + + // Respect the formatting flags by using the helper method + // `pad_integral` on the Formatter object. See the method documentation + // for details, and the function `pad` can be used to pad strings. + let decimals = f.precision().unwrap_or(3); + let string = f64::to_str_exact(magnitude, decimals); + f.pad_integral(true, "", string.as_bytes()) + } +} + +fn main() { + let myvector = Vector2D { x: 3, y: 4 }; + + println!("{}", myvector); // => "(3, 4)" + println!("{:10.3b}", myvector); // => " 5.000" +} +``` + +### Related macros + +There are a number of related macros in the `format!` family. The ones that are +currently implemented are: + +```ignore +format! // described above +write! // first argument is a &mut io::Writer, the destination +writeln! // same as write but appends a newline +print! // the format string is printed to the standard output +println! // same as print but appends a newline +format_args! // described below. +``` + + +#### `write!` + +This and `writeln` are two macros which are used to emit the format string to a +specified stream. This is used to prevent intermediate allocations of format +strings and instead directly write the output. Under the hood, this function is +actually invoking the `write` function defined in this module. Example usage is: + +```rust +# #![allow(unused_must_use)] +use std::io; + +let mut w = Vec::new(); +write!(&mut w as &mut io::Writer, "Hello {}!", "world"); +``` + +#### `print!` + +This and `println` emit their output to stdout. Similarly to the `write!` macro, +the goal of these macros is to avoid intermediate allocations when printing +output. Example usage is: + +```rust +print!("Hello {}!", "world"); +println!("I have a newline {}", "character at the end"); +``` + +#### `format_args!` +This is a curious macro which is used to safely pass around +an opaque object describing the format string. This object +does not require any heap allocations to create, and it only +references information on the stack. Under the hood, all of +the related macros are implemented in terms of this. First +off, some example usage is: + +``` +use std::fmt; +use std::io; + +# #[allow(unused_must_use)] +# fn main() { +format_args!(fmt::format, "this returns {}", "String"); + +let some_writer: &mut io::Writer = &mut io::stdout(); +format_args!(|args| { write!(some_writer, "{}", args) }, "print with a {}", "closure"); + +fn my_fmt_fn(args: &fmt::Arguments) { + write!(&mut io::stdout(), "{}", args); +} +format_args!(my_fmt_fn, "or a {} too", "function"); +# } +``` + +The first argument of the `format_args!` macro is a function (or closure) which +takes one argument of type `&fmt::Arguments`. This structure can then be +passed to the `write` and `format` functions inside this module in order to +process the format string. The goal of this macro is to even further prevent +intermediate allocations when dealing formatting strings. + +For example, a logging library could use the standard formatting syntax, but it +would internally pass around this structure until it has been determined where +output should go to. + +It is unsafe to programmatically create an instance of `fmt::Arguments` because +the operations performed when executing a format string require the compile-time +checks provided by the compiler. The `format_args!` macro is the only method of +safely creating these structures, but they can be unsafely created with the +constructor provided. + +## Syntax + +The syntax for the formatting language used is drawn from other languages, so it +should not be too alien. Arguments are formatted with python-like syntax, +meaning that arguments are surrounded by `{}` instead of the C-like `%`. The +actual grammar for the formatting syntax is: + +```text +format_string := [ format ] * +format := '{' [ argument ] [ ':' format_spec ] '}' +argument := integer | identifier + +format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type] +fill := character +align := '<' | '^' | '>' +sign := '+' | '-' +width := count +precision := count | '*' +type := identifier | '' +count := parameter | integer +parameter := integer '$' +``` + +## Formatting Parameters + +Each argument being formatted can be transformed by a number of formatting +parameters (corresponding to `format_spec` in the syntax above). These +parameters affect the string representation of what's being formatted. This +syntax draws heavily from Python's, so it may seem a bit familiar. + +### Fill/Alignment + +The fill character is provided normally in conjunction with the `width` +parameter. This indicates that if the value being formatted is smaller than +`width` some extra characters will be printed around it. The extra characters +are specified by `fill`, and the alignment can be one of two options: + +* `<` - the argument is left-aligned in `width` columns +* `^` - the argument is center-aligned in `width` columns +* `>` - the argument is right-aligned in `width` columns + +### Sign/#/0 + +These can all be interpreted as flags for a particular formatter. + +* '+' - This is intended for numeric types and indicates that the sign should + always be printed. Positive signs are never printed by default, and the + negative sign is only printed by default for the `Signed` trait. This + flag indicates that the correct sign (+ or -) should always be printed. +* '-' - Currently not used +* '#' - This flag is indicates that the "alternate" form of printing should be + used. By default, this only applies to the integer formatting traits and + performs like: + * `x` - precedes the argument with a "0x" + * `X` - precedes the argument with a "0x" + * `t` - precedes the argument with a "0b" + * `o` - precedes the argument with a "0o" +* '0' - This is used to indicate for integer formats that the padding should + both be done with a `0` character as well as be sign-aware. A format + like `{:08d}` would yield `00000001` for the integer `1`, while the same + format would yield `-0000001` for the integer `-1`. Notice that the + negative version has one fewer zero than the positive version. + +### Width + +This is a parameter for the "minimum width" that the format should take up. If +the value's string does not fill up this many characters, then the padding +specified by fill/alignment will be used to take up the required space. + +The default fill/alignment for non-numerics is a space and left-aligned. The +defaults for numeric formatters is also a space but with right-alignment. If the +'0' flag is specified for numerics, then the implicit fill character is '0'. + +The value for the width can also be provided as a `uint` in the list of +parameters by using the `2$` syntax indicating that the second argument is a +`uint` specifying the width. + +### Precision + +For non-numeric types, this can be considered a "maximum width". If the +resulting string is longer than this width, then it is truncated down to this +many characters and only those are emitted. + +For integral types, this has no meaning currently. + +For floating-point types, this indicates how many digits after the decimal point +should be printed. + +## Escaping + +The literal characters `{` and `}` may be included in a string by preceding them +with the same character. For example, the `{` character is escaped with `{{` and +the `}` character is escaped with `}}`. + +*/ + +#![experimental] + +use io::Writer; +use io; +use result::{Ok, Err}; +use string; +use vec::Vec; + +pub use core::fmt::{Formatter, Result, FormatWriter, rt}; +pub use core::fmt::{Show, Octal, Binary}; +pub use core::fmt::{LowerHex, UpperHex, Pointer}; +pub use core::fmt::{LowerExp, UpperExp}; +pub use core::fmt::Error; +pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt}; + +#[doc(hidden)] +pub use core::fmt::{argument, argumentstr, argumentuint}; + +/// The format function takes a precompiled format string and a list of +/// arguments, to return the resulting formatted string. +/// +/// # Arguments +/// +/// * args - a structure of arguments generated via the `format_args!` macro. +/// Because this structure can only be safely generated at +/// compile-time, this function is safe. +/// +/// # Example +/// +/// ```rust +/// use std::fmt; +/// +/// let s = format_args!(fmt::format, "Hello, {}!", "world"); +/// assert_eq!(s, "Hello, world!".to_string()); +/// ``` +#[experimental = "this is an implementation detail of format! and should not \ + be called directly"] +pub fn format(args: &Arguments) -> string::String { unimplemented!() } + +impl<'a> Writer for Formatter<'a> { + fn write(&mut self, b: &[u8]) -> io::IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/hash.rs b/src/libst2/hash.rs new file mode 100644 index 0000000000000..23f9ee827da85 --- /dev/null +++ b/src/libst2/hash.rs @@ -0,0 +1,94 @@ +// 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. + +/*! + * Generic hashing support. + * + * This module provides a generic way to compute the hash of a value. The + * simplest way to make a type hashable is to use `#[deriving(Hash)]`: + * + * # Example + * + * ```rust + * use std::hash; + * use std::hash::Hash; + * + * #[deriving(Hash)] + * struct Person { + * id: uint, + * name: String, + * phone: u64, + * } + * + * let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; + * let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; + * + * assert!(hash::hash(&person1) != hash::hash(&person2)); + * ``` + * + * If you need more control over how a value is hashed, you need to implement + * the trait `Hash`: + * + * ```rust + * use std::hash; + * use std::hash::Hash; + * use std::hash::sip::SipState; + * + * struct Person { + * id: uint, + * name: String, + * phone: u64, + * } + * + * impl Hash for Person { + * fn hash(&self, state: &mut SipState) { + * self.id.hash(state); + * self.phone.hash(state); + * } + * } + * + * let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; + * let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; + * + * assert!(hash::hash(&person1) == hash::hash(&person2)); + * ``` + */ + +#![experimental] + +pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip}; + +use core::kinds::Sized; +use default::Default; +use rand::Rng; +use rand; + +/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes +/// initialized with random keys. +#[deriving(Clone)] +pub struct RandomSipHasher { + hasher: sip::SipHasher, +} + +impl RandomSipHasher { + /// Construct a new `RandomSipHasher` that is initialized with random keys. + #[inline] + pub fn new() -> RandomSipHasher { unimplemented!() } +} + +impl Hasher for RandomSipHasher { + #[inline] + fn hash>(&self, value: &T) -> u64 { unimplemented!() } +} + +impl Default for RandomSipHasher { + #[inline] + fn default() -> RandomSipHasher { unimplemented!() } +} diff --git a/src/libst2/io/buffered.rs b/src/libst2/io/buffered.rs new file mode 100644 index 0000000000000..1a9900ee9892d --- /dev/null +++ b/src/libst2/io/buffered.rs @@ -0,0 +1,246 @@ +// Copyright 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. +// +// ignore-lexer-test FIXME #15883 + +//! Buffering wrappers for I/O traits + +use cmp; +use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; +use iter::ExactSize; +use ops::Drop; +use option::{Some, None, Option}; +use result::{Ok, Err}; +use slice::{SlicePrelude}; +use slice; +use vec::Vec; + +/// Wraps a Reader and buffers input from it +/// +/// It can be excessively inefficient to work directly with a `Reader`. For +/// example, every call to `read` on `TcpStream` results in a system call. A +/// `BufferedReader` performs large, infrequent reads on the underlying +/// `Reader` and maintains an in-memory buffer of the results. +/// +/// # Example +/// +/// ```rust +/// use std::io::{BufferedReader, File}; +/// +/// let file = File::open(&Path::new("message.txt")); +/// let mut reader = BufferedReader::new(file); +/// +/// let mut buf = [0, ..100]; +/// match reader.read(&mut buf) { +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) +/// } +/// ``` +pub struct BufferedReader { + inner: R, + buf: Vec, + pos: uint, + cap: uint, +} + +impl BufferedReader { + /// Creates a new `BufferedReader` with the specified buffer capacity + pub fn with_capacity(cap: uint, inner: R) -> BufferedReader { unimplemented!() } + + /// Creates a new `BufferedReader` with a default buffer capacity + pub fn new(inner: R) -> BufferedReader { unimplemented!() } + + /// Gets a reference to the underlying reader. + /// + /// This type does not expose the ability to get a mutable reference to the + /// underlying reader because that could possibly corrupt the buffer. + pub fn get_ref<'a>(&'a self) -> &'a R { unimplemented!() } + + /// Unwraps this `BufferedReader`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. + pub fn unwrap(self) -> R { unimplemented!() } +} + +impl Buffer for BufferedReader { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + + fn consume(&mut self, amt: uint) { unimplemented!() } +} + +impl Reader for BufferedReader { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +/// Wraps a Writer and buffers output to it +/// +/// It can be excessively inefficient to work directly with a `Writer`. For +/// example, every call to `write` on `TcpStream` results in a system call. A +/// `BufferedWriter` keeps an in memory buffer of data and writes it to the +/// underlying `Writer` in large, infrequent batches. +/// +/// This writer will be flushed when it is dropped. +/// +/// # Example +/// +/// ```rust +/// use std::io::{BufferedWriter, File}; +/// +/// let file = File::create(&Path::new("message.txt")).unwrap(); +/// let mut writer = BufferedWriter::new(file); +/// +/// writer.write_str("hello, world").unwrap(); +/// writer.flush().unwrap(); +/// ``` +pub struct BufferedWriter { + inner: Option, + buf: Vec, + pos: uint +} + +impl BufferedWriter { + /// Creates a new `BufferedWriter` with the specified buffer capacity + pub fn with_capacity(cap: uint, inner: W) -> BufferedWriter { unimplemented!() } + + /// Creates a new `BufferedWriter` with a default buffer capacity + pub fn new(inner: W) -> BufferedWriter { unimplemented!() } + + fn flush_buf(&mut self) -> IoResult<()> { unimplemented!() } + + /// Gets a reference to the underlying writer. + /// + /// This type does not expose the ability to get a mutable reference to the + /// underlying reader because that could possibly corrupt the buffer. + pub fn get_ref<'a>(&'a self) -> &'a W { unimplemented!() } + + /// Unwraps this `BufferedWriter`, returning the underlying writer. + /// + /// The buffer is flushed before returning the writer. + pub fn unwrap(mut self) -> W { unimplemented!() } +} + +impl Writer for BufferedWriter { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + +#[unsafe_destructor] +impl Drop for BufferedWriter { + fn drop(&mut self) { unimplemented!() } +} + +/// Wraps a Writer and buffers output to it, flushing whenever a newline (`0x0a`, +/// `'\n'`) is detected. +/// +/// This writer will be flushed when it is dropped. +pub struct LineBufferedWriter { + inner: BufferedWriter, +} + +impl LineBufferedWriter { + /// Creates a new `LineBufferedWriter` + pub fn new(inner: W) -> LineBufferedWriter { unimplemented!() } + + /// Gets a reference to the underlying writer. + /// + /// This type does not expose the ability to get a mutable reference to the + /// underlying reader because that could possibly corrupt the buffer. + pub fn get_ref<'a>(&'a self) -> &'a W { unimplemented!() } + + /// Unwraps this `LineBufferedWriter`, returning the underlying writer. + /// + /// The internal buffer is flushed before returning the writer. + pub fn unwrap(self) -> W { unimplemented!() } +} + +impl Writer for LineBufferedWriter { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + +struct InternalBufferedWriter(BufferedWriter); + +impl InternalBufferedWriter { + fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter { unimplemented!() } +} + +impl Reader for InternalBufferedWriter { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +/// Wraps a Stream and buffers input and output to and from it. +/// +/// It can be excessively inefficient to work directly with a `Stream`. For +/// example, every call to `read` or `write` on `TcpStream` results in a system +/// call. A `BufferedStream` keeps in memory buffers of data, making large, +/// infrequent calls to `read` and `write` on the underlying `Stream`. +/// +/// The output half will be flushed when this stream is dropped. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::{BufferedStream, File}; +/// +/// let file = File::open(&Path::new("message.txt")); +/// let mut stream = BufferedStream::new(file); +/// +/// stream.write("hello, world".as_bytes()); +/// stream.flush(); +/// +/// let mut buf = [0, ..100]; +/// match stream.read(&mut buf) { +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("error reading: {}", e) +/// } +/// ``` +pub struct BufferedStream { + inner: BufferedReader> +} + +impl BufferedStream { + /// Creates a new buffered stream with explicitly listed capacities for the + /// reader/writer buffer. + pub fn with_capacities(reader_cap: uint, writer_cap: uint, inner: S) + -> BufferedStream { unimplemented!() } + + /// Creates a new buffered stream with the default reader/writer buffer + /// capacities. + pub fn new(inner: S) -> BufferedStream { unimplemented!() } + + /// Gets a reference to the underlying stream. + /// + /// This type does not expose the ability to get a mutable reference to the + /// underlying reader because that could possibly corrupt the buffer. + pub fn get_ref<'a>(&'a self) -> &'a S { unimplemented!() } + + /// Unwraps this `BufferedStream`, returning the underlying stream. + /// + /// The internal buffer is flushed before returning the stream. Any leftover + /// data in the read buffer is lost. + pub fn unwrap(self) -> S { unimplemented!() } +} + +impl Buffer for BufferedStream { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + fn consume(&mut self, amt: uint) { unimplemented!() } +} + +impl Reader for BufferedStream { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for BufferedStream { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/io/comm_adapters.rs b/src/libst2/io/comm_adapters.rs new file mode 100644 index 0000000000000..5dff2143c7740 --- /dev/null +++ b/src/libst2/io/comm_adapters.rs @@ -0,0 +1,88 @@ +// Copyright 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. + +use clone::Clone; +use cmp; +use comm::{Sender, Receiver}; +use io; +use option::{None, Some}; +use result::{Ok, Err}; +use slice::{bytes, CloneSliceAllocPrelude, SlicePrelude}; +use super::{Buffer, Reader, Writer, IoResult}; +use vec::Vec; + +/// Allows reading from a rx. +/// +/// # Example +/// +/// ``` +/// use std::io::ChanReader; +/// +/// let (tx, rx) = channel(); +/// # drop(tx); +/// let mut reader = ChanReader::new(rx); +/// +/// let mut buf = [0u8, ..100]; +/// match reader.read(&mut buf) { +/// Ok(nread) => println!("Read {} bytes", nread), +/// Err(e) => println!("read error: {}", e), +/// } +/// ``` +pub struct ChanReader { + buf: Vec, // A buffer of bytes received but not consumed. + pos: uint, // How many of the buffered bytes have already be consumed. + rx: Receiver>, // The Receiver to pull data from. + closed: bool, // Whether the channel this Receiver connects to has been closed. +} + +impl ChanReader { + /// Wraps a `Port` in a `ChanReader` structure + pub fn new(rx: Receiver>) -> ChanReader { unimplemented!() } +} + +impl Buffer for ChanReader { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + + fn consume(&mut self, amt: uint) { unimplemented!() } +} + +impl Reader for ChanReader { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +/// Allows writing to a tx. +/// +/// # Example +/// +/// ``` +/// # #![allow(unused_must_use)] +/// use std::io::ChanWriter; +/// +/// let (tx, rx) = channel(); +/// # drop(rx); +/// let mut writer = ChanWriter::new(tx); +/// writer.write("hello, world".as_bytes()); +/// ``` +pub struct ChanWriter { + tx: Sender>, +} + +impl ChanWriter { + /// Wraps a channel in a `ChanWriter` structure + pub fn new(tx: Sender>) -> ChanWriter { unimplemented!() } +} + +impl Clone for ChanWriter { + fn clone(&self) -> ChanWriter { unimplemented!() } +} + +impl Writer for ChanWriter { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/io/extensions.rs b/src/libst2/io/extensions.rs new file mode 100644 index 0000000000000..5b59ba6fdfa8d --- /dev/null +++ b/src/libst2/io/extensions.rs @@ -0,0 +1,97 @@ +// Copyright 2013-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. + +//! Utility mixins that apply to all Readers and Writers + +#![allow(missing_docs)] + +// FIXME: Not sure how this should be structured +// FIXME: Iteration should probably be considered separately + +use io::{IoError, IoResult, Reader}; +use io; +use iter::Iterator; +use num::Int; +use option::{Option, Some, None}; +use ptr::RawPtr; +use result::{Ok, Err}; +use slice::{SlicePrelude, AsSlice}; + +/// An iterator that reads a single byte on each iteration, +/// until `.read_byte()` returns `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Bytes` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +pub struct Bytes<'r, T:'r> { + reader: &'r mut T, +} + +impl<'r, R: Reader> Bytes<'r, R> { + /// Constructs a new byte iterator from the given Reader instance. + pub fn new(r: &'r mut R) -> Bytes<'r, R> { unimplemented!() } +} + +impl<'r, R: Reader> Iterator> for Bytes<'r, R> { + #[inline] + fn next(&mut self) -> Option> { unimplemented!() } +} + +/// Converts an 8-bit to 64-bit unsigned value to a little-endian byte +/// representation of the given size. If the size is not big enough to +/// represent the value, then the high-order bytes are truncated. +/// +/// Arguments: +/// +/// * `n`: The value to convert. +/// * `size`: The size of the value, in bytes. This must be 8 or less, or task +/// panic occurs. If this is less than 8, then a value of that +/// many bytes is produced. For example, if `size` is 4, then a +/// 32-bit byte representation is produced. +/// * `f`: A callback that receives the value. +/// +/// This function returns the value returned by the callback, for convenience. +pub fn u64_to_le_bytes(n: u64, size: uint, f: |v: &[u8]| -> T) -> T { unimplemented!() } + +/// Converts an 8-bit to 64-bit unsigned value to a big-endian byte +/// representation of the given size. If the size is not big enough to +/// represent the value, then the high-order bytes are truncated. +/// +/// Arguments: +/// +/// * `n`: The value to convert. +/// * `size`: The size of the value, in bytes. This must be 8 or less, or task +/// panic occurs. If this is less than 8, then a value of that +/// many bytes is produced. For example, if `size` is 4, then a +/// 32-bit byte representation is produced. +/// * `f`: A callback that receives the value. +/// +/// This function returns the value returned by the callback, for convenience. +pub fn u64_to_be_bytes(n: u64, size: uint, f: |v: &[u8]| -> T) -> T { unimplemented!() } + +/// Extracts an 8-bit to 64-bit unsigned big-endian value from the given byte +/// buffer and returns it as a 64-bit value. +/// +/// Arguments: +/// +/// * `data`: The buffer in which to extract the value. +/// * `start`: The offset at which to extract the value. +/// * `size`: The size of the value in bytes to extract. This must be 8 or +/// less, or task panic occurs. If this is less than 8, then only +/// that many bytes are parsed. For example, if `size` is 4, then a +/// 32-bit value is parsed. +pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 { unimplemented!() } diff --git a/src/libst2/io/fs.rs b/src/libst2/io/fs.rs new file mode 100644 index 0000000000000..097c228bc3b19 --- /dev/null +++ b/src/libst2/io/fs.rs @@ -0,0 +1,530 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15679 + +/*! Synchronous File I/O + +This module provides a set of functions and traits for working +with regular files & directories on a filesystem. + +At the top-level of the module are a set of freestanding functions, associated +with various filesystem operations. They all operate on `Path` objects. + +All operations in this module, including those as part of `File` et al +block the task during execution. In the event of failure, all functions/methods +will return an `IoResult` type with an `Err` value. + +Also included in this module is an implementation block on the `Path` object +defined in `std::path::Path`. The impl adds useful methods about inspecting the +metadata of a file. This includes getting the `stat` information, reading off +particular bits of it, etc. + +# Example + +```rust +# #![allow(unused_must_use)] +use std::io::fs::PathExtensions; +use std::io::{File, fs}; + +let path = Path::new("foo.txt"); + +// create the file, whether it exists or not +let mut file = File::create(&path); +file.write(b"foobar"); +# drop(file); + +// open the file in read-only mode +let mut file = File::open(&path); +file.read_to_end(); + +println!("{}", path.stat().unwrap().size); +# drop(file); +fs::unlink(&path); +``` + +*/ + +use clone::Clone; +use io::standard_error; +use io::{FilePermission, Write, Open, FileAccess, FileMode}; +use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; +use io::{Read, Truncate, ReadWrite, Append}; +use io::UpdateIoError; +use io; +use iter::{Iterator, Extend}; +use option::{Some, None, Option}; +use path::{Path, GenericPath}; +use path; +use result::{Err, Ok}; +use slice::SlicePrelude; +use string::String; +use vec::Vec; + +use sys::fs as fs_imp; +use sys_common; + +/// Unconstrained file access type that exposes read and write operations +/// +/// Can be constructed via `File::open()`, `File::create()`, and +/// `File::open_mode()`. +/// +/// # Error +/// +/// This type will return errors as an `IoResult` if operations are +/// attempted against it for which its underlying file descriptor was not +/// configured at creation time, via the `FileAccess` parameter to +/// `File::open_mode()`. +pub struct File { + fd: fs_imp::FileDesc, + path: Path, + last_nread: int, +} + +impl sys_common::AsFileDesc for File { + fn as_fd(&self) -> &fs_imp::FileDesc { unimplemented!() } +} + +impl File { + /// Open a file at `path` in the mode specified by the `mode` and `access` + /// arguments + /// + /// # Example + /// + /// ```rust,should_fail + /// use std::io::{File, Open, ReadWrite}; + /// + /// let p = Path::new("/some/file/path.txt"); + /// + /// let file = match File::open_mode(&p, Open, ReadWrite) { + /// Ok(f) => f, + /// Err(e) => panic!("file error: {}", e), + /// }; + /// // do some stuff with that file + /// + /// // the file will be closed at the end of this block + /// ``` + /// + /// `FileMode` and `FileAccess` provide information about the permissions + /// context in which a given stream is created. More information about them + /// can be found in `std::io`'s docs. If a file is opened with `Write` + /// or `ReadWrite` access, then it will be created if it does not already + /// exist. + /// + /// Note that, with this function, a `File` is returned regardless of the + /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a + /// `File` opened as `Read` will return an error at runtime). + /// + /// # Error + /// + /// This function will return an error under a number of different + /// circumstances, to include but not limited to: + /// + /// * Opening a file that does not exist with `Read` access. + /// * Attempting to open a file with a `FileAccess` that the user lacks + /// permissions for + /// * Filesystem-level errors (full disk, etc) + pub fn open_mode(path: &Path, + mode: FileMode, + access: FileAccess) -> IoResult { unimplemented!() } + + /// Attempts to open a file in read-only mode. This function is equivalent to + /// `File::open_mode(path, Open, Read)`, and will raise all of the same + /// errors that `File::open_mode` does. + /// + /// For more information, see the `File::open_mode` function. + /// + /// # Example + /// + /// ```rust + /// use std::io::File; + /// + /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); + /// ``` + pub fn open(path: &Path) -> IoResult { unimplemented!() } + + /// Attempts to create a file in write-only mode. This function is + /// equivalent to `File::open_mode(path, Truncate, Write)`, and will + /// raise all of the same errors that `File::open_mode` does. + /// + /// For more information, see the `File::open_mode` function. + /// + /// # Example + /// + /// ```rust + /// # #![allow(unused_must_use)] + /// use std::io::File; + /// + /// let mut f = File::create(&Path::new("foo.txt")); + /// f.write(b"This is a sample file"); + /// # drop(f); + /// # ::std::io::fs::unlink(&Path::new("foo.txt")); + /// ``` + pub fn create(path: &Path) -> IoResult { unimplemented!() } + + /// Returns the original path which was used to open this file. + pub fn path<'a>(&'a self) -> &'a Path { unimplemented!() } + + /// Synchronizes all modifications to this file to its permanent storage + /// device. This will flush any internal buffers necessary to perform this + /// operation. + pub fn fsync(&mut self) -> IoResult<()> { unimplemented!() } + + /// This function is similar to `fsync`, except that it may not synchronize + /// file metadata to the filesystem. This is intended for use case which + /// must synchronize content, but don't need the metadata on disk. The goal + /// of this method is to reduce disk operations. + pub fn datasync(&mut self) -> IoResult<()> { unimplemented!() } + + /// Either truncates or extends the underlying file, updating the size of + /// this file to become `size`. This is equivalent to unix's `truncate` + /// function. + /// + /// If the `size` is less than the current file's size, then the file will + /// be shrunk. If it is greater than the current file's size, then the file + /// will be extended to `size` and have all of the intermediate data filled + /// in with 0s. + pub fn truncate(&mut self, size: i64) -> IoResult<()> { unimplemented!() } + + /// Returns true if the stream has reached the end of the file. + /// + /// If true, then this file will no longer continue to return data via + /// `read`. + /// + /// Note that the operating system will not return an `EOF` indicator + /// until you have attempted to read past the end of the file, so if + /// you've read _exactly_ the number of bytes in the file, this will + /// return `false`, not `true`. + pub fn eof(&self) -> bool { unimplemented!() } + + /// Queries information about the underlying file. + pub fn stat(&mut self) -> IoResult { unimplemented!() } +} + +/// Unlink a file from the underlying filesystem. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::fs; +/// +/// let p = Path::new("/some/file/path.txt"); +/// fs::unlink(&p); +/// ``` +/// +/// Note that, just because an unlink call was successful, it is not +/// guaranteed that a file is immediately deleted (e.g. depending on +/// platform, other open file descriptors may prevent immediate removal) +/// +/// # Error +/// +/// This function will return an error if `path` points to a directory, if the +/// user lacks permissions to remove the file, or if some other filesystem-level +/// error occurs. +pub fn unlink(path: &Path) -> IoResult<()> { unimplemented!() } + +/// Given a path, query the file system to get information about a file, +/// directory, etc. This function will traverse symlinks to query +/// information about the destination file. +/// +/// # Example +/// +/// ```rust +/// use std::io::fs; +/// +/// let p = Path::new("/some/file/path.txt"); +/// match fs::stat(&p) { +/// Ok(stat) => { /* ... */ } +/// Err(e) => { /* handle error */ } +/// } +/// ``` +/// +/// # Error +/// +/// This function will return an error if the user lacks the requisite permissions +/// to perform a `stat` call on the given `path` or if there is no entry in the +/// filesystem at the provided path. +pub fn stat(path: &Path) -> IoResult { unimplemented!() } + +/// Perform the same operation as the `stat` function, except that this +/// function does not traverse through symlinks. This will return +/// information about the symlink file instead of the file that it points +/// to. +/// +/// # Error +/// +/// See `stat` +pub fn lstat(path: &Path) -> IoResult { unimplemented!() } + +/// Rename a file or directory to a new name. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::fs; +/// +/// fs::rename(&Path::new("foo"), &Path::new("bar")); +/// ``` +/// +/// # Error +/// +/// This function will return an error if the provided `from` doesn't exist, if +/// the process lacks permissions to view the contents, or if some other +/// intermittent I/O error occurs. +pub fn rename(from: &Path, to: &Path) -> IoResult<()> { unimplemented!() } + +/// Copies the contents of one file to another. This function will also +/// copy the permission bits of the original file to the destination file. +/// +/// Note that if `from` and `to` both point to the same file, then the file +/// will likely get truncated by this operation. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::fs; +/// +/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); +/// ``` +/// +/// # Error +/// +/// This function will return an error in the following situations, but is not +/// limited to just these cases: +/// +/// * The `from` path is not a file +/// * The `from` file does not exist +/// * The current process does not have the permission rights to access +/// `from` or write `to` +/// +/// Note that this copy is not atomic in that once the destination is +/// ensured to not exist, there is nothing preventing the destination from +/// being created and then destroyed by this operation. +pub fn copy(from: &Path, to: &Path) -> IoResult<()> { unimplemented!() } + +/// Changes the permission mode bits found on a file or a directory. This +/// function takes a mask from the `io` module +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io; +/// use std::io::fs; +/// +/// fs::chmod(&Path::new("file.txt"), io::USER_FILE); +/// fs::chmod(&Path::new("file.txt"), io::USER_READ | io::USER_WRITE); +/// fs::chmod(&Path::new("dir"), io::USER_DIR); +/// fs::chmod(&Path::new("file.exe"), io::USER_EXEC); +/// ``` +/// +/// # Error +/// +/// This function will return an error if the provided `path` doesn't exist, if +/// the process lacks permissions to change the attributes of the file, or if +/// some other I/O error is encountered. +pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> { unimplemented!() } + +/// Change the user and group owners of a file at the specified path. +pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { + fs_imp::chown(path, uid, gid) + .update_err("couldn't chown path", |e| + format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid)) +} + +/// Creates a new hard link on the filesystem. The `dst` path will be a +/// link pointing to the `src` path. Note that systems often require these +/// two paths to both be located on the same filesystem. +pub fn link(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } + +/// Creates a new symbolic link on the filesystem. The `dst` path will be a +/// symlink pointing to the `src` path. +pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } + +/// Reads a symlink, returning the file that the symlink points to. +/// +/// # Error +/// +/// This function will return an error on failure. Failure conditions include +/// reading a file that does not exist or reading a file which is not a symlink. +pub fn readlink(path: &Path) -> IoResult { unimplemented!() } + +/// Create a new, empty directory at the provided path +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io; +/// use std::io::fs; +/// +/// let p = Path::new("/some/dir"); +/// fs::mkdir(&p, io::USER_RWX); +/// ``` +/// +/// # Error +/// +/// This function will return an error if the user lacks permissions to make a +/// new directory at the provided `path`, or if the directory already exists. +pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { unimplemented!() } + +/// Remove an existing, empty directory +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::fs; +/// +/// let p = Path::new("/some/dir"); +/// fs::rmdir(&p); +/// ``` +/// +/// # Error +/// +/// This function will return an error if the user lacks permissions to remove +/// the directory at the provided `path`, or if the directory isn't empty. +pub fn rmdir(path: &Path) -> IoResult<()> { unimplemented!() } + +/// Retrieve a vector containing all entries within a provided directory +/// +/// # Example +/// +/// ```rust +/// use std::io::fs::PathExtensions; +/// use std::io::fs; +/// use std::io; +/// +/// // one possible implementation of fs::walk_dir only visiting files +/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> { +/// if dir.is_dir() { +/// let contents = try!(fs::readdir(dir)); +/// for entry in contents.iter() { +/// if entry.is_dir() { +/// try!(visit_dirs(entry, |p| cb(p))); +/// } else { +/// cb(entry); +/// } +/// } +/// Ok(()) +/// } else { +/// Err(io::standard_error(io::InvalidInput)) +/// } +/// } +/// ``` +/// +/// # Error +/// +/// This function will return an error if the provided `path` doesn't exist, if +/// the process lacks permissions to view the contents or if the `path` points +/// at a non-directory file +pub fn readdir(path: &Path) -> IoResult> { unimplemented!() } + +/// Returns an iterator which will recursively walk the directory structure +/// rooted at `path`. The path given will not be iterated over, and this will +/// perform iteration in some top-down order. The contents of unreadable +/// subdirectories are ignored. +pub fn walk_dir(path: &Path) -> IoResult { unimplemented!() } + +/// An iterator which walks over a directory +pub struct Directories { + stack: Vec, +} + +impl Iterator for Directories { + fn next(&mut self) -> Option { unimplemented!() } +} + +/// Recursively create a directory and all of its parent components if they +/// are missing. +/// +/// # Error +/// +/// See `fs::mkdir`. +pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { unimplemented!() } + +/// Removes a directory at this path, after removing all its contents. Use +/// carefully! +/// +/// # Error +/// +/// See `file::unlink` and `fs::readdir` +pub fn rmdir_recursive(path: &Path) -> IoResult<()> { unimplemented!() } + +/// Changes the timestamps for a file's last modification and access time. +/// The file at the path specified will have its last access time set to +/// `atime` and its modification time set to `mtime`. The times specified should +/// be in milliseconds. +// FIXME(#10301) these arguments should not be u64 +pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { unimplemented!() } + +impl Reader for File { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for File { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +impl Seek for File { + fn tell(&self) -> IoResult { unimplemented!() } + + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } +} + +/// Utility methods for paths. +pub trait PathExtensions { + /// Get information on the file, directory, etc at this path. + /// + /// Consult the `fs::stat` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with `file::stat`. + fn stat(&self) -> IoResult; + + /// Get information on the file, directory, etc at this path, not following + /// symlinks. + /// + /// Consult the `fs::lstat` documentation for more info. + /// + /// This call preserves identical runtime/error semantics with `file::lstat`. + fn lstat(&self) -> IoResult; + + /// Boolean value indicator whether the underlying file exists on the local + /// filesystem. Returns false in exactly the cases where `fs::stat` fails. + fn exists(&self) -> bool; + + /// Whether the underlying implementation (be it a file path, or something + /// else) points at a "regular file" on the FS. Will return false for paths + /// to non-existent locations or directories or other non-regular files + /// (named pipes, etc). Follows links when making this determination. + fn is_file(&self) -> bool; + + /// Whether the underlying implementation (be it a file path, or something + /// else) is pointing at a directory in the underlying FS. Will return + /// false for paths to non-existent locations or if the item is not a + /// directory (eg files, named pipes, etc). Follows links when making this + /// determination. + fn is_dir(&self) -> bool; +} + +impl PathExtensions for path::Path { + fn stat(&self) -> IoResult { unimplemented!() } + fn lstat(&self) -> IoResult { unimplemented!() } + fn exists(&self) -> bool { unimplemented!() } + fn is_file(&self) -> bool { unimplemented!() } + fn is_dir(&self) -> bool { unimplemented!() } +} + +fn mode_string(mode: FileMode) -> &'static str { unimplemented!() } + +fn access_string(access: FileAccess) -> &'static str { unimplemented!() } diff --git a/src/libst2/io/mem.rs b/src/libst2/io/mem.rs new file mode 100644 index 0000000000000..910161cf3570c --- /dev/null +++ b/src/libst2/io/mem.rs @@ -0,0 +1,235 @@ +// Copyright 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. +// +// ignore-lexer-test FIXME #15679 + +//! Readers and Writers for in-memory buffers + +#![allow(deprecated)] + +use cmp::min; +use option::None; +use result::{Err, Ok}; +use io; +use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; +use slice::{mod, AsSlice, SlicePrelude}; +use vec::Vec; + +const BUF_CAPACITY: uint = 128; + +fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult { unimplemented!() } + +impl Writer for Vec { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +/// Writes to an owned, growable byte vector +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::MemWriter; +/// +/// let mut w = MemWriter::new(); +/// w.write(&[0, 1, 2]); +/// +/// assert_eq!(w.unwrap(), vec!(0, 1, 2)); +/// ``` +#[deprecated = "use the Vec Writer implementation directly"] +#[deriving(Clone)] +pub struct MemWriter { + buf: Vec, +} + +impl MemWriter { + /// Create a new `MemWriter`. + #[inline] + pub fn new() -> MemWriter { unimplemented!() } + /// Create a new `MemWriter`, allocating at least `n` bytes for + /// the internal buffer. + #[inline] + pub fn with_capacity(n: uint) -> MemWriter { unimplemented!() } + /// Create a new `MemWriter` that will append to an existing `Vec`. + #[inline] + pub fn from_vec(buf: Vec) -> MemWriter { unimplemented!() } + + /// Acquires an immutable reference to the underlying buffer of this + /// `MemWriter`. + #[inline] + pub fn get_ref<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + /// Unwraps this `MemWriter`, returning the underlying buffer + #[inline] + pub fn unwrap(self) -> Vec { unimplemented!() } +} + +impl Writer for MemWriter { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +/// Reads from an owned byte vector +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::MemReader; +/// +/// let mut r = MemReader::new(vec!(0, 1, 2)); +/// +/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2)); +/// ``` +pub struct MemReader { + buf: Vec, + pos: uint +} + +impl MemReader { + /// Creates a new `MemReader` which will read the buffer given. The buffer + /// can be re-acquired through `unwrap` + #[inline] + pub fn new(buf: Vec) -> MemReader { unimplemented!() } + + /// Tests whether this reader has read all bytes in its buffer. + /// + /// If `true`, then this will no longer return bytes from `read`. + #[inline] + pub fn eof(&self) -> bool { unimplemented!() } + + /// Acquires an immutable reference to the underlying buffer of this + /// `MemReader`. + /// + /// No method is exposed for acquiring a mutable reference to the buffer + /// because it could corrupt the state of this `MemReader`. + #[inline] + pub fn get_ref<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + /// Unwraps this `MemReader`, returning the underlying buffer + #[inline] + pub fn unwrap(self) -> Vec { unimplemented!() } +} + +impl Reader for MemReader { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Seek for MemReader { + #[inline] + fn tell(&self) -> IoResult { unimplemented!() } + + #[inline] + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } +} + +impl Buffer for MemReader { + #[inline] + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + + #[inline] + fn consume(&mut self, amt: uint) { unimplemented!() } +} + +/// Writes to a fixed-size byte slice +/// +/// If a write will not fit in the buffer, it returns an error and does not +/// write any data. +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::BufWriter; +/// +/// let mut buf = [0, ..4]; +/// { +/// let mut w = BufWriter::new(&mut buf); +/// w.write(&[0, 1, 2]); +/// } +/// assert!(buf == [0, 1, 2, 0]); +/// ``` +pub struct BufWriter<'a> { + buf: &'a mut [u8], + pos: uint +} + +impl<'a> BufWriter<'a> { + /// Creates a new `BufWriter` which will wrap the specified buffer. The + /// writer initially starts at position 0. + #[inline] + pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> { unimplemented!() } +} + +impl<'a> Writer for BufWriter<'a> { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +impl<'a> Seek for BufWriter<'a> { + #[inline] + fn tell(&self) -> IoResult { unimplemented!() } + + #[inline] + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } +} + +/// Reads from a fixed-size byte slice +/// +/// # Example +/// +/// ```rust +/// # #![allow(unused_must_use)] +/// use std::io::BufReader; +/// +/// let mut buf = [0, 1, 2, 3]; +/// let mut r = BufReader::new(&mut buf); +/// +/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2, 3)); +/// ``` +pub struct BufReader<'a> { + buf: &'a [u8], + pos: uint +} + +impl<'a> BufReader<'a> { + /// Creates a new buffered reader which will read the specified buffer + #[inline] + pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> { unimplemented!() } + + /// Tests whether this reader has read all bytes in its buffer. + /// + /// If `true`, then this will no longer return bytes from `read`. + #[inline] + pub fn eof(&self) -> bool { unimplemented!() } +} + +impl<'a> Reader for BufReader<'a> { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl<'a> Seek for BufReader<'a> { + #[inline] + fn tell(&self) -> IoResult { unimplemented!() } + + #[inline] + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } +} + +impl<'a> Buffer for BufReader<'a> { + #[inline] + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + + #[inline] + fn consume(&mut self, amt: uint) { unimplemented!() } +} diff --git a/src/libst2/io/mod.rs b/src/libst2/io/mod.rs new file mode 100644 index 0000000000000..e957f67db0282 --- /dev/null +++ b/src/libst2/io/mod.rs @@ -0,0 +1,1258 @@ +#![experimental] +#![deny(unused_must_use)] + +pub use self::SeekStyle::*; +pub use self::FileMode::*; +pub use self::FileAccess::*; +pub use self::FileType::*; +pub use self::IoErrorKind::*; + +use char::Char; +use clone::Clone; +use default::Default; +use error::{FromError, Error}; +use fmt; +use int; +use iter::Iterator; +use mem::transmute; +use ops::{BitOr, BitXor, BitAnd, Sub, Not}; +use option::{Option, Some, None}; +use os; +use boxed::Box; +use result::{Ok, Err, Result}; +use sys; +use slice::{AsSlice, SlicePrelude}; +use str::{Str, StrPrelude}; +use str; +use string::String; +use uint; +use unicode::char::UnicodeChar; +use vec::Vec; + +// Reexports +pub use self::stdio::stdin; +pub use self::stdio::stdout; +pub use self::stdio::stderr; +pub use self::stdio::print; +pub use self::stdio::println; + +pub use self::fs::File; +pub use self::timer::Timer; +pub use self::net::ip::IpAddr; +pub use self::net::tcp::TcpListener; +pub use self::net::tcp::TcpStream; +pub use self::net::udp::UdpStream; +pub use self::pipe::PipeStream; +pub use self::process::{Process, Command}; +pub use self::tempfile::TempDir; + +pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; +pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream, + LineBufferedWriter}; +pub use self::comm_adapters::{ChanReader, ChanWriter}; + +mod buffered; +mod comm_adapters; +mod mem; +mod result; +mod tempfile; +pub mod extensions; +pub mod fs; +pub mod net; +pub mod pipe; +pub mod process; +pub mod stdio; +pub mod test; +pub mod timer; +pub mod util; + +/// The default buffer size for various I/O operations +// libuv recommends 64k buffers to maximize throughput +// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA +const DEFAULT_BUF_SIZE: uint = 1024 * 64; + +/// A convenient typedef of the return value of any I/O action. +pub type IoResult = Result; + +/// The type passed to I/O condition handlers to indicate error +/// +/// # FIXME +/// +/// Is something like this sufficient? It's kind of archaic +#[deriving(PartialEq, Eq, Clone)] +pub struct IoError { + /// An enumeration which can be matched against for determining the flavor + /// of error. + pub kind: IoErrorKind, + /// A human-readable description about the error + pub desc: &'static str, + /// Detailed information about this error, not always available + pub detail: Option +} + +impl IoError { + /// Convert an `errno` value into an `IoError`. + /// + /// If `detail` is `true`, the `detail` field of the `IoError` + /// struct is filled with an allocated string describing the error + /// in more detail, retrieved from the operating system. + pub fn from_errno(errno: uint, detail: bool) -> IoError { unimplemented!() } + + /// Retrieve the last error to occur as a (detailed) IoError. + /// + /// This uses the OS `errno`, and so there should not be any task + /// descheduling or migration (other than that performed by the + /// operating system) between the call(s) for which errors are + /// being checked and the call of this function. + pub fn last_error() -> IoError { unimplemented!() } +} + +impl fmt::Show for IoError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl Error for IoError { + fn description(&self) -> &str { unimplemented!() } + + fn detail(&self) -> Option { unimplemented!() } +} + +impl FromError for Box { + fn from_error(err: IoError) -> Box { unimplemented!() } +} + +/// A list specifying general categories of I/O error. +#[deriving(PartialEq, Eq, Clone, Show)] +pub enum IoErrorKind { + /// Any I/O error not part of this list. + OtherIoError, + /// The operation could not complete because end of file was reached. + EndOfFile, + /// The file was not found. + FileNotFound, + /// The file permissions disallowed access to this file. + PermissionDenied, + /// A network connection failed for some reason not specified in this list. + ConnectionFailed, + /// The network operation failed because the network connection was closed. + Closed, + /// The connection was refused by the remote server. + ConnectionRefused, + /// The connection was reset by the remote server. + ConnectionReset, + /// The connection was aborted (terminated) by the remote server. + ConnectionAborted, + /// The network operation failed because it was not connected yet. + NotConnected, + /// The operation failed because a pipe was closed. + BrokenPipe, + /// A file already existed with that name. + PathAlreadyExists, + /// No file exists at that location. + PathDoesntExist, + /// The path did not specify the type of file that this operation required. For example, + /// attempting to copy a directory with the `fs::copy()` operation will fail with this error. + MismatchedFileTypeForOperation, + /// The operation temporarily failed (for example, because a signal was received), and retrying + /// may succeed. + ResourceUnavailable, + /// No I/O functionality is available for this task. + IoUnavailable, + /// A parameter was incorrect in a way that caused an I/O error not part of this list. + InvalidInput, + /// The I/O operation's timeout expired, causing it to be canceled. + TimedOut, + /// This write operation failed to write all of its data. + /// + /// Normally the write() method on a Writer guarantees that all of its data + /// has been written, but some operations may be terminated after only + /// partially writing some data. An example of this is a timed out write + /// which successfully wrote a known number of bytes, but bailed out after + /// doing so. + /// + /// The payload contained as part of this variant is the number of bytes + /// which are known to have been successfully written. + ShortWrite(uint), + /// The Reader returned 0 bytes from `read()` too many times. + NoProgress, +} + +/// A trait that lets you add a `detail` to an IoError easily +trait UpdateIoError { + /// Returns an IoError with updated description and detail + fn update_err(self, desc: &'static str, detail: |&IoError| -> String) -> Self; + + /// Returns an IoError with updated detail + fn update_detail(self, detail: |&IoError| -> String) -> Self; + + /// Returns an IoError with update description + fn update_desc(self, desc: &'static str) -> Self; +} + +impl UpdateIoError for IoResult { + fn update_err(self, desc: &'static str, detail: |&IoError| -> String) -> IoResult { unimplemented!() } + + fn update_detail(self, detail: |&IoError| -> String) -> IoResult { unimplemented!() } + + fn update_desc(self, desc: &'static str) -> IoResult { unimplemented!() } +} + +static NO_PROGRESS_LIMIT: uint = 1000; + +/// A trait for objects which are byte-oriented streams. Readers are defined by +/// one method, `read`. This function will block until data is available, +/// filling in the provided buffer with any data read. +/// +/// Readers are intended to be composable with one another. Many objects +/// throughout the I/O and related libraries take and provide types which +/// implement the `Reader` trait. +pub trait Reader { + + // Only method which need to get implemented for this trait + + /// Read bytes, up to the length of `buf` and place them in `buf`. + /// Returns the number of bytes read. The number of bytes read may + /// be less than the number requested, even 0. Returns `Err` on EOF. + /// + /// # Error + /// + /// If an error occurs during this I/O operation, then it is returned as + /// `Err(IoError)`. Note that end-of-file is considered an error, and can be + /// inspected for in the error's `kind` field. Also note that reading 0 + /// bytes is not considered an error in all circumstances + /// + /// # Implementation Note + /// + /// When implementing this method on a new Reader, you are strongly encouraged + /// not to return 0 if you can avoid it. + fn read(&mut self, buf: &mut [u8]) -> IoResult; + + // Convenient helper methods based on the above methods + + /// Reads at least `min` bytes and places them in `buf`. + /// Returns the number of bytes read. + /// + /// This will continue to call `read` until at least `min` bytes have been + /// read. If `read` returns 0 too many times, `NoProgress` will be + /// returned. + /// + /// # Error + /// + /// If an error occurs at any point, that error is returned, and no further + /// bytes are read. + fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { unimplemented!() } + + /// Reads a single byte. Returns `Err` on EOF. + fn read_byte(&mut self) -> IoResult { unimplemented!() } + + /// Reads up to `len` bytes and appends them to a vector. + /// Returns the number of bytes read. The number of bytes read may be + /// less than the number requested, even 0. Returns Err on EOF. + /// + /// # Error + /// + /// If an error occurs during this I/O operation, then it is returned + /// as `Err(IoError)`. See `read()` for more details. + fn push(&mut self, len: uint, buf: &mut Vec) -> IoResult { unimplemented!() } + + /// Reads at least `min` bytes, but no more than `len`, and appends them to + /// a vector. + /// Returns the number of bytes read. + /// + /// This will continue to call `read` until at least `min` bytes have been + /// read. If `read` returns 0 too many times, `NoProgress` will be + /// returned. + /// + /// # Error + /// + /// If an error occurs at any point, that error is returned, and no further + /// bytes are read. + fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { unimplemented!() } + + /// Reads exactly `len` bytes and gives you back a new vector of length + /// `len` + /// + /// # Error + /// + /// Fails with the same conditions as `read`. Additionally returns error + /// on EOF. Note that if an error is returned, then some number of bytes may + /// have already been consumed from the underlying reader, and they are lost + /// (not returned as part of the error). If this is unacceptable, then it is + /// recommended to use the `push_at_least` or `read` methods. + fn read_exact(&mut self, len: uint) -> IoResult> { unimplemented!() } + + /// Reads all remaining bytes from the stream. + /// + /// # Error + /// + /// Returns any non-EOF error immediately. Previously read bytes are + /// discarded when an error is returned. + /// + /// When EOF is encountered, all bytes read up to that point are returned. + fn read_to_end(&mut self) -> IoResult> { unimplemented!() } + + /// Reads all of the remaining bytes of this stream, interpreting them as a + /// UTF-8 encoded stream. The corresponding string is returned. + /// + /// # Error + /// + /// This function returns all of the same errors as `read_to_end` with an + /// additional error if the reader's contents are not a valid sequence of + /// UTF-8 bytes. + fn read_to_string(&mut self) -> IoResult { unimplemented!() } + + // Byte conversion helpers + + /// Reads `n` little-endian unsigned integer bytes. + /// + /// `n` must be between 1 and 8, inclusive. + fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } + + /// Reads `n` little-endian signed integer bytes. + /// + /// `n` must be between 1 and 8, inclusive. + fn read_le_int_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } + + /// Reads `n` big-endian unsigned integer bytes. + /// + /// `n` must be between 1 and 8, inclusive. + fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } + + /// Reads `n` big-endian signed integer bytes. + /// + /// `n` must be between 1 and 8, inclusive. + fn read_be_int_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } + + /// Reads a little-endian unsigned integer. + /// + /// The number of bytes returned is system-dependent. + fn read_le_uint(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian integer. + /// + /// The number of bytes returned is system-dependent. + fn read_le_int(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian unsigned integer. + /// + /// The number of bytes returned is system-dependent. + fn read_be_uint(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian integer. + /// + /// The number of bytes returned is system-dependent. + fn read_be_int(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `u64`. + /// + /// `u64`s are 8 bytes long. + fn read_be_u64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `u32`. + /// + /// `u32`s are 4 bytes long. + fn read_be_u32(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `u16`. + /// + /// `u16`s are 2 bytes long. + fn read_be_u16(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `i64`. + /// + /// `i64`s are 8 bytes long. + fn read_be_i64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `i32`. + /// + /// `i32`s are 4 bytes long. + fn read_be_i32(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `i16`. + /// + /// `i16`s are 2 bytes long. + fn read_be_i16(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `f64`. + /// + /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. + fn read_be_f64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a big-endian `f32`. + /// + /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. + fn read_be_f32(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `u64`. + /// + /// `u64`s are 8 bytes long. + fn read_le_u64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `u32`. + /// + /// `u32`s are 4 bytes long. + fn read_le_u32(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `u16`. + /// + /// `u16`s are 2 bytes long. + fn read_le_u16(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `i64`. + /// + /// `i64`s are 8 bytes long. + fn read_le_i64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `i32`. + /// + /// `i32`s are 4 bytes long. + fn read_le_i32(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `i16`. + /// + /// `i16`s are 2 bytes long. + fn read_le_i16(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `f64`. + /// + /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. + fn read_le_f64(&mut self) -> IoResult { unimplemented!() } + + /// Reads a little-endian `f32`. + /// + /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. + fn read_le_f32(&mut self) -> IoResult { unimplemented!() } + + /// Read a u8. + /// + /// `u8`s are 1 byte. + fn read_u8(&mut self) -> IoResult { unimplemented!() } + + /// Read an i8. + /// + /// `i8`s are 1 byte. + fn read_i8(&mut self) -> IoResult { unimplemented!() } +} + +/// A reader which can be converted to a RefReader. +#[deprecated = "use ByRefReader instead"] +pub trait AsRefReader { + /// Creates a wrapper around a mutable reference to the reader. + /// + /// This is useful to allow applying adaptors while still + /// retaining ownership of the original value. + fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; +} + +#[allow(deprecated)] +impl AsRefReader for T { + fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { unimplemented!() } +} + +/// A reader which can be converted to a RefReader. +pub trait ByRefReader { + /// Creates a wrapper around a mutable reference to the reader. + /// + /// This is useful to allow applying adaptors while still + /// retaining ownership of the original value. + fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; +} + +impl ByRefReader for T { + fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { unimplemented!() } +} + +/// A reader which can be converted to bytes. +pub trait BytesReader { + /// Create an iterator that reads a single byte on + /// each iteration, until EOF. + /// + /// # Error + /// + /// Any error other than `EndOfFile` that is produced by the underlying Reader + /// is returned by the iterator and should be handled by the caller. + fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self>; +} + +impl BytesReader for T { + fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { unimplemented!() } +} + +impl<'a> Reader for Box { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl<'a> Reader for &'a mut Reader+'a { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +/// Returns a slice of `v` between `start` and `end`. +/// +/// Similar to `slice()` except this function only bounds the slice on the +/// capacity of `v`, not the length. +/// +/// # Panics +/// +/// Panics when `start` or `end` point outside the capacity of `v`, or when +/// `start` > `end`. +// Private function here because we aren't sure if we want to expose this as +// API yet. If so, it should be a method on Vec. +unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) -> &'a mut [T] { unimplemented!() } + +/// A `RefReader` is a struct implementing `Reader` which contains a reference +/// to another reader. This is often useful when composing streams. +/// +/// # Example +/// +/// ``` +/// # fn main() {} +/// # fn process_input(r: R) {} +/// # fn foo() { +/// use std::io; +/// use std::io::ByRefReader; +/// use std::io::util::LimitReader; +/// +/// let mut stream = io::stdin(); +/// +/// // Only allow the function to process at most one kilobyte of input +/// { +/// let stream = LimitReader::new(stream.by_ref(), 1024); +/// process_input(stream); +/// } +/// +/// // 'stream' is still available for use here +/// +/// # } +/// ``` +pub struct RefReader<'a, R:'a> { + /// The underlying reader which this is referencing + inner: &'a mut R +} + +impl<'a, R: Reader> Reader for RefReader<'a, R> { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl<'a, R: Buffer> Buffer for RefReader<'a, R> { + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } + fn consume(&mut self, amt: uint) { unimplemented!() } +} + +fn extend_sign(val: u64, nbytes: uint) -> i64 { unimplemented!() } + +/// A trait for objects which are byte-oriented streams. Writers are defined by +/// one method, `write`. This function will block until the provided buffer of +/// bytes has been entirely written, and it will return any failures which occur. +/// +/// Another commonly overridden method is the `flush` method for writers such as +/// buffered writers. +/// +/// Writers are intended to be composable with one another. Many objects +/// throughout the I/O and related libraries take and provide types which +/// implement the `Writer` trait. +pub trait Writer { + /// Write the entirety of a given buffer + /// + /// # Errors + /// + /// If an error happens during the I/O operation, the error is returned as + /// `Err`. Note that it is considered an error if the entire buffer could + /// not be written, and if an error is returned then it is unknown how much + /// data (if any) was actually written. + fn write(&mut self, buf: &[u8]) -> IoResult<()>; + + /// Flush this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// This is by default a no-op and implementers of the `Writer` trait should + /// decide whether their stream needs to be buffered or not. + fn flush(&mut self) -> IoResult<()> { unimplemented!() } + + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the `format_args!` + /// macro, but it is rare that this should explicitly be called. The + /// `write!` macro should be favored to invoke this method instead. + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> { unimplemented!() } + + /// Write a rust string into this sink. + /// + /// The bytes written will be the UTF-8 encoded version of the input string. + /// If other encodings are desired, it is recommended to compose this stream + /// with another performing the conversion, or to use `write` with a + /// converted byte-array instead. + #[inline] + fn write_str(&mut self, s: &str) -> IoResult<()> { unimplemented!() } + + /// Writes a string into this sink, and then writes a literal newline (`\n`) + /// byte afterwards. Note that the writing of the newline is *not* atomic in + /// the sense that the call to `write` is invoked twice (once with the + /// string and once with a newline character). + /// + /// If other encodings or line ending flavors are desired, it is recommended + /// that the `write` method is used specifically instead. + #[inline] + fn write_line(&mut self, s: &str) -> IoResult<()> { unimplemented!() } + + /// Write a single char, encoded as UTF-8. + #[inline] + fn write_char(&mut self, c: char) -> IoResult<()> { unimplemented!() } + + /// Write the result of passing n through `int::to_str_bytes`. + #[inline] + fn write_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } + + /// Write the result of passing n through `uint::to_str_bytes`. + #[inline] + fn write_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian uint (number of bytes depends on system). + #[inline] + fn write_le_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian int (number of bytes depends on system). + #[inline] + fn write_le_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian uint (number of bytes depends on system). + #[inline] + fn write_be_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian int (number of bytes depends on system). + #[inline] + fn write_be_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian u64 (8 bytes). + #[inline] + fn write_be_u64(&mut self, n: u64) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian u32 (4 bytes). + #[inline] + fn write_be_u32(&mut self, n: u32) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian u16 (2 bytes). + #[inline] + fn write_be_u16(&mut self, n: u16) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian i64 (8 bytes). + #[inline] + fn write_be_i64(&mut self, n: i64) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian i32 (4 bytes). + #[inline] + fn write_be_i32(&mut self, n: i32) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian i16 (2 bytes). + #[inline] + fn write_be_i16(&mut self, n: i16) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). + #[inline] + fn write_be_f64(&mut self, f: f64) -> IoResult<()> { unimplemented!() } + + /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). + #[inline] + fn write_be_f32(&mut self, f: f32) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian u64 (8 bytes). + #[inline] + fn write_le_u64(&mut self, n: u64) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian u32 (4 bytes). + #[inline] + fn write_le_u32(&mut self, n: u32) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian u16 (2 bytes). + #[inline] + fn write_le_u16(&mut self, n: u16) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian i64 (8 bytes). + #[inline] + fn write_le_i64(&mut self, n: i64) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian i32 (4 bytes). + #[inline] + fn write_le_i32(&mut self, n: i32) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian i16 (2 bytes). + #[inline] + fn write_le_i16(&mut self, n: i16) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian IEEE754 double-precision floating-point + /// (8 bytes). + #[inline] + fn write_le_f64(&mut self, f: f64) -> IoResult<()> { unimplemented!() } + + /// Write a little-endian IEEE754 single-precision floating-point + /// (4 bytes). + #[inline] + fn write_le_f32(&mut self, f: f32) -> IoResult<()> { unimplemented!() } + + /// Write a u8 (1 byte). + #[inline] + fn write_u8(&mut self, n: u8) -> IoResult<()> { unimplemented!() } + + /// Write an i8 (1 byte). + #[inline] + fn write_i8(&mut self, n: i8) -> IoResult<()> { unimplemented!() } +} + +/// A writer which can be converted to a RefWriter. +#[deprecated = "use ByRefWriter instead"] +pub trait AsRefWriter { + /// Creates a wrapper around a mutable reference to the writer. + /// + /// This is useful to allow applying wrappers while still + /// retaining ownership of the original value. + #[inline] + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; +} + +#[allow(deprecated)] +impl AsRefWriter for T { + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { unimplemented!() } +} + +/// A writer which can be converted to a RefWriter. +pub trait ByRefWriter { + /// Creates a wrapper around a mutable reference to the writer. + /// + /// This is useful to allow applying wrappers while still + /// retaining ownership of the original value. + #[inline] + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; +} + +impl ByRefWriter for T { + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { + RefWriter { inner: self } + } +} + +impl<'a> Writer for Box { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + #[inline] + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl<'a> Writer for &'a mut Writer+'a { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + #[inline] + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + +/// A `RefWriter` is a struct implementing `Writer` which contains a reference +/// to another writer. This is often useful when composing streams. +/// +/// # Example +/// +/// ``` +/// # fn main() {} +/// # fn process_input(r: R) {} +/// # fn foo () { +/// use std::io::util::TeeReader; +/// use std::io::{stdin, ByRefWriter}; +/// +/// let mut output = Vec::new(); +/// +/// { +/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a +/// // handle to it in the outer scope +/// let mut tee = TeeReader::new(stdin(), output.by_ref()); +/// process_input(tee); +/// } +/// +/// println!("input processed: {}", output); +/// # } +/// ``` +pub struct RefWriter<'a, W:'a> { + /// The underlying writer which this is referencing + inner: &'a mut W +} + +impl<'a, W: Writer> Writer for RefWriter<'a, W> { + #[inline] + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + #[inline] + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + + +/// A Stream is a readable and a writable object. Data written is typically +/// received by the object which reads receive data from. +pub trait Stream: Reader + Writer { } + +impl Stream for T {} + +/// An iterator that reads a line on each iteration, +/// until `.read_line()` encounters `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Lines` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +pub struct Lines<'r, T:'r> { + buffer: &'r mut T, +} + +impl<'r, T: Buffer> Iterator> for Lines<'r, T> { + fn next(&mut self) -> Option> { unimplemented!() } +} + +/// An iterator that reads a utf8-encoded character on each iteration, +/// until `.read_char()` encounters `EndOfFile`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `Chars` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Error +/// +/// Any error other than `EndOfFile` that is produced by the underlying Reader +/// is returned by the iterator and should be handled by the caller. +pub struct Chars<'r, T:'r> { + buffer: &'r mut T +} + +impl<'r, T: Buffer> Iterator> for Chars<'r, T> { + fn next(&mut self) -> Option> { unimplemented!() } +} + +/// A Buffer is a type of reader which has some form of internal buffering to +/// allow certain kinds of reading operations to be more optimized than others. +/// This type extends the `Reader` trait with a few methods that are not +/// possible to reasonably implement with purely a read interface. +pub trait Buffer: Reader { + /// Fills the internal buffer of this object, returning the buffer contents. + /// Note that none of the contents will be "read" in the sense that later + /// calling `read` may return the same contents. + /// + /// The `consume` function must be called with the number of bytes that are + /// consumed from this buffer returned to ensure that the bytes are never + /// returned twice. + /// + /// # Error + /// + /// This function will return an I/O error if the underlying reader was + /// read, but returned an error. Note that it is not an error to return a + /// 0-length buffer. + fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]>; + + /// Tells this buffer that `amt` bytes have been consumed from the buffer, + /// so they should no longer be returned in calls to `read`. + fn consume(&mut self, amt: uint); + + /// Reads the next line of input, interpreted as a sequence of UTF-8 + /// encoded Unicode codepoints. If a newline is encountered, then the + /// newline is contained in the returned string. + /// + /// # Example + /// + /// ```rust + /// use std::io; + /// + /// let mut reader = io::stdin(); + /// let input = reader.read_line().ok().unwrap_or("nothing".to_string()); + /// ``` + /// + /// # Error + /// + /// This function has the same error semantics as `read_until`: + /// + /// * All non-EOF errors will be returned immediately + /// * If an error is returned previously consumed bytes are lost + /// * EOF is only returned if no bytes have been read + /// * Reach EOF may mean that the delimiter is not present in the return + /// value + /// + /// Additionally, this function can fail if the line of input read is not a + /// valid UTF-8 sequence of bytes. + fn read_line(&mut self) -> IoResult { unimplemented!() } + + /// Reads a sequence of bytes leading up to a specified delimiter. Once the + /// specified byte is encountered, reading ceases and the bytes up to and + /// including the delimiter are returned. + /// + /// # Error + /// + /// If any I/O error is encountered other than EOF, the error is immediately + /// returned. Note that this may discard bytes which have already been read, + /// and those bytes will *not* be returned. It is recommended to use other + /// methods if this case is worrying. + /// + /// If EOF is encountered, then this function will return EOF if 0 bytes + /// have been read, otherwise the pending byte buffer is returned. This + /// is the reason that the byte buffer returned may not always contain the + /// delimiter. + fn read_until(&mut self, byte: u8) -> IoResult> { unimplemented!() } + + /// Reads the next utf8-encoded character from the underlying stream. + /// + /// # Error + /// + /// If an I/O error occurs, or EOF, then this function will return `Err`. + /// This function will also return error if the stream does not contain a + /// valid utf-8 encoded codepoint as the next few bytes in the stream. + fn read_char(&mut self) -> IoResult { unimplemented!() } +} + +/// Extension methods for the Buffer trait which are included in the prelude. +pub trait BufferPrelude { + /// Create an iterator that reads a utf8-encoded character on each iteration + /// until EOF. + /// + /// # Error + /// + /// Any error other than `EndOfFile` that is produced by the underlying Reader + /// is returned by the iterator and should be handled by the caller. + fn chars<'r>(&'r mut self) -> Chars<'r, Self>; + + /// Create an iterator that reads a line on each iteration until EOF. + /// + /// # Error + /// + /// Any error other than `EndOfFile` that is produced by the underlying Reader + /// is returned by the iterator and should be handled by the caller. + fn lines<'r>(&'r mut self) -> Lines<'r, Self>; +} + +impl BufferPrelude for T { + fn chars<'r>(&'r mut self) -> Chars<'r, T> { unimplemented!() } + + fn lines<'r>(&'r mut self) -> Lines<'r, T> { unimplemented!() } +} + +/// When seeking, the resulting cursor is offset from a base by the offset given +/// to the `seek` function. The base used is specified by this enumeration. +pub enum SeekStyle { + /// Seek from the beginning of the stream + SeekSet, + /// Seek from the end of the stream + SeekEnd, + /// Seek from the current position + SeekCur, +} + +/// An object implementing `Seek` internally has some form of cursor which can +/// be moved within a stream of bytes. The stream typically has a fixed size, +/// allowing seeking relative to either end. +pub trait Seek { + /// Return position of file cursor in the stream + fn tell(&self) -> IoResult; + + /// Seek to an offset in a stream + /// + /// A successful seek clears the EOF indicator. Seeking beyond EOF is + /// allowed, but seeking before position 0 is not allowed. + /// + /// # Errors + /// + /// * Seeking to a negative offset is considered an error + /// * Seeking past the end of the stream does not modify the underlying + /// stream, but the next write may cause the previous data to be filled in + /// with a bit pattern. + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; +} + +/// A listener is a value that can consume itself to start listening for +/// connections. +/// +/// Doing so produces some sort of Acceptor. +pub trait Listener> { + /// Spin up the listener and start queuing incoming connections + /// + /// # Error + /// + /// Returns `Err` if this listener could not be bound to listen for + /// connections. In all cases, this listener is consumed. + fn listen(self) -> IoResult; +} + +/// An acceptor is a value that presents incoming connections +pub trait Acceptor { + /// Wait for and accept an incoming connection + /// + /// # Error + /// + /// Returns `Err` if an I/O error is encountered. + fn accept(&mut self) -> IoResult; + + /// Create an iterator over incoming connection attempts. + /// + /// Note that I/O errors will be yielded by the iterator itself. + fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { unimplemented!() } +} + +/// An infinite iterator over incoming connection attempts. +/// Calling `next` will block the task until a connection is attempted. +/// +/// Since connection attempts can continue forever, this iterator always returns +/// `Some`. The `Some` contains the `IoResult` representing whether the +/// connection attempt was successful. A successful connection will be wrapped +/// in `Ok`. A failed connection is represented as an `Err`. +pub struct IncomingConnections<'a, A:'a> { + inc: &'a mut A, +} + +impl<'a, T, A: Acceptor> Iterator> for IncomingConnections<'a, A> { + fn next(&mut self) -> Option> { unimplemented!() } +} + +/// Creates a standard error for a commonly used flavor of error. The `detail` +/// field of the returned error will always be `None`. +/// +/// # Example +/// +/// ``` +/// use std::io; +/// +/// let eof = io::standard_error(io::EndOfFile); +/// let einval = io::standard_error(io::InvalidInput); +/// ``` +pub fn standard_error(kind: IoErrorKind) -> IoError { unimplemented!() } + +/// A mode specifies how a file should be opened or created. These modes are +/// passed to `File::open_mode` and are used to control where the file is +/// positioned when it is initially opened. +pub enum FileMode { + /// Opens a file positioned at the beginning. + Open, + /// Opens a file positioned at EOF. + Append, + /// Opens a file, truncating it if it already exists. + Truncate, +} + +/// Access permissions with which the file should be opened. `File`s +/// opened with `Read` will return an error if written to. +pub enum FileAccess { + /// Read-only access, requests to write will result in an error + Read, + /// Write-only access, requests to read will result in an error + Write, + /// Read-write access, no requests are denied by default + ReadWrite, +} + +/// Different kinds of files which can be identified by a call to stat +#[deriving(PartialEq, Show, Hash, Clone)] +pub enum FileType { + /// This is a normal file, corresponding to `S_IFREG` + TypeFile, + + /// This file is a directory, corresponding to `S_IFDIR` + TypeDirectory, + + /// This file is a named pipe, corresponding to `S_IFIFO` + TypeNamedPipe, + + /// This file is a block device, corresponding to `S_IFBLK` + TypeBlockSpecial, + + /// This file is a symbolic link to another file, corresponding to `S_IFLNK` + TypeSymlink, + + /// The type of this file is not recognized as one of the other categories + TypeUnknown, +} + +/// A structure used to describe metadata information about a file. This +/// structure is created through the `stat` method on a `Path`. +/// +/// # Example +/// +/// ``` +/// # use std::io::fs::PathExtensions; +/// # fn main() {} +/// # fn foo() { +/// let info = match Path::new("foo.txt").stat() { +/// Ok(stat) => stat, +/// Err(e) => panic!("couldn't read foo.txt: {}", e), +/// }; +/// +/// println!("byte size: {}", info.size); +/// # } +/// ``` +#[deriving(Hash)] +pub struct FileStat { + /// The size of the file, in bytes + pub size: u64, + /// The kind of file this path points to (directory, file, pipe, etc.) + pub kind: FileType, + /// The file permissions currently on the file + pub perm: FilePermission, + + // FIXME(#10301): These time fields are pretty useless without an actual + // time representation, what are the milliseconds relative + // to? + + /// The time that the file was created at, in platform-dependent + /// milliseconds + pub created: u64, + /// The time that this file was last modified, in platform-dependent + /// milliseconds + pub modified: u64, + /// The time that this file was last accessed, in platform-dependent + /// milliseconds + pub accessed: u64, + + /// Information returned by stat() which is not guaranteed to be + /// platform-independent. This information may be useful on some platforms, + /// but it may have different meanings or no meaning at all on other + /// platforms. + /// + /// Usage of this field is discouraged, but if access is desired then the + /// fields are located here. + #[unstable] + pub unstable: UnstableFileStat, +} + +/// This structure represents all of the possible information which can be +/// returned from a `stat` syscall which is not contained in the `FileStat` +/// structure. This information is not necessarily platform independent, and may +/// have different meanings or no meaning at all on some platforms. +#[unstable] +#[deriving(Hash)] +pub struct UnstableFileStat { + /// The ID of the device containing the file. + pub device: u64, + /// The file serial number. + pub inode: u64, + /// The device ID. + pub rdev: u64, + /// The number of hard links to this file. + pub nlink: u64, + /// The user ID of the file. + pub uid: u64, + /// The group ID of the file. + pub gid: u64, + /// The optimal block size for I/O. + pub blksize: u64, + /// The blocks allocated for this file. + pub blocks: u64, + /// User-defined flags for the file. + pub flags: u64, + /// The file generation number. + pub gen: u64, +} + +bitflags! { + #[doc = "A set of permissions for a file or directory is represented"] + #[doc = "by a set of flags which are or'd together."] + flags FilePermission: u32 { + const USER_READ = 0o400, + const USER_WRITE = 0o200, + const USER_EXECUTE = 0o100, + const GROUP_READ = 0o040, + const GROUP_WRITE = 0o020, + const GROUP_EXECUTE = 0o010, + const OTHER_READ = 0o004, + const OTHER_WRITE = 0o002, + const OTHER_EXECUTE = 0o001, + + const USER_RWX = USER_READ.bits | USER_WRITE.bits | USER_EXECUTE.bits, + const GROUP_RWX = GROUP_READ.bits | GROUP_WRITE.bits | GROUP_EXECUTE.bits, + const OTHER_RWX = OTHER_READ.bits | OTHER_WRITE.bits | OTHER_EXECUTE.bits, + + #[doc = "Permissions for user owned files, equivalent to 0644 on"] + #[doc = "unix-like systems."] + const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, + + #[doc = "Permissions for user owned directories, equivalent to 0755 on"] + #[doc = "unix-like systems."] + const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | + OTHER_READ.bits | OTHER_EXECUTE.bits, + + #[doc = "Permissions for user owned executables, equivalent to 0755"] + #[doc = "on unix-like systems."] + const USER_EXEC = USER_DIR.bits, + + #[doc = "All possible permissions enabled."] + const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, + + // Deprecated names + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_READ instead"] + const UserRead = USER_READ.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_WRITE instead"] + const UserWrite = USER_WRITE.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_EXECUTE instead"] + const UserExecute = USER_EXECUTE.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use GROUP_READ instead"] + const GroupRead = GROUP_READ.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use GROUP_WRITE instead"] + const GroupWrite = GROUP_WRITE.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use GROUP_EXECUTE instead"] + const GroupExecute = GROUP_EXECUTE.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use OTHER_READ instead"] + const OtherRead = OTHER_READ.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use OTHER_WRITE instead"] + const OtherWrite = OTHER_WRITE.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use OTHER_EXECUTE instead"] + const OtherExecute = OTHER_EXECUTE.bits, + + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_RWX instead"] + const UserRWX = USER_RWX.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use GROUP_RWX instead"] + const GroupRWX = GROUP_RWX.bits, + #[allow(non_upper_case_globals)] + #[deprecated = "use OTHER_RWX instead"] + const OtherRWX = OTHER_RWX.bits, + + #[doc = "Deprecated: use `USER_FILE` instead."] + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_FILE instead"] + const UserFile = USER_FILE.bits, + + #[doc = "Deprecated: use `USER_DIR` instead."] + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_DIR instead"] + const UserDir = USER_DIR.bits, + #[doc = "Deprecated: use `USER_EXEC` instead."] + #[allow(non_upper_case_globals)] + #[deprecated = "use USER_EXEC instead"] + const UserExec = USER_EXEC.bits, + + #[doc = "Deprecated: use `ALL_PERMISSIONS` instead"] + #[allow(non_upper_case_globals)] + #[deprecated = "use ALL_PERMISSIONS instead"] + const AllPermissions = ALL_PERMISSIONS.bits, + } +} + +impl Default for FilePermission { + #[inline] + fn default() -> FilePermission { unimplemented!() } +} + +impl fmt::Show for FilePermission { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} diff --git a/src/libst2/io/net/addrinfo.rs b/src/libst2/io/net/addrinfo.rs new file mode 100644 index 0000000000000..ee7ede39e4a80 --- /dev/null +++ b/src/libst2/io/net/addrinfo.rs @@ -0,0 +1,96 @@ +// Copyright 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. + +/*! + +Synchronous DNS Resolution + +Contains the functionality to perform DNS resolution in a style related to +getaddrinfo() + +*/ + +#![allow(missing_docs)] + +pub use self::SocketType::*; +pub use self::Flag::*; +pub use self::Protocol::*; + +use iter::Iterator; +use io::{IoResult}; +use io::net::ip::{SocketAddr, IpAddr}; +use option::{Option, Some, None}; +use sys; +use vec::Vec; + +/// Hints to the types of sockets that are desired when looking up hosts +pub enum SocketType { + Stream, Datagram, Raw +} + +/// Flags which can be or'd into the `flags` field of a `Hint`. These are used +/// to manipulate how a query is performed. +/// +/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` +pub enum Flag { + AddrConfig, + All, + CanonName, + NumericHost, + NumericServ, + Passive, + V4Mapped, +} + +/// A transport protocol associated with either a hint or a return value of +/// `lookup` +pub enum Protocol { + TCP, UDP +} + +/// This structure is used to provide hints when fetching addresses for a +/// remote host to control how the lookup is performed. +/// +/// For details on these fields, see their corresponding definitions via +/// `man -s 3 getaddrinfo` +pub struct Hint { + pub family: uint, + pub socktype: Option, + pub protocol: Option, + pub flags: uint, +} + +pub struct Info { + pub address: SocketAddr, + pub family: uint, + pub socktype: Option, + pub protocol: Option, + pub flags: uint, +} + +/// Easy name resolution. Given a hostname, returns the list of IP addresses for +/// that hostname. +pub fn get_host_addresses(host: &str) -> IoResult> { unimplemented!() } + +/// Full-fledged resolution. This function will perform a synchronous call to +/// getaddrinfo, controlled by the parameters +/// +/// # Arguments +/// +/// * hostname - an optional hostname to lookup against +/// * servname - an optional service name, listed in the system services +/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this +/// controls lookup +/// +/// FIXME: this is not public because the `Hint` structure is not ready for public +/// consumption just yet. +#[allow(unused_variables)] +fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option) + -> IoResult> { unimplemented!() } diff --git a/src/libst2/io/net/ip.rs b/src/libst2/io/net/ip.rs new file mode 100644 index 0000000000000..478956b28fc1c --- /dev/null +++ b/src/libst2/io/net/ip.rs @@ -0,0 +1,231 @@ +// Copyright 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. + +//! Internet Protocol (IP) addresses. +//! +//! This module contains functions useful for parsing, formatting, and +//! manipulating IP addresses. + +#![allow(missing_docs)] + +pub use self::IpAddr::*; + +use fmt; +use io::{mod, IoResult, IoError}; +use io::net; +use iter::Iterator; +use option::{Option, None, Some}; +use result::{Ok, Err}; +use str::{FromStr, StrPrelude}; +use slice::{CloneSlicePrelude, SlicePrelude}; +use vec::Vec; + +pub type Port = u16; + +#[deriving(PartialEq, Eq, Clone, Hash)] +pub enum IpAddr { + Ipv4Addr(u8, u8, u8, u8), + Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16) +} + +impl fmt::Show for IpAddr { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +#[deriving(PartialEq, Eq, Clone, Hash)] +pub struct SocketAddr { + pub ip: IpAddr, + pub port: Port, +} + +impl fmt::Show for SocketAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +struct Parser<'a> { + // parsing as ASCII, so can use byte array + s: &'a [u8], + pos: uint, +} + +impl<'a> Parser<'a> { + fn new(s: &'a str) -> Parser<'a> { unimplemented!() } + + fn is_eof(&self) -> bool { unimplemented!() } + + // Commit only if parser returns Some + fn read_atomically(&mut self, cb: |&mut Parser| -> Option) + -> Option { unimplemented!() } + + // Commit only if parser read till EOF + fn read_till_eof(&mut self, cb: |&mut Parser| -> Option) + -> Option { unimplemented!() } + + // Return result of first successful parser + fn read_or(&mut self, parsers: &mut [|&mut Parser| -> Option]) + -> Option { unimplemented!() } + + // Apply 3 parsers sequentially + fn read_seq_3( + &mut self, + pa: |&mut Parser| -> Option, + pb: |&mut Parser| -> Option, + pc: |&mut Parser| -> Option) + -> Option<(A, B, C)> { unimplemented!() } + + // Read next char + fn read_char(&mut self) -> Option { unimplemented!() } + + // Return char and advance iff next char is equal to requested + fn read_given_char(&mut self, c: char) -> Option { unimplemented!() } + + // Read digit + fn read_digit(&mut self, radix: u8) -> Option { unimplemented!() } + + fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { unimplemented!() } + + // Read number, failing if max_digits of number value exceeded + fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { unimplemented!() } + + fn read_ipv4_addr_impl(&mut self) -> Option { unimplemented!() } + + // Read IPv4 address + fn read_ipv4_addr(&mut self) -> Option { unimplemented!() } + + fn read_ipv6_addr_impl(&mut self) -> Option { unimplemented!() } + + fn read_ipv6_addr(&mut self) -> Option { unimplemented!() } + + fn read_ip_addr(&mut self) -> Option { unimplemented!() } + + fn read_socket_addr(&mut self) -> Option { unimplemented!() } +} + +impl FromStr for IpAddr { + fn from_str(s: &str) -> Option { unimplemented!() } +} + +impl FromStr for SocketAddr { + fn from_str(s: &str) -> Option { unimplemented!() } +} + +/// A trait for objects which can be converted or resolved to one or more `SocketAddr` values. +/// +/// Implementing types minimally have to implement either `to_socket_addr` or `to_socket_addr_all` +/// method, and its trivial counterpart will be available automatically. +/// +/// This trait is used for generic address resolution when constructing network objects. +/// By default it is implemented for the following types: +/// +/// * `SocketAddr` - `to_socket_addr` is identity function. +/// +/// * `(IpAddr, u16)` - `to_socket_addr` constructs `SocketAddr` trivially. +/// +/// * `(&str, u16)` - the string should be either a string representation of an IP address +/// expected by `FromStr` implementation for `IpAddr` or a host name. +/// +/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding +/// to that IP address joined with the given port. +/// +/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses +/// for the host name, each joined with the given port. +/// +/// * `&str` - the string should be either a string representation of a `SocketAddr` as +/// expected by its `FromStr` implementation or a string like `:` pair +/// where `` is a `u16` value. +/// +/// For the former, `to_socker_addr_all` returns a vector with a single element corresponding +/// to that socker address. +/// +/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses +/// for the host name, each joined with the port. +/// +/// +/// This trait allows constructing network objects like `TcpStream` or `UdpSocket` easily with +/// values of various types for the bind/connection address. It is needed because sometimes +/// one type is more appropriate than the other: for simple uses a string like `"localhost:12345"` +/// is much nicer than manual construction of the corresponding `SocketAddr`, but sometimes +/// `SocketAddr` value is *the* main source of the address, and converting it to some other type +/// (e.g. a string) just for it to be converted back to `SocketAddr` in constructor methods +/// is pointless. +/// +/// Some examples: +/// +/// ```rust,no_run +/// # #![allow(unused_must_use)] +/// +/// use std::io::{TcpStream, TcpListener}; +/// use std::io::net::udp::UdpSocket; +/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; +/// +/// fn main() { +/// // The following lines are equivalent modulo possible "localhost" name resolution +/// // differences +/// let tcp_s = TcpStream::connect(SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 12345 }); +/// let tcp_s = TcpStream::connect((Ipv4Addr(127, 0, 0, 1), 12345u16)); +/// let tcp_s = TcpStream::connect(("127.0.0.1", 12345u16)); +/// let tcp_s = TcpStream::connect(("localhost", 12345u16)); +/// let tcp_s = TcpStream::connect("127.0.0.1:12345"); +/// let tcp_s = TcpStream::connect("localhost:12345"); +/// +/// // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to() behave similarly +/// let tcp_l = TcpListener::bind("localhost:12345"); +/// +/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451u16)).unwrap(); +/// udp_s.send_to([7u8, 7u8, 7u8].as_slice(), (Ipv4Addr(127, 0, 0, 1), 23451u16)); +/// } +/// ``` +pub trait ToSocketAddr { + /// Converts this object to single socket address value. + /// + /// If more than one value is available, this method returns the first one. If no + /// values are available, this method returns an `IoError`. + /// + /// By default this method delegates to `to_socket_addr_all` method, taking the first + /// item from its result. + fn to_socket_addr(&self) -> IoResult { unimplemented!() } + + /// Converts this object to all available socket address values. + /// + /// Some values like host name string naturally corrrespond to multiple IP addresses. + /// This method tries to return all available addresses corresponding to this object. + /// + /// By default this method delegates to `to_socket_addr` method, creating a singleton + /// vector from its result. + #[inline] + fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } +} + +impl ToSocketAddr for SocketAddr { + #[inline] + fn to_socket_addr(&self) -> IoResult { unimplemented!() } +} + +impl ToSocketAddr for (IpAddr, u16) { + #[inline] + fn to_socket_addr(&self) -> IoResult { unimplemented!() } +} + +fn resolve_socket_addr(s: &str, p: u16) -> IoResult> { unimplemented!() } + +fn parse_and_resolve_socket_addr(s: &str) -> IoResult> { unimplemented!() } + +impl<'a> ToSocketAddr for (&'a str, u16) { + fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } +} + +// accepts strings like 'localhost:12345' +impl<'a> ToSocketAddr for &'a str { + fn to_socket_addr(&self) -> IoResult { unimplemented!() } + + fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } +} diff --git a/src/libst2/io/net/mod.rs b/src/libst2/io/net/mod.rs new file mode 100644 index 0000000000000..00d57cf317e68 --- /dev/null +++ b/src/libst2/io/net/mod.rs @@ -0,0 +1,27 @@ +// Copyright 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. + +//! Networking I/O + +use io::{IoError, IoResult, InvalidInput}; +use option::None; +use result::{Ok, Err}; +use self::ip::{SocketAddr, ToSocketAddr}; + +pub use self::addrinfo::get_host_addresses; + +pub mod addrinfo; +pub mod tcp; +pub mod udp; +pub mod ip; +pub mod pipe; + +fn with_addresses(addr: A, action: |SocketAddr| -> IoResult) + -> IoResult { unimplemented!() } diff --git a/src/libst2/io/net/pipe.rs b/src/libst2/io/net/pipe.rs new file mode 100644 index 0000000000000..e52462ed3fa5e --- /dev/null +++ b/src/libst2/io/net/pipe.rs @@ -0,0 +1,206 @@ +// Copyright 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. + +/*! + +Named pipes + +This module contains the ability to communicate over named pipes with +synchronous I/O. On windows, this corresponds to talking over a Named Pipe, +while on Unix it corresponds to UNIX domain sockets. + +These pipes are similar to TCP in the sense that you can have both a stream to a +server and a server itself. The server provided accepts other `UnixStream` +instances as clients. + +*/ + +#![allow(missing_docs)] + +use prelude::*; + +use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; +use time::Duration; + +use sys::pipe::UnixStream as UnixStreamImp; +use sys::pipe::UnixListener as UnixListenerImp; +use sys::pipe::UnixAcceptor as UnixAcceptorImp; + +/// A stream which communicates over a named pipe. +pub struct UnixStream { + inner: UnixStreamImp, +} + +impl UnixStream { + + /// Connect to a pipe named by `path`. This will attempt to open a + /// connection to the underlying socket. + /// + /// The returned stream will be closed when the object falls out of scope. + /// + /// # Example + /// + /// ```rust + /// # #![allow(unused_must_use)] + /// use std::io::net::pipe::UnixStream; + /// + /// let server = Path::new("path/to/my/socket"); + /// let mut stream = UnixStream::connect(&server); + /// stream.write(&[1, 2, 3]); + /// ``` + pub fn connect(path: &P) -> IoResult { unimplemented!() } + + /// Connect to a pipe named by `path`, timing out if the specified number of + /// milliseconds. + /// + /// This function is similar to `connect`, except that if `timeout` + /// elapses the function will return an error of kind `TimedOut`. + /// + /// If a `timeout` with zero or negative duration is specified then + /// the function returns `Err`, with the error kind set to `TimedOut`. + #[experimental = "the timeout argument is likely to change types"] + pub fn connect_timeout(path: &P, + timeout: Duration) -> IoResult { unimplemented!() } + + + /// Closes the reading half of this connection. + /// + /// This method will close the reading portion of this connection, causing + /// all pending and future reads to immediately return with an error. + /// + /// Note that this method affects all cloned handles associated with this + /// stream, not just this one handle. + pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } + + /// Closes the writing half of this connection. + /// + /// This method will close the writing portion of this connection, causing + /// all pending and future writes to immediately return with an error. + /// + /// Note that this method affects all cloned handles associated with this + /// stream, not just this one handle. + pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } + + /// Sets the read/write timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the read timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the write timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } +} + +impl Clone for UnixStream { + fn clone(&self) -> UnixStream { unimplemented!() } +} + +impl Reader for UnixStream { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for UnixStream { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +/// A value that can listen for incoming named pipe connection requests. +pub struct UnixListener { + /// The internal, opaque runtime Unix listener. + inner: UnixListenerImp, +} + +impl UnixListener { + /// Creates a new listener, ready to receive incoming connections on the + /// specified socket. The server will be named by `path`. + /// + /// This listener will be closed when it falls out of scope. + /// + /// # Example + /// + /// ``` + /// # fn main() {} + /// # fn foo() { + /// # #![allow(unused_must_use)] + /// use std::io::net::pipe::UnixListener; + /// use std::io::{Listener, Acceptor}; + /// + /// let server = Path::new("/path/to/my/socket"); + /// let stream = UnixListener::bind(&server); + /// for mut client in stream.listen().incoming() { + /// client.write(&[1, 2, 3, 4]); + /// } + /// # } + /// ``` + pub fn bind(path: &P) -> IoResult { unimplemented!() } +} + +impl Listener for UnixListener { + fn listen(self) -> IoResult { unimplemented!() } +} + +/// A value that can accept named pipe connections, returned from `listen()`. +pub struct UnixAcceptor { + /// The internal, opaque runtime Unix acceptor. + inner: UnixAcceptorImp +} + +impl UnixAcceptor { + /// Sets a timeout for this acceptor, after which accept() will no longer + /// block indefinitely. + /// + /// The argument specified is the amount of time, in milliseconds, into the + /// future after which all invocations of accept() will not block (and any + /// pending invocation will return). A value of `None` will clear any + /// existing timeout. + /// + /// When using this method, it is likely necessary to reset the timeout as + /// appropriate, the timeout specified is specific to this object, not + /// specific to the next request. + #[experimental = "the name and arguments to this function are likely \ + to change"] + pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Closes the accepting capabilities of this acceptor. + /// + /// This function has the same semantics as `TcpAcceptor::close_accept`, and + /// more information can be found in that documentation. + #[experimental] + pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Acceptor for UnixAcceptor { + fn accept(&mut self) -> IoResult { unimplemented!() } +} + +impl Clone for UnixAcceptor { + /// Creates a new handle to this unix acceptor, allowing for simultaneous + /// accepts. + /// + /// The underlying unix acceptor will not be closed until all handles to the + /// acceptor have been deallocated. Incoming connections will be received on + /// at most once acceptor, the same connection will not be accepted twice. + /// + /// The `close_accept` method will shut down *all* acceptors cloned from the + /// same original acceptor, whereas the `set_timeout` method only affects + /// the selector that it is called on. + /// + /// This function is useful for creating a handle to invoke `close_accept` + /// on to wake up any other task blocked in `accept`. + fn clone(&self) -> UnixAcceptor { unimplemented!() } +} diff --git a/src/libst2/io/net/tcp.rs b/src/libst2/io/net/tcp.rs new file mode 100644 index 0000000000000..00a3dc462bbd8 --- /dev/null +++ b/src/libst2/io/net/tcp.rs @@ -0,0 +1,400 @@ +// Copyright 2013-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. + +//! 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. + +use clone::Clone; +use io::IoResult; +use iter::Iterator; +use result::Err; +use io::net::ip::{SocketAddr, ToSocketAddr}; +use io::{Reader, Writer, Listener, Acceptor}; +use io::{standard_error, TimedOut}; +use option::{None, Some, Option}; +use time::Duration; + +use sys::tcp::TcpStream as TcpStreamImp; +use sys::tcp::TcpListener as TcpListenerImp; +use sys::tcp::TcpAcceptor as TcpAcceptorImp; + +/// A structure which represents a TCP stream between a local socket and a +/// remote socket. +/// +/// # Example +/// +/// ```no_run +/// # #![allow(unused_must_use)] +/// use std::io::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254"); +/// +/// stream.write(&[1]); +/// let mut buf = [0]; +/// stream.read(&mut buf); +/// drop(stream); // close the connection +/// ``` +pub struct TcpStream { + inner: TcpStreamImp, +} + +impl TcpStream { + fn new(s: TcpStreamImp) -> TcpStream { unimplemented!() } + + /// Open a TCP connection to a remote host. + /// + /// `addr` is an address of the remote host. Anything which implements `ToSocketAddr` + /// trait can be supplied for the address; see this trait documentation for + /// concrete examples. + pub fn connect(addr: A) -> IoResult { unimplemented!() } + + /// Creates a TCP connection to a remote socket address, timing out after + /// the specified duration. + /// + /// This is the same as the `connect` method, except that if the timeout + /// specified elapses before a connection is made an error will be + /// returned. The error's kind will be `TimedOut`. + /// + /// Same as the `connect` method, `addr` argument type can be anything which + /// implements `ToSocketAddr` trait. + /// + /// If a `timeout` with zero or negative duration is specified then + /// the function returns `Err`, with the error kind set to `TimedOut`. + #[experimental = "the timeout argument may eventually change types"] + pub fn connect_timeout(addr: A, + timeout: Duration) -> IoResult { unimplemented!() } + + /// Returns the socket address of the remote peer of this TCP connection. + pub fn peer_name(&mut self) -> IoResult { unimplemented!() } + + /// Returns the socket address of the local half of this TCP connection. + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } + + /// Sets the nodelay flag on this connection to the boolean specified + #[experimental] + pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { unimplemented!() } + + /// Sets the keepalive timeout to the timeout specified. + /// + /// If the value specified is `None`, then the keepalive flag is cleared on + /// this connection. Otherwise, the keepalive timeout will be set to the + /// specified time, in seconds. + #[experimental] + pub fn set_keepalive(&mut self, delay_in_seconds: Option) -> IoResult<()> { unimplemented!() } + + /// Closes the reading half of this connection. + /// + /// This method will close the reading portion of this connection, causing + /// all pending and future reads to immediately return with an error. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(unused_must_use)] + /// use std::io::timer; + /// use std::io::TcpStream; + /// use std::time::Duration; + /// + /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let stream2 = stream.clone(); + /// + /// spawn(proc() { + /// // close this stream after one second + /// timer::sleep(Duration::seconds(1)); + /// let mut stream = stream2; + /// stream.close_read(); + /// }); + /// + /// // wait for some data, will get canceled after one second + /// let mut buf = [0]; + /// stream.read(&mut buf); + /// ``` + /// + /// Note that this method affects all cloned handles associated with this + /// stream, not just this one handle. + pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } + + /// Closes the writing half of this connection. + /// + /// This method will close the writing portion of this connection, causing + /// all future writes to immediately return with an error. + /// + /// Note that this method affects all cloned handles associated with this + /// stream, not just this one handle. + pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } + + /// Sets a timeout, in milliseconds, for blocking operations on this stream. + /// + /// This function will set a timeout for all blocking operations (including + /// reads and writes) on this stream. The timeout specified is a relative + /// time, in milliseconds, into the future after which point operations will + /// time out. This means that the timeout must be reset periodically to keep + /// it from expiring. Specifying a value of `None` will clear the timeout + /// for this stream. + /// + /// The timeout on this stream is local to this stream only. Setting a + /// timeout does not affect any other cloned instances of this stream, nor + /// does the timeout propagated to cloned handles of this stream. Setting + /// this timeout will override any specific read or write timeouts + /// previously set for this stream. + /// + /// For clarification on the semantics of interrupting a read and a write, + /// take a look at `set_read_timeout` and `set_write_timeout`. + #[experimental = "the timeout argument may change in type and value"] + pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the timeout for read operations on this stream. + /// + /// See documentation in `set_timeout` for the semantics of this read time. + /// This will overwrite any previous read timeout set through either this + /// function or `set_timeout`. + /// + /// # Errors + /// + /// When this timeout expires, if there is no pending read operation, no + /// action is taken. Otherwise, the read operation will be scheduled to + /// promptly return. If a timeout error is returned, then no data was read + /// during the timeout period. + #[experimental = "the timeout argument may change in type and value"] + pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the timeout for write operations on this stream. + /// + /// See documentation in `set_timeout` for the semantics of this write time. + /// This will overwrite any previous write timeout set through either this + /// function or `set_timeout`. + /// + /// # Errors + /// + /// When this timeout expires, if there is no pending write operation, no + /// action is taken. Otherwise, the pending write operation will be + /// scheduled to promptly return. The actual state of the underlying stream + /// is not specified. + /// + /// The write operation may return an error of type `ShortWrite` which + /// indicates that the object is known to have written an exact number of + /// bytes successfully during the timeout period, and the remaining bytes + /// were never written. + /// + /// If the write operation returns `TimedOut`, then it the timeout primitive + /// does not know how many bytes were written as part of the timeout + /// operation. It may be the case that bytes continue to be written in an + /// asynchronous fashion after the call to write returns. + #[experimental = "the timeout argument may change in type and value"] + pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } +} + +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 { unimplemented!() } +} + +impl Reader for TcpStream { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for TcpStream { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} + +/// 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(dead_code)] +/// use std::io::{TcpListener, TcpStream}; +/// use std::io::{Acceptor, Listener}; +/// +/// let listener = TcpListener::bind("127.0.0.1:80"); +/// +/// // bind the listener to the specified address +/// let mut acceptor = listener.listen(); +/// +/// fn handle_client(mut stream: TcpStream) { +/// // ... +/// # &mut stream; // silence unused mutability/variable warning +/// } +/// // accept connections and process them, spawning a new tasks for each one +/// for stream in acceptor.incoming() { +/// match stream { +/// Err(e) => { /* connection failed */ } +/// Ok(stream) => spawn(proc() { +/// // connection succeeded +/// handle_client(stream) +/// }) +/// } +/// } +/// +/// // close the socket server +/// drop(acceptor); +/// # } +/// ``` +pub struct TcpListener { + inner: TcpListenerImp, +} + +impl TcpListener { + /// Creates a new `TcpListener` which will be bound to the specified 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. + /// + /// The address type can be any implementor of `ToSocketAddr` trait. See its + /// documentation for concrete examples. + pub fn bind(addr: A) -> IoResult { unimplemented!() } + + /// Returns the local socket address of this listener. + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } +} + +impl Listener for TcpListener { + fn listen(self) -> IoResult { unimplemented!() } +} + +/// 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 { + inner: TcpAcceptorImp, +} + +impl TcpAcceptor { + /// Prevents blocking on all future accepts after `ms` milliseconds have + /// elapsed. + /// + /// This function is used to set a deadline after which this acceptor will + /// time out accepting any connections. The argument is the relative + /// distance, in milliseconds, to a point in the future after which all + /// accepts will fail. + /// + /// If the argument specified is `None`, then any previously registered + /// timeout is cleared. + /// + /// A timeout of `0` can be used to "poll" this acceptor to see if it has + /// any pending connections. All pending connections will be accepted, + /// regardless of whether the timeout has expired or not (the accept will + /// not block in this case). + /// + /// # Example + /// + /// ```no_run + /// # #![allow(experimental)] + /// use std::io::TcpListener; + /// use std::io::{Listener, Acceptor, TimedOut}; + /// + /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); + /// + /// // After 100ms have passed, all accepts will fail + /// a.set_timeout(Some(100)); + /// + /// match a.accept() { + /// Ok(..) => println!("accepted a socket"), + /// Err(ref e) if e.kind == TimedOut => { println!("timed out!"); } + /// Err(e) => println!("err: {}", e), + /// } + /// + /// // Reset the timeout and try again + /// a.set_timeout(Some(100)); + /// let socket = a.accept(); + /// + /// // Clear the timeout and block indefinitely waiting for a connection + /// a.set_timeout(None); + /// let socket = a.accept(); + /// ``` + #[experimental = "the type of the argument and name of this function are \ + subject to change"] + pub fn set_timeout(&mut self, ms: Option) { unimplemented!() } + + /// Closes the accepting capabilities of this acceptor. + /// + /// This function is similar to `TcpStream`'s `close_{read,write}` methods + /// in that it will affect *all* cloned handles of this acceptor's original + /// handle. + /// + /// Once this function succeeds, all future calls to `accept` will return + /// immediately with an error, preventing all future calls to accept. The + /// underlying socket will not be relinquished back to the OS until all + /// acceptors have been deallocated. + /// + /// This is useful for waking up a thread in an accept loop to indicate that + /// it should exit. + /// + /// # Example + /// + /// ``` + /// # #![allow(experimental)] + /// use std::io::{TcpListener, Listener, Acceptor, EndOfFile}; + /// + /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); + /// let a2 = a.clone(); + /// + /// spawn(proc() { + /// let mut a2 = a2; + /// for socket in a2.incoming() { + /// match socket { + /// Ok(s) => { /* handle s */ } + /// Err(ref e) if e.kind == EndOfFile => break, // closed + /// Err(e) => panic!("unexpected error: {}", e), + /// } + /// } + /// }); + /// + /// # fn wait_for_sigint() {} + /// // Now that our accept loop is running, wait for the program to be + /// // requested to exit. + /// wait_for_sigint(); + /// + /// // Signal our accept loop to exit + /// assert!(a.close_accept().is_ok()); + /// ``` + #[experimental] + pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Acceptor for TcpAcceptor { + fn accept(&mut self) -> IoResult { unimplemented!() } +} + +impl Clone for TcpAcceptor { + /// Creates a new handle to this TCP acceptor, allowing for simultaneous + /// accepts. + /// + /// The underlying TCP acceptor will not be closed until all handles to the + /// acceptor have been deallocated. Incoming connections will be received on + /// at most once acceptor, the same connection will not be accepted twice. + /// + /// The `close_accept` method will shut down *all* acceptors cloned from the + /// same original acceptor, whereas the `set_timeout` method only affects + /// the selector that it is called on. + /// + /// This function is useful for creating a handle to invoke `close_accept` + /// on to wake up any other task blocked in `accept`. + fn clone(&self) -> TcpAcceptor { unimplemented!() } +} diff --git a/src/libst2/io/net/udp.rs b/src/libst2/io/net/udp.rs new file mode 100644 index 0000000000000..9a3c7544b60e0 --- /dev/null +++ b/src/libst2/io/net/udp.rs @@ -0,0 +1,182 @@ +// Copyright 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. + +//! UDP (User Datagram Protocol) network connections. +//! +//! This module contains the ability to open a UDP stream to a socket address. +//! The destination and binding addresses can either be an IPv4 or IPv6 +//! address. There is no corresponding notion of a server because UDP is a +//! datagram protocol. + +use clone::Clone; +use io::net::ip::{SocketAddr, IpAddr, ToSocketAddr}; +use io::{Reader, Writer, IoResult}; +use option::Option; +use result::{Ok, Err}; +use sys::udp::UdpSocket as UdpSocketImp; + +/// A User Datagram Protocol socket. +/// +/// This is an implementation of a bound UDP socket. This supports both IPv4 and +/// IPv6 addresses, and there is no corresponding notion of a server because UDP +/// is a datagram protocol. +/// +/// # Example +/// +/// ```rust,no_run +/// # #![allow(unused_must_use)] +/// #![feature(slicing_syntax)] +/// +/// use std::io::net::udp::UdpSocket; +/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; +/// fn main() { +/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 34254 }; +/// let mut socket = match UdpSocket::bind(addr) { +/// Ok(s) => s, +/// Err(e) => panic!("couldn't bind socket: {}", e), +/// }; +/// +/// let mut buf = [0, ..10]; +/// match socket.recv_from(&mut buf) { +/// Ok((amt, src)) => { +/// // Send a reply to the socket we received data from +/// let buf = buf[mut ..amt]; +/// buf.reverse(); +/// socket.send_to(buf, src); +/// } +/// Err(e) => println!("couldn't receive a datagram: {}", e) +/// } +/// drop(socket); // close the socket +/// } +/// ``` +pub struct UdpSocket { + inner: UdpSocketImp, +} + +impl UdpSocket { + /// Creates a UDP socket from the given address. + /// + /// Address type can be any implementor of `ToSocketAddr` trait. See its + /// documentation for concrete examples. + pub fn bind(addr: A) -> IoResult { unimplemented!() } + + /// Receives data from the socket. On success, returns the number of bytes + /// read and the address from whence the data came. + pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { unimplemented!() } + + /// Sends data on the socket to the given address. Returns nothing on + /// success. + /// + /// Address type can be any implementor of `ToSocketAddr` trait. See its + /// documentation for concrete examples. + pub fn send_to(&mut self, buf: &[u8], addr: A) -> IoResult<()> { unimplemented!() } + + /// Creates a `UdpStream`, which allows use of the `Reader` and `Writer` + /// traits to receive and send data from the same address. This transfers + /// ownership of the socket to the stream. + /// + /// Note that this call does not perform any actual network communication, + /// because UDP is a datagram protocol. + #[deprecated = "`UdpStream` has been deprecated"] + #[allow(deprecated)] + pub fn connect(self, other: SocketAddr) -> UdpStream { unimplemented!() } + + /// Returns the socket address that this socket was created from. + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } + + /// Joins a multicast IP address (becomes a member of it) + #[experimental] + pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } + + /// Leaves a multicast IP address (drops membership from it) + #[experimental] + pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } + + /// Set the multicast loop flag to the specified value + /// + /// This lets multicast packets loop back to local sockets (if enabled) + #[experimental] + pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { unimplemented!() } + + /// Sets the multicast TTL + #[experimental] + pub fn set_multicast_ttl(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } + + /// Sets this socket's TTL + #[experimental] + pub fn set_ttl(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } + + /// Sets the broadcast flag on or off + #[experimental] + pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> { unimplemented!() } + + /// Sets the read/write timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the read timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Sets the write timeout for this socket. + /// + /// For more information, see `TcpStream::set_timeout` + #[experimental = "the timeout argument may change in type and value"] + pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } +} + +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 { unimplemented!() } +} + +/// A type that allows convenient usage of a UDP stream connected to one +/// address via the `Reader` and `Writer` traits. +/// +/// # Note +/// +/// This structure has been deprecated because `Reader` is a stream-oriented API but UDP +/// is a packet-oriented protocol. Every `Reader` method will read a whole packet and +/// throw all superfluous bytes away so that they are no longer available for further +/// method calls. +#[deprecated] +pub struct UdpStream { + socket: UdpSocket, + connected_to: SocketAddr +} + +impl UdpStream { + /// Allows access to the underlying UDP socket owned by this stream. This + /// is useful to, for example, use the socket to send data to hosts other + /// than the one that this stream is connected to. + pub fn as_socket(&mut self, f: |&mut UdpSocket| -> T) -> T { unimplemented!() } + + /// Consumes this UDP stream and returns out the underlying socket. + pub fn disconnect(self) -> UdpSocket { unimplemented!() } +} + +impl Reader for UdpStream { + /// Returns the next non-empty message from the specified address. + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for UdpStream { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/io/pipe.rs b/src/libst2/io/pipe.rs new file mode 100644 index 0000000000000..2103382e52bf4 --- /dev/null +++ b/src/libst2/io/pipe.rs @@ -0,0 +1,93 @@ +// Copyright 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. + +//! Synchronous, in-memory pipes. +//! +//! Currently these aren't particularly useful, there only exists bindings +//! enough so that pipes can be created to child processes. + +#![allow(missing_docs)] + +use prelude::*; + +use io::IoResult; +use libc; +use sync::Arc; + +use sys_common; +use sys; +use sys::fs::FileDesc as FileDesc; + +/// A synchronous, in-memory pipe. +pub struct PipeStream { + inner: Arc +} + +pub struct PipePair { + pub reader: PipeStream, + pub writer: PipeStream, +} + +impl PipeStream { + /// Consumes a file descriptor to return a pipe stream that will have + /// synchronous, but non-blocking reads/writes. This is useful if the file + /// descriptor is acquired via means other than the standard methods. + /// + /// This operation consumes ownership of the file descriptor and it will be + /// closed once the object is deallocated. + /// + /// # Example + /// + /// ```{rust,no_run} + /// # #![allow(unused_must_use)] + /// extern crate libc; + /// + /// use std::io::pipe::PipeStream; + /// + /// fn main() { + /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); + /// pipe.write(b"Hello, stderr!"); + /// } + /// ``` + pub fn open(fd: libc::c_int) -> IoResult { unimplemented!() } + + // FIXME: expose this some other way + /// Wrap a FileDesc directly, taking ownership. + #[doc(hidden)] + pub fn from_filedesc(fd: FileDesc) -> PipeStream { unimplemented!() } + + /// Creates a pair of in-memory OS pipes for a unidirectional communication + /// stream. + /// + /// The structure returned contains a reader and writer I/O object. Data + /// written to the writer can be read from the reader. + /// + /// # Errors + /// + /// This function can fail to succeed if the underlying OS has run out of + /// available resources to allocate a new pipe. + pub fn pair() -> IoResult { unimplemented!() } +} + +impl sys_common::AsFileDesc for PipeStream { + fn as_fd(&self) -> &sys::fs::FileDesc { unimplemented!() } +} + +impl Clone for PipeStream { + fn clone(&self) -> PipeStream { unimplemented!() } +} + +impl Reader for PipeStream { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Writer for PipeStream { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/io/process.rs b/src/libst2/io/process.rs new file mode 100644 index 0000000000000..8ba11b60a05a5 --- /dev/null +++ b/src/libst2/io/process.rs @@ -0,0 +1,470 @@ +// Copyright 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. + +//! Bindings for executing child processes + +#![allow(experimental)] +#![allow(non_upper_case_globals)] + +pub use self::StdioContainer::*; +pub use self::ProcessExit::*; + +use prelude::*; + +use fmt; +use os; +use io::{IoResult, IoError}; +use io; +use libc; +use c_str::CString; +use collections::HashMap; +use hash::Hash; +#[cfg(windows)] +use std::hash::sip::SipState; +use io::pipe::{PipeStream, PipePair}; +use path::BytesContainer; + +use sys; +use sys::fs::FileDesc; +use sys::process::Process as ProcessImp; + +/// Signal a process to exit, without forcibly killing it. Corresponds to +/// SIGTERM on unix platforms. +#[cfg(windows)] pub const PleaseExitSignal: int = 15; +/// Signal a process to exit immediately, forcibly killing it. Corresponds to +/// SIGKILL on unix platforms. +#[cfg(windows)] pub const MustDieSignal: int = 9; +/// Signal a process to exit, without forcibly killing it. Corresponds to +/// SIGTERM on unix platforms. +#[cfg(not(windows))] pub const PleaseExitSignal: int = libc::SIGTERM as int; +/// Signal a process to exit immediately, forcibly killing it. Corresponds to +/// SIGKILL on unix platforms. +#[cfg(not(windows))] pub const MustDieSignal: int = libc::SIGKILL as int; + +/// Representation of a running or exited child process. +/// +/// This structure is used to represent and manage child processes. A child +/// process is created via the `Command` struct, which configures the spawning +/// process and can itself be constructed using a builder-style interface. +/// +/// # Example +/// +/// ```should_fail +/// use std::io::Command; +/// +/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() { +/// Ok(child) => child, +/// Err(e) => panic!("failed to execute child: {}", e), +/// }; +/// +/// let contents = child.stdout.as_mut().unwrap().read_to_end(); +/// assert!(child.wait().unwrap().success()); +/// ``` +pub struct Process { + handle: ProcessImp, + forget: bool, + + /// None until wait() is called. + exit_code: Option, + + /// Manually delivered signal + exit_signal: Option, + + /// Deadline after which wait() will return + deadline: u64, + + /// Handle to the child's stdin, if the `stdin` field of this process's + /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. + pub stdin: Option, + + /// Handle to the child's stdout, if the `stdout` field of this process's + /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. + pub stdout: Option, + + /// Handle to the child's stderr, if the `stderr` field of this process's + /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. + pub stderr: Option, +} + +/// A representation of environment variable name +/// It compares case-insensitive on Windows and case-sensitive everywhere else. +#[cfg(not(windows))] +#[deriving(PartialEq, Eq, Hash, Clone, Show)] +struct EnvKey(CString); + +#[doc(hidden)] +#[cfg(windows)] +#[deriving(Eq, Clone, Show)] +struct EnvKey(CString); + +#[cfg(windows)] +impl Hash for EnvKey { + fn hash(&self, state: &mut SipState) { unimplemented!() } +} + +#[cfg(windows)] +impl PartialEq for EnvKey { + fn eq(&self, other: &EnvKey) -> bool { unimplemented!() } +} + +impl BytesContainer for EnvKey { + fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } +} + +/// A HashMap representation of environment variables. +pub type EnvMap = HashMap; + +/// The `Command` type acts as a process builder, providing fine-grained control +/// over how a new process should be spawned. A default configuration can be +/// generated using `Command::new(program)`, where `program` gives a path to the +/// program to be executed. Additional builder methods allow the configuration +/// to be changed (for example, by adding arguments) prior to spawning: +/// +/// ``` +/// use std::io::Command; +/// +/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() { +/// Ok(p) => p, +/// Err(e) => panic!("failed to execute process: {}", e), +/// }; +/// +/// let output = process.stdout.as_mut().unwrap().read_to_end(); +/// ``` +#[deriving(Clone)] +pub struct Command { + // The internal data for the builder. Documented by the builder + // methods below, and serialized into rt::rtio::ProcessConfig. + program: CString, + args: Vec, + env: Option, + cwd: Option, + stdin: StdioContainer, + stdout: StdioContainer, + stderr: StdioContainer, + uid: Option, + gid: Option, + detach: bool, +} + +// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so +// we cannot usefully take ToCStr arguments by reference (without forcing an +// additional & around &str). So we are instead temporarily adding an instance +// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by ToCStr should be passed by +// reference. (Here: {new, arg, args, env}.) + +impl Command { + /// Constructs a new `Command` for launching the program at + /// path `program`, with the following default configuration: + /// + /// * No arguments to the program + /// * Inherit the current process's environment + /// * Inherit the current process's working directory + /// * A readable pipe for stdin (file descriptor 0) + /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2) + /// + /// Builder methods are provided to change these defaults and + /// otherwise configure the process. + pub fn new(program: T) -> Command { unimplemented!() } + + /// Add an argument to pass to the program. + pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { unimplemented!() } + + /// Add multiple arguments to pass to the program. + pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { unimplemented!() } + // Get a mutable borrow of the environment variable map for this `Command`. + fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { unimplemented!() } + + /// Inserts or updates an environment variable mapping. + /// + /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, + /// and case-sensitive on all other platforms. + pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U) + -> &'a mut Command { unimplemented!() } + + /// Removes an environment variable mapping. + pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { unimplemented!() } + + /// Sets the entire environment map for the child process. + /// + /// If the given slice contains multiple instances of an environment + /// variable, the *rightmost* instance will determine the value. + pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)]) + -> &'a mut Command { unimplemented!() } + + /// Set the working directory for the child process. + pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { unimplemented!() } + + /// Configuration for the child process's stdin handle (file descriptor 0). + /// Defaults to `CreatePipe(true, false)` so the input can be written to. + pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } + + /// Configuration for the child process's stdout handle (file descriptor 1). + /// Defaults to `CreatePipe(false, true)` so the output can be collected. + pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } + + /// Configuration for the child process's stderr handle (file descriptor 2). + /// Defaults to `CreatePipe(false, true)` so the output can be collected. + pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } + + /// Sets the child process's user id. This translates to a `setuid` call in + /// the child process. Setting this value on windows will cause the spawn to + /// fail. Failure in the `setuid` call on unix will also cause the spawn to + /// fail. + pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command { unimplemented!() } + + /// Similar to `uid`, but sets the group id of the child process. This has + /// the same semantics as the `uid` field. + pub fn gid<'a>(&'a mut self, id: uint) -> &'a mut Command { unimplemented!() } + + /// Sets the child process to be spawned in a detached state. On unix, this + /// means that the child is the leader of a new process group. + pub fn detached<'a>(&'a mut self) -> &'a mut Command { unimplemented!() } + + /// Executes the command as a child process, which is returned. + pub fn spawn(&self) -> IoResult { unimplemented!() } + + /// Executes the command as a child process, waiting for it to finish and + /// collecting all of its output. + /// + /// # Example + /// + /// ``` + /// use std::io::Command; + /// + /// let output = match Command::new("cat").arg("foot.txt").output() { + /// Ok(output) => output, + /// Err(e) => panic!("failed to execute process: {}", e), + /// }; + /// + /// println!("status: {}", output.status); + /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice())); + /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice())); + /// ``` + pub fn output(&self) -> IoResult { unimplemented!() } + + /// Executes a command as a child process, waiting for it to finish and + /// collecting its exit status. + /// + /// # Example + /// + /// ``` + /// use std::io::Command; + /// + /// let status = match Command::new("ls").status() { + /// Ok(status) => status, + /// Err(e) => panic!("failed to execute process: {}", e), + /// }; + /// + /// println!("process exited with: {}", status); + /// ``` + pub fn status(&self) -> IoResult { unimplemented!() } +} + +impl fmt::Show for Command { + /// Format the program and arguments of a Command for display. Any + /// non-utf8 data is lossily converted using the utf8 replacement + /// character. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +fn setup_io(io: StdioContainer) -> IoResult<(Option, Option)> { unimplemented!() } + +// Allow the sys module to get access to the Command state +impl sys::process::ProcessConfig for Command { + fn program(&self) -> &CString { unimplemented!() } + fn args(&self) -> &[CString] { unimplemented!() } + fn env(&self) -> Option<&EnvMap> { unimplemented!() } + fn cwd(&self) -> Option<&CString> { unimplemented!() } + fn uid(&self) -> Option { unimplemented!() } + fn gid(&self) -> Option { unimplemented!() } + fn detach(&self) -> bool { unimplemented!() } + +} + +/// The output of a finished process. +#[deriving(PartialEq, Eq, Clone)] +pub struct ProcessOutput { + /// The status (exit code) of the process. + pub status: ProcessExit, + /// The data that the process wrote to stdout. + pub output: Vec, + /// The data that the process wrote to stderr. + pub error: Vec, +} + +/// Describes what to do with a standard io stream for a child process. +#[deriving(Clone)] +pub enum StdioContainer { + /// This stream will be ignored. This is the equivalent of attaching the + /// stream to `/dev/null` + Ignored, + + /// The specified file descriptor is inherited for the stream which it is + /// specified for. Ownership of the file descriptor is *not* taken, so the + /// caller must clean it up. + InheritFd(libc::c_int), + + /// Creates a pipe for the specified file descriptor which will be created + /// when the process is spawned. + /// + /// The first boolean argument is whether the pipe is readable, and the + /// second is whether it is writable. These properties are from the view of + /// the *child* process, not the parent process. + CreatePipe(bool /* readable */, bool /* writable */), +} + +/// Describes the result of a process after it has terminated. +/// Note that Windows have no signals, so the result is usually ExitStatus. +#[deriving(PartialEq, Eq, Clone)] +pub enum ProcessExit { + /// Normal termination with an exit status. + ExitStatus(int), + + /// Termination by signal, with the signal number. + ExitSignal(int), +} + +impl fmt::Show for ProcessExit { + /// Format a ProcessExit enum, to nicely present the information. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl ProcessExit { + /// Was termination successful? Signal termination not considered a success, + /// and success is defined as a zero exit status. + pub fn success(&self) -> bool { unimplemented!() } + + /// Checks whether this ProcessExit matches the given exit status. + /// Termination by signal will never match an exit code. + pub fn matches_exit_status(&self, wanted: int) -> bool { unimplemented!() } +} + +impl Process { + /// Sends `signal` to another process in the system identified by `id`. + /// + /// Note that windows doesn't quite have the same model as unix, so some + /// unix signals are mapped to windows signals. Notably, unix termination + /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`. + /// + /// Additionally, a signal number of 0 can check for existence of the target + /// process. Note, though, that on some platforms signals will continue to + /// be successfully delivered if the child has exited, but not yet been + /// reaped. + pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> { unimplemented!() } + + /// Returns the process id of this child process + pub fn id(&self) -> libc::pid_t { unimplemented!() } + + /// Sends the specified signal to the child process, returning whether the + /// signal could be delivered or not. + /// + /// Note that signal 0 is interpreted as a poll to check whether the child + /// process is still alive or not. If an error is returned, then the child + /// process has exited. + /// + /// On some unix platforms signals will continue to be received after a + /// child has exited but not yet been reaped. In order to report the status + /// of signal delivery correctly, unix implementations may invoke + /// `waitpid()` with `WNOHANG` in order to reap the child as necessary. + /// + /// # Errors + /// + /// If the signal delivery fails, the corresponding error is returned. + pub fn signal(&mut self, signal: int) -> IoResult<()> { unimplemented!() } + + /// Sends a signal to this child requesting that it exits. This is + /// equivalent to sending a SIGTERM on unix platforms. + pub fn signal_exit(&mut self) -> IoResult<()> { unimplemented!() } + + /// Sends a signal to this child forcing it to exit. This is equivalent to + /// sending a SIGKILL on unix platforms. + pub fn signal_kill(&mut self) -> IoResult<()> { unimplemented!() } + + /// Wait for the child to exit completely, returning the status that it + /// exited with. This function will continue to have the same return value + /// after it has been called at least once. + /// + /// The stdin handle to the child process will be closed before waiting. + /// + /// # Errors + /// + /// This function can fail if a timeout was previously specified via + /// `set_timeout` and the timeout expires before the child exits. + pub fn wait(&mut self) -> IoResult { unimplemented!() } + + /// Sets a timeout, in milliseconds, for future calls to wait(). + /// + /// The argument specified is a relative distance into the future, in + /// milliseconds, after which any call to wait() will return immediately + /// with a timeout error, and all future calls to wait() will not block. + /// + /// A value of `None` will clear any previous timeout, and a value of `Some` + /// will override any previously set timeout. + /// + /// # Example + /// + /// ```no_run + /// # #![allow(experimental)] + /// use std::io::{Command, IoResult}; + /// use std::io::process::ProcessExit; + /// + /// fn run_gracefully(prog: &str) -> IoResult { + /// let mut p = try!(Command::new("long-running-process").spawn()); + /// + /// // give the process 10 seconds to finish completely + /// p.set_timeout(Some(10_000)); + /// match p.wait() { + /// Ok(status) => return Ok(status), + /// Err(..) => {} + /// } + /// + /// // Attempt to exit gracefully, but don't wait for it too long + /// try!(p.signal_exit()); + /// p.set_timeout(Some(1_000)); + /// match p.wait() { + /// Ok(status) => return Ok(status), + /// Err(..) => {} + /// } + /// + /// // Well, we did our best, forcefully kill the process + /// try!(p.signal_kill()); + /// p.set_timeout(None); + /// p.wait() + /// } + /// ``` + #[experimental = "the type of the timeout is likely to change"] + pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } + + /// Simultaneously wait for the child to exit and collect all remaining + /// output on the stdout/stderr handles, returning a `ProcessOutput` + /// instance. + /// + /// The stdin handle to the child is closed before waiting. + /// + /// # Errors + /// + /// This function can fail for any of the same reasons that `wait()` can + /// fail. + pub fn wait_with_output(mut self) -> IoResult { unimplemented!() } + + /// Forgets this process, allowing it to outlive the parent + /// + /// This function will forcefully prevent calling `wait()` on the child + /// process in the destructor, allowing the child to outlive the + /// parent. Note that this operation can easily lead to leaking the + /// resources of the child process, so care must be taken when + /// invoking this method. + pub fn forget(mut self) { unimplemented!() } +} + +impl Drop for Process { + fn drop(&mut self) { unimplemented!() } +} diff --git a/src/libst2/io/result.rs b/src/libst2/io/result.rs new file mode 100644 index 0000000000000..f89cc7c258923 --- /dev/null +++ b/src/libst2/io/result.rs @@ -0,0 +1,42 @@ +// Copyright 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. + +//! Implementations of I/O traits for the IoResult type +//! +//! I/O constructors return option types to allow errors to be handled. +//! These implementations allow e.g. `IoResult` to be used +//! as a `Reader` without unwrapping the result first. + +use clone::Clone; +use result::{Ok, Err}; +use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; + +impl Writer for IoResult { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + fn flush(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Reader for IoResult { + fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } +} + +impl Seek for IoResult { + fn tell(&self) -> IoResult { unimplemented!() } + fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } +} + +impl, L: Listener> Listener for IoResult { + fn listen(self) -> IoResult { unimplemented!() } +} + +impl> Acceptor for IoResult { + fn accept(&mut self) -> IoResult { unimplemented!() } +} diff --git a/src/libst2/io/stdio.rs b/src/libst2/io/stdio.rs new file mode 100644 index 0000000000000..8b646fe584e8d --- /dev/null +++ b/src/libst2/io/stdio.rs @@ -0,0 +1,396 @@ +// Copyright 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. + +/*! Non-blocking access to stdin, stdout, and stderr. + +This module provides bindings to the local event loop's TTY interface, using it +to offer synchronous but non-blocking versions of stdio. These handles can be +inspected for information about terminal dimensions or for related information +about the stream or terminal to which it is attached. + +# Example + +```rust +# #![allow(unused_must_use)] +use std::io; + +let mut out = io::stdout(); +out.write(b"Hello, world!"); +``` + +*/ + +use self::StdSource::*; + +use boxed::Box; +use cell::RefCell; +use failure::LOCAL_STDERR; +use fmt; +use io::{Reader, Writer, IoResult, IoError, OtherIoError, + standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; +use iter::Iterator; +use kinds::Send; +use libc; +use mem; +use option::{Option, Some, None}; +use result::{Ok, Err}; +use rustrt; +use rustrt::local::Local; +use rustrt::task::Task; +use slice::SlicePrelude; +use str::StrPrelude; +use sys::{fs, tty}; +use uint; + +// And so begins the tale of acquiring a uv handle to a stdio stream on all +// platforms in all situations. Our story begins by splitting the world into two +// categories, windows and unix. Then one day the creators of unix said let +// there be redirection! And henceforth there was redirection away from the +// console for standard I/O streams. +// +// After this day, the world split into four factions: +// +// 1. Unix with stdout on a terminal. +// 2. Unix with stdout redirected. +// 3. Windows with stdout on a terminal. +// 4. Windows with stdout redirected. +// +// Many years passed, and then one day the nation of libuv decided to unify this +// world. After months of toiling, uv created three ideas: TTY, Pipe, File. +// These three ideas propagated throughout the lands and the four great factions +// decided to settle among them. +// +// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon +// doing so, they even enhanced themselves further then their Pipe/File +// brethren, becoming the dominant powers. +// +// The group of 4, however, decided to work independently. They abandoned the +// common TTY belief throughout, and even abandoned the fledgling Pipe belief. +// The members of the 4th faction decided to only align themselves with File. +// +// tl;dr; TTY works on everything but when windows stdout is redirected, in that +// case pipe also doesn't work, but magically file does! +enum StdSource { + TTY(tty::TTY), + File(fs::FileDesc), +} + +fn src(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T { + match tty::TTY::new(fd) { + Ok(tty) => f(TTY(tty)), + Err(_) => f(File(fs::FileDesc::new(fd, false))), + } +} + +thread_local!(static LOCAL_STDOUT: RefCell>> = { + RefCell::new(None) +}) + +/// Creates a new non-blocking handle to the stdin of the current process. +/// +/// The returned handled is buffered by default with a `BufferedReader`. If +/// buffered access is not desired, the `stdin_raw` function is provided to +/// provided unbuffered access to stdin. +/// +/// Care should be taken when creating multiple handles to the stdin of a +/// process. Because this is a buffered reader by default, it's possible for +/// pending input to be unconsumed in one reader and unavailable to other +/// readers. It is recommended that only one handle at a time is created for the +/// stdin of a process. +/// +/// See `stdout()` for more notes about this function. +pub fn stdin() -> BufferedReader { + // The default buffer capacity is 64k, but apparently windows doesn't like + // 64k reads on stdin. See #13304 for details, but the idea is that on + // windows we use a slightly smaller buffer that's been seen to be + // acceptable. + if cfg!(windows) { + BufferedReader::with_capacity(8 * 1024, stdin_raw()) + } else { + BufferedReader::new(stdin_raw()) + } +} + +/// Creates a new non-blocking handle to the stdin of the current process. +/// +/// Unlike `stdin()`, the returned reader is *not* a buffered reader. +/// +/// See `stdout()` for more notes about this function. +pub fn stdin_raw() -> StdReader { + src(libc::STDIN_FILENO, true, |src| StdReader { inner: src }) +} + +/// Creates a line-buffered handle to the stdout of the current process. +/// +/// Note that this is a fairly expensive operation in that at least one memory +/// allocation is performed. Additionally, this must be called from a runtime +/// task context because the stream returned will be a non-blocking object using +/// the local scheduler to perform the I/O. +/// +/// Care should be taken when creating multiple handles to an output stream for +/// a single process. While usage is still safe, the output may be surprising if +/// no synchronization is performed to ensure a sane output. +pub fn stdout() -> LineBufferedWriter { + LineBufferedWriter::new(stdout_raw()) +} + +/// Creates an unbuffered handle to the stdout of the current process +/// +/// See notes in `stdout()` for more information. +pub fn stdout_raw() -> StdWriter { + src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src }) +} + +/// Creates a line-buffered handle to the stderr of the current process. +/// +/// See `stdout()` for notes about this function. +pub fn stderr() -> LineBufferedWriter { + LineBufferedWriter::new(stderr_raw()) +} + +/// Creates an unbuffered handle to the stderr of the current process +/// +/// See notes in `stdout()` for more information. +pub fn stderr_raw() -> StdWriter { + src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src }) +} + +/// Resets the task-local stdout handle to the specified writer +/// +/// This will replace the current task's stdout handle, returning the old +/// handle. All future calls to `print` and friends will emit their output to +/// this specified handle. +/// +/// Note that this does not need to be called for all new tasks; the default +/// output handle is to the process's stdout stream. +pub fn set_stdout(stdout: Box) -> Option> { + let mut new = Some(stdout); + LOCAL_STDOUT.with(|slot| { + mem::replace(&mut *slot.borrow_mut(), new.take()) + }).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) +} + +/// Resets the task-local stderr handle to the specified writer +/// +/// This will replace the current task's stderr handle, returning the old +/// handle. Currently, the stderr handle is used for printing panic messages +/// during task panic. +/// +/// Note that this does not need to be called for all new tasks; the default +/// output handle is to the process's stderr stream. +pub fn set_stderr(stderr: Box) -> Option> { + let mut new = Some(stderr); + LOCAL_STDERR.with(|slot| { + mem::replace(&mut *slot.borrow_mut(), new.take()) + }).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) +} + +// Helper to access the local task's stdout handle +// +// Note that this is not a safe function to expose because you can create an +// aliased pointer very easily: +// +// with_task_stdout(|io1| { +// with_task_stdout(|io2| { +// // io1 aliases io2 +// }) +// }) +fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) { + let result = if Local::exists(None::) { + let mut my_stdout = LOCAL_STDOUT.with(|slot| { + slot.borrow_mut().take() + }).unwrap_or_else(|| { + box stdout() as Box + }); + let result = f(&mut *my_stdout); + let mut var = Some(my_stdout); + LOCAL_STDOUT.with(|slot| { + *slot.borrow_mut() = var.take(); + }); + result + } else { + let mut io = rustrt::Stdout; + f(&mut io as &mut Writer) + }; + match result { + Ok(()) => {} + Err(e) => panic!("failed printing to stdout: {}", e), + } +} + +/// Flushes the local task's stdout handle. +/// +/// By default, this stream is a line-buffering stream, so flushing may be +/// necessary to ensure that all output is printed to the screen (if there are +/// no newlines printed). +/// +/// Note that logging macros do not use this stream. Using the logging macros +/// will emit output to stderr, and while they are line buffered the log +/// messages are always terminated in a newline (no need to flush). +pub fn flush() { + with_task_stdout(|io| io.flush()) +} + +/// Prints a string to the stdout of the current process. No newline is emitted +/// after the string is printed. +pub fn print(s: &str) { + with_task_stdout(|io| io.write(s.as_bytes())) +} + +/// Prints a string to the stdout of the current process. A literal +/// `\n` character is printed to the console after the string. +pub fn println(s: &str) { + with_task_stdout(|io| { + io.write(s.as_bytes()).and_then(|()| io.write(&[b'\n'])) + }) +} + +/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible +/// with the `format_args!` macro. +pub fn print_args(fmt: &fmt::Arguments) { + with_task_stdout(|io| write!(io, "{}", fmt)) +} + +/// Similar to `println`, but takes a `fmt::Arguments` structure to be +/// compatible with the `format_args!` macro. +pub fn println_args(fmt: &fmt::Arguments) { + with_task_stdout(|io| writeln!(io, "{}", fmt)) +} + +/// Representation of a reader of a standard input stream +pub struct StdReader { + inner: StdSource +} + +impl StdReader { + /// Returns whether this stream is attached to a TTY instance or not. + pub fn isatty(&self) -> bool { + match self.inner { + TTY(..) => true, + File(..) => false, + } + } +} + +impl Reader for StdReader { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + let ret = match self.inner { + TTY(ref mut tty) => { + // Flush the task-local stdout so that weird issues like a + // print!'d prompt not being shown until after the user hits + // enter. + flush(); + tty.read(buf).map(|i| i as uint) + }, + File(ref mut file) => file.read(buf).map(|i| i as uint), + }; + match ret { + // When reading a piped stdin, libuv will return 0-length reads when + // stdin reaches EOF. For pretty much all other streams it will + // return an actual EOF error, but apparently for stdin it's a + // little different. Hence, here we convert a 0 length read to an + // end-of-file indicator so the caller knows to stop reading. + Ok(0) => { Err(standard_error(EndOfFile)) } + ret @ Ok(..) | ret @ Err(..) => ret, + } + } +} + +/// Representation of a writer to a standard output stream +pub struct StdWriter { + inner: StdSource +} + +impl StdWriter { + /// Gets the size of this output window, if possible. This is typically used + /// when the writer is attached to something like a terminal, this is used + /// to fetch the dimensions of the terminal. + /// + /// If successful, returns `Ok((width, height))`. + /// + /// # Error + /// + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. + pub fn winsize(&mut self) -> IoResult<(int, int)> { + match self.inner { + TTY(ref mut tty) => { + tty.get_winsize() + } + File(..) => { + Err(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }) + } + } + } + + /// Controls whether this output stream is a "raw stream" or simply a normal + /// stream. + /// + /// # Error + /// + /// This function will return an error if the output stream is not actually + /// connected to a TTY instance, or if querying the TTY instance fails. + pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { + match self.inner { + TTY(ref mut tty) => { + tty.set_raw(raw) + } + File(..) => { + Err(IoError { + kind: OtherIoError, + desc: "stream is not a tty", + detail: None, + }) + } + } + } + + /// Returns whether this stream is attached to a TTY instance or not. + pub fn isatty(&self) -> bool { + match self.inner { + TTY(..) => true, + File(..) => false, + } + } +} + +impl Writer for StdWriter { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + // As with stdin on windows, stdout often can't handle writes of large + // sizes. For an example, see #14940. For this reason, chunk the output + // buffer on windows, but on unix we can just write the whole buffer all + // at once. + // + // For some other references, it appears that this problem has been + // encountered by others [1] [2]. We choose the number 8KB just because + // libuv does the same. + // + // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 + // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html + let max_size = if cfg!(windows) {8192} else {uint::MAX}; + for chunk in buf.chunks(max_size) { + try!(match self.inner { + TTY(ref mut tty) => tty.write(chunk), + File(ref mut file) => file.write(chunk), + }) + } + Ok(()) + } +} diff --git a/src/libst2/io/tempfile.rs b/src/libst2/io/tempfile.rs new file mode 100644 index 0000000000000..7fed90aa5cc92 --- /dev/null +++ b/src/libst2/io/tempfile.rs @@ -0,0 +1,69 @@ +// Copyright 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. + +//! Temporary files and directories + +use io::{fs, IoResult}; +use io; +use libc; +use ops::Drop; +use option::{Option, None, Some}; +use os; +use path::{Path, GenericPath}; +use result::{Ok, Err}; +use sync::atomic; + +/// A wrapper for a path to temporary directory implementing automatic +/// scope-based deletion. +pub struct TempDir { + path: Option, + disarmed: bool +} + +impl TempDir { + /// Attempts to make a temporary directory inside of `tmpdir` whose name + /// will have the suffix `suffix`. The directory will be automatically + /// deleted once the returned wrapper is destroyed. + /// + /// If no directory can be created, `Err` is returned. + pub fn new_in(tmpdir: &Path, suffix: &str) -> IoResult { unimplemented!() } + + /// Attempts to make a temporary directory inside of `os::tmpdir()` whose + /// name will have the suffix `suffix`. The directory will be automatically + /// deleted once the returned wrapper is destroyed. + /// + /// If no directory can be created, `Err` is returned. + pub fn new(suffix: &str) -> IoResult { unimplemented!() } + + /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. + /// This discards the wrapper so that the automatic deletion of the + /// temporary directory is prevented. + pub fn unwrap(self) -> Path { unimplemented!() } + + /// Access the wrapped `std::path::Path` to the temporary directory. + pub fn path<'a>(&'a self) -> &'a Path { unimplemented!() } + + /// Close and remove the temporary directory + /// + /// Although `TempDir` removes the directory on drop, in the destructor + /// any errors are ignored. To detect errors cleaning up the temporary + /// directory, call `close` instead. + pub fn close(mut self) -> IoResult<()> { unimplemented!() } + + fn cleanup_dir(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Drop for TempDir { + fn drop(&mut self) { unimplemented!() } +} + +// the tests for this module need to change the path using change_dir, +// and this doesn't play nicely with other tests so these unit tests are located +// in src/test/run-pass/tempfile.rs diff --git a/src/libst2/io/test.rs b/src/libst2/io/test.rs new file mode 100644 index 0000000000000..53ff2e8dc965a --- /dev/null +++ b/src/libst2/io/test.rs @@ -0,0 +1,81 @@ +// Copyright 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. + +/*! Various utility functions useful for writing I/O tests */ + +#![macro_escape] + +use libc; +use os; +use prelude::*; +use std::io::net::ip::*; +use sync::atomic::{AtomicUint, INIT_ATOMIC_UINT, Relaxed}; + +/// Get a port number, starting at 9600, for use in tests +pub fn next_test_port() -> u16 { unimplemented!() } + +/// Get a temporary path which could be the location of a unix socket +pub fn next_test_unix() -> Path { unimplemented!() } + +/// Get a unique IPv4 localhost:port pair starting at 9600 +pub fn next_test_ip4() -> SocketAddr { unimplemented!() } + +/// Get a unique IPv6 localhost:port pair starting at 9600 +pub fn next_test_ip6() -> SocketAddr { unimplemented!() } + +/* +XXX: Welcome to MegaHack City. + +The bots run multiple builds at the same time, and these builds +all want to use ports. This function figures out which workspace +it is running in and assigns a port range based on it. +*/ +fn base_port() -> u16 { unimplemented!() } + +/// Raises the file descriptor limit when running tests if necessary +pub fn raise_fd_limit() { unimplemented!() } + +#[cfg(target_os="macos")] +#[allow(non_camel_case_types)] +mod darwin_fd_limit { + /*! + * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the + * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low + * for our multithreaded scheduler testing, depending on the number of cores available. + * + * This fixes issue #7772. + */ + + use libc; + type rlim_t = libc::uint64_t; + #[repr(C)] + struct rlimit { + rlim_cur: rlim_t, + rlim_max: rlim_t + } + extern { + // name probably doesn't need to be mut, but the C function doesn't specify const + fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint, + oldp: *mut libc::c_void, oldlenp: *mut libc::size_t, + newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int; + fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int; + fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int; + } + static CTL_KERN: libc::c_int = 1; + static KERN_MAXFILESPERPROC: libc::c_int = 29; + static RLIMIT_NOFILE: libc::c_int = 8; + + pub unsafe fn raise_fd_limit() { unimplemented!() } +} + +#[cfg(not(target_os="macos"))] +mod darwin_fd_limit { + pub unsafe fn raise_fd_limit() { unimplemented!() } +} diff --git a/src/libst2/io/timer.rs b/src/libst2/io/timer.rs new file mode 100644 index 0000000000000..f705dae118dc5 --- /dev/null +++ b/src/libst2/io/timer.rs @@ -0,0 +1,192 @@ +// Copyright 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. + +/*! + +Synchronous Timers + +This module exposes the functionality to create timers, block the current task, +and create receivers which will receive notifications after a period of time. + +*/ + +// FIXME: These functions take Durations but only pass ms to the backend impls. + +use comm::{Receiver, Sender, channel}; +use time::Duration; +use io::IoResult; +use sys::timer::Callback; +use sys::timer::Timer as TimerImp; + +/// A synchronous timer object +/// +/// Values of this type can be used to put the current task to sleep for a +/// period of time. Handles to this timer can also be created in the form of +/// receivers which will receive notifications over time. +/// +/// # Example +/// +/// ``` +/// # fn main() {} +/// # fn foo() { +/// use std::io::Timer; +/// use std::time::Duration; +/// +/// let mut timer = Timer::new().unwrap(); +/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile +/// +/// let timeout = timer.oneshot(Duration::milliseconds(10)); +/// // do some work +/// timeout.recv(); // wait for the timeout to expire +/// +/// let periodic = timer.periodic(Duration::milliseconds(10)); +/// loop { +/// periodic.recv(); +/// // this loop is only executed once every 10ms +/// } +/// # } +/// ``` +/// +/// If only sleeping is necessary, then a convenience API is provided through +/// the `io::timer` module. +/// +/// ``` +/// # fn main() {} +/// # fn foo() { +/// use std::io::timer; +/// use std::time::Duration; +/// +/// // Put this task to sleep for 5 seconds +/// timer::sleep(Duration::seconds(5)); +/// # } +/// ``` +pub struct Timer { + inner: TimerImp, +} + +struct TimerCallback { tx: Sender<()> } + +/// Sleep the current task for the specified duration. +/// +/// When provided a zero or negative `duration`, the function will +/// return immediately. +pub fn sleep(duration: Duration) { unimplemented!() } + +impl Timer { + /// Creates a new timer which can be used to put the current task to sleep + /// for a number of milliseconds, or to possibly create channels which will + /// get notified after an amount of time has passed. + pub fn new() -> IoResult { unimplemented!() } + + /// Blocks the current task for the specified duration. + /// + /// Note that this function will cause any other receivers for this timer to + /// be invalidated (the other end will be closed). + /// + /// When provided a zero or negative `duration`, the function will + /// return immediately. + pub fn sleep(&mut self, duration: Duration) { unimplemented!() } + + /// Creates a oneshot receiver which will have a notification sent when + /// the specified duration has elapsed. + /// + /// This does *not* block the current task, but instead returns immediately. + /// + /// Note that this invalidates any previous receiver which has been created + /// by this timer, and that the returned receiver will be invalidated once + /// the timer is destroyed (when it falls out of scope). In particular, if + /// this is called in method-chaining style, the receiver will be + /// invalidated at the end of that statement, and all `recv` calls will + /// fail. + /// + /// # Example + /// + /// ```rust + /// use std::io::Timer; + /// use std::time::Duration; + /// + /// let mut timer = Timer::new().unwrap(); + /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10)); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 10 ms after the `oneshot` call + /// ten_milliseconds.recv(); + /// ``` + /// + /// ```rust + /// use std::io::Timer; + /// use std::time::Duration; + /// + /// // Incorrect, method chaining-style: + /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5)); + /// // The timer object was destroyed, so this will always fail: + /// // five_ms.recv() + /// ``` + /// + /// When provided a zero or negative `duration`, the message will + /// be sent immediately. + pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { unimplemented!() } + + /// Creates a receiver which will have a continuous stream of notifications + /// being sent each time the specified duration has elapsed. + /// + /// This does *not* block the current task, but instead returns + /// immediately. The first notification will not be received immediately, + /// but rather after the first duration. + /// + /// Note that this invalidates any previous receiver which has been created + /// by this timer, and that the returned receiver will be invalidated once + /// the timer is destroyed (when it falls out of scope). In particular, if + /// this is called in method-chaining style, the receiver will be + /// invalidated at the end of that statement, and all `recv` calls will + /// fail. + /// + /// # Example + /// + /// ```rust + /// use std::io::Timer; + /// use std::time::Duration; + /// + /// let mut timer = Timer::new().unwrap(); + /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10)); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 10 ms after the `periodic` call + /// ten_milliseconds.recv(); + /// + /// for _ in range(0u, 100) { /* do work */ } + /// + /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the + /// // previous `recv`) + /// ten_milliseconds.recv(); + /// ``` + /// + /// ```rust + /// use std::io::Timer; + /// use std::time::Duration; + /// + /// // Incorrect, method chaining-style. + /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5)); + /// // The timer object was destroyed, so this will always fail: + /// // five_ms.recv() + /// ``` + /// + /// When provided a zero or negative `duration`, the messages will + /// be sent without delay. + pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { unimplemented!() } +} + +impl Callback for TimerCallback { + fn call(&mut self) { unimplemented!() } +} + +fn in_ms_u64(d: Duration) -> u64 { unimplemented!() } diff --git a/src/libst2/io/util.rs b/src/libst2/io/util.rs new file mode 100644 index 0000000000000..4e1ffc8f8c85f --- /dev/null +++ b/src/libst2/io/util.rs @@ -0,0 +1,161 @@ +// Copyright 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. + +/*! Utility implementations of Reader and Writer */ + +use prelude::*; +use cmp; +use io; +use slice::bytes::MutableByteVector; + +/// Wraps a `Reader`, limiting the number of bytes that can be read from it. +pub struct LimitReader { + limit: uint, + inner: R +} + +impl LimitReader { + /// Creates a new `LimitReader` + pub fn new(r: R, limit: uint) -> LimitReader { unimplemented!() } + + /// Consumes the `LimitReader`, returning the underlying `Reader`. + pub fn unwrap(self) -> R { unimplemented!() } + + /// Returns the number of bytes that can be read before the `LimitReader` + /// will return EOF. + /// + /// # Note + /// + /// The reader may reach EOF after reading fewer bytes than indicated by + /// this method if the underlying reader reaches EOF. + pub fn limit(&self) -> uint { unimplemented!() } +} + +impl Reader for LimitReader { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} + +impl Buffer for LimitReader { + fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } + + fn consume(&mut self, amt: uint) { unimplemented!() } + +} + +/// A `Writer` which ignores bytes written to it, like /dev/null. +pub struct NullWriter; + +impl Writer for NullWriter { + #[inline] + fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { unimplemented!() } +} + +/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. +pub struct ZeroReader; + +impl Reader for ZeroReader { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} + +impl Buffer for ZeroReader { + fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } + + fn consume(&mut self, _amt: uint) { unimplemented!() } +} + +/// A `Reader` which is always at EOF, like /dev/null. +pub struct NullReader; + +impl Reader for NullReader { + #[inline] + fn read(&mut self, _buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} + +impl Buffer for NullReader { + fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } + fn consume(&mut self, _amt: uint) { unimplemented!() } +} + +/// A `Writer` which multiplexes writes to a set of `Writer`s. +/// +/// The `Writer`s are delegated to in order. If any `Writer` returns an error, +/// that error is returned immediately and remaining `Writer`s are not called. +pub struct MultiWriter { + writers: Vec> +} + +impl MultiWriter { + /// Creates a new `MultiWriter` + pub fn new(writers: Vec>) -> MultiWriter { unimplemented!() } +} + +impl Writer for MultiWriter { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { unimplemented!() } + + #[inline] + fn flush(&mut self) -> io::IoResult<()> { unimplemented!() } +} + +/// A `Reader` which chains input from multiple `Reader`s, reading each to +/// completion before moving onto the next. +pub struct ChainedReader { + readers: I, + cur_reader: Option, +} + +impl> ChainedReader { + /// Creates a new `ChainedReader` + pub fn new(mut readers: I) -> ChainedReader { unimplemented!() } +} + +impl> Reader for ChainedReader { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} + +/// A `Reader` which forwards input from another `Reader`, passing it along to +/// a `Writer` as well. Similar to the `tee(1)` command. +pub struct TeeReader { + reader: R, + writer: W, +} + +impl TeeReader { + /// Creates a new `TeeReader` + pub fn new(r: R, w: W) -> TeeReader { unimplemented!() } + + /// Consumes the `TeeReader`, returning the underlying `Reader` and + /// `Writer`. + pub fn unwrap(self) -> (R, W) { unimplemented!() } +} + +impl Reader for TeeReader { + fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} + +/// Copies all data from a `Reader` to a `Writer`. +pub fn copy(r: &mut R, w: &mut W) -> io::IoResult<()> { unimplemented!() } + +/// An adaptor converting an `Iterator` to a `Reader`. +pub struct IterReader { + iter: T, +} + +impl> IterReader { + /// Creates a new `IterReader` which will read from the specified + /// `Iterator`. + pub fn new(iter: T) -> IterReader { unimplemented!() } +} + +impl> Reader for IterReader { + #[inline] + fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } +} diff --git a/src/libst2/lib.rs b/src/libst2/lib.rs new file mode 100644 index 0000000000000..77da727e94d31 --- /dev/null +++ b/src/libst2/lib.rs @@ -0,0 +1,280 @@ +// 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. + +//! # The Rust Standard Library +//! +//! The Rust Standard Library provides the essential runtime +//! functionality for building portable Rust software. +//! It is linked to all Rust crates by default. +//! +//! ## Intrinsic types and operations +//! +//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html) +//! modules deal with unsafe pointers and memory manipulation. +//! [`kinds`](kinds/index.html) defines the special built-in traits, +//! and [`raw`](raw/index.html) the runtime representation of Rust types. +//! These are some of the lowest-level building blocks in Rust. +//! +//! ## Math on primitive types and math traits +//! +//! Although basic operations on primitive types are implemented +//! directly by the compiler, the standard library additionally +//! defines many common operations through traits defined in +//! mod [`num`](num/index.html). +//! +//! ## Pervasive types +//! +//! The [`option`](option/index.html) and [`result`](result/index.html) +//! modules define optional and error-handling types, `Option` and `Result`. +//! [`iter`](iter/index.html) defines Rust's iterator protocol +//! along with a wide variety of iterators. +//! [`Cell` and `RefCell`](cell/index.html) are for creating types that +//! manage their own mutability. +//! +//! ## Vectors, slices and strings +//! +//! The common container type, `Vec`, a growable vector backed by an +//! array, lives in the [`vec`](vec/index.html) module. References to +//! arrays, `&[T]`, more commonly called "slices", are built-in types +//! for which the [`slice`](slice/index.html) module defines many +//! methods. +//! +//! `&str`, a UTF-8 string, is a built-in type, and the standard library +//! defines methods for it on a variety of traits in the +//! [`str`](str/index.html) module. Rust strings are immutable; +//! use the `String` type defined in [`string`](string/index.html) +//! for a mutable string builder. +//! +//! For converting to strings use the [`format!`](fmt/index.html) +//! macro, and for converting from strings use the +//! [`FromStr`](str/trait.FromStr.html) trait. +//! +//! ## Platform abstractions +//! +//! Besides basic data types, the standard library is largely concerned +//! with abstracting over differences in common platforms, most notably +//! Windows and Unix derivatives. The [`os`](os/index.html) module +//! provides a number of basic functions for interacting with the +//! operating environment, including program arguments, environment +//! variables, and directory navigation. The [`path`](path/index.html) +//! module encapsulates the platform-specific rules for dealing +//! with file paths. +//! +//! `std` also includes modules for interoperating with the +//! C language: [`c_str`](c_str/index.html) and +//! [`c_vec`](c_vec/index.html). +//! +//! ## Concurrency, I/O, and the runtime +//! +//! The [`task`](task/index.html) module contains Rust's threading abstractions, +//! while [`comm`](comm/index.html) contains the channel types for message +//! passing. [`sync`](sync/index.html) contains further, primitive, shared +//! memory types, including [`atomic`](sync/atomic/index.html). +//! +//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets, +//! timers, and process spawning, are defined in the [`io`](io/index.html) module. +//! +//! Rust's I/O and concurrency depends on a small runtime interface +//! that lives, along with its support code, in mod [`rt`](rt/index.html). +//! While a notable part of the standard library's architecture, this +//! module is not intended for public use. +//! +//! ## The Rust prelude and macros +//! +//! Finally, the [`prelude`](prelude/index.html) defines a +//! common set of traits, types, and functions that are made available +//! to all code by default. [`macros`](macros/index.html) contains +//! all the standard macros, such as `assert!`, `panic!`, `println!`, +//! and `format!`, also available to all Rust code. + +#![crate_name = "std"] +#![unstable] +#![comment = "The Rust standard library"] +#![license = "MIT/ASL2"] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://doc.rust-lang.org/nightly/", + html_playground_url = "http://play.rust-lang.org/")] + +#![allow(unknown_features)] +#![feature(macro_rules, globs, linkage)] +#![feature(default_type_params, phase, lang_items, unsafe_destructor)] +#![feature(import_shadowing, slicing_syntax)] + +// Don't link to std. We are std. +#![no_std] + +#![deny(missing_docs)] + +#![reexport_test_harness_main = "test_main"] + +#[cfg(test)] #[phase(plugin, link)] extern crate log; + +extern crate alloc; +extern crate unicode; +extern crate core; +extern crate "collections" as core_collections; +extern crate "rand" as core_rand; +extern crate "sync" as core_sync; +extern crate libc; +extern crate rustrt; + +// Make std testable by not duplicating lang items. See #2912 +#[cfg(test)] extern crate "std" as realstd; +#[cfg(test)] pub use realstd::kinds; +#[cfg(test)] pub use realstd::ops; +#[cfg(test)] pub use realstd::cmp; +#[cfg(test)] pub use realstd::boxed; + + +// NB: These reexports are in the order they should be listed in rustdoc + +pub use core::any; +pub use core::bool; +pub use core::borrow; +pub use core::cell; +pub use core::clone; +#[cfg(not(test))] pub use core::cmp; +pub use core::default; +pub use core::finally; +pub use core::intrinsics; +pub use core::iter; +#[cfg(not(test))] pub use core::kinds; +pub use core::mem; +#[cfg(not(test))] pub use core::ops; +pub use core::ptr; +pub use core::raw; +pub use core::simd; +pub use core::tuple; +// FIXME #15320: primitive documentation needs top-level modules, this +// should be `std::tuple::unit`. +pub use core::unit; +pub use core::result; +pub use core::option; + +pub use alloc::boxed; +pub use alloc::rc; + +pub use core_collections::slice; +pub use core_collections::str; +pub use core_collections::string; +pub use core_collections::vec; + +pub use rustrt::c_str; + +pub use unicode::char; + +pub use core_sync::comm; + +/* Exported macros */ + +pub mod macros; +pub mod bitflags; + +mod rtdeps; + +/* The Prelude. */ + +pub mod prelude; + + +/* Primitive types */ + +#[path = "num/float_macros.rs"] mod float_macros; +#[path = "num/int_macros.rs"] mod int_macros; +#[path = "num/uint_macros.rs"] mod uint_macros; + +#[path = "num/int.rs"] pub mod int; +#[path = "num/i8.rs"] pub mod i8; +#[path = "num/i16.rs"] pub mod i16; +#[path = "num/i32.rs"] pub mod i32; +#[path = "num/i64.rs"] pub mod i64; + +#[path = "num/uint.rs"] pub mod uint; +#[path = "num/u8.rs"] pub mod u8; +#[path = "num/u16.rs"] pub mod u16; +#[path = "num/u32.rs"] pub mod u32; +#[path = "num/u64.rs"] pub mod u64; + +#[path = "num/f32.rs"] pub mod f32; +#[path = "num/f64.rs"] pub mod f64; + +pub mod ascii; + +/* Common traits */ + +pub mod error; +pub mod num; + +/* Runtime and platform support */ + +pub mod thread_local; +pub mod c_vec; +pub mod dynamic_lib; +pub mod fmt; +pub mod io; +pub mod os; +pub mod path; +pub mod rand; +pub mod time; + +/* Common data structures */ + +pub mod collections; +pub mod hash; + +/* Tasks and communication */ + +pub mod task; +pub mod sync; + +#[cfg(unix)] +#[path = "sys/unix/mod.rs"] mod sys; +#[cfg(windows)] +#[path = "sys/windows/mod.rs"] mod sys; + +#[path = "sys/common/mod.rs"] mod sys_common; + +pub mod rt; +mod failure; + +// A curious inner-module that's not exported that contains the binding +// 'std' so that macro-expanded references to std::error and such +// can be resolved within libstd. +#[doc(hidden)] +mod std { + // mods used for deriving + pub use clone; + pub use cmp; + pub use hash; + + pub use comm; // used for select!() + pub use error; // used for try!() + pub use fmt; // used for any formatting strings + pub use io; // used for println!() + pub use option; // used for bitflags!{} + pub use rt; // used for panic!() + pub use vec; // used for vec![] + pub use cell; // used for tls! + pub use thread_local; // used for thread_local! + pub use kinds; // used for tls! + + // The test runner calls ::std::os::args() but really wants realstd + #[cfg(test)] pub use realstd::os as os; + // The test runner requires std::slice::Vector, so re-export std::slice just for it. + // + // It is also used in vec![] + pub use slice; + + pub use boxed; // used for vec![] + +} diff --git a/src/libst2/macros.rs b/src/libst2/macros.rs new file mode 100644 index 0000000000000..08115a313119d --- /dev/null +++ b/src/libst2/macros.rs @@ -0,0 +1,626 @@ +// 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. + +//! Standard library macros +//! +//! This modules contains a set of macros which are exported from the standard +//! library. Each macro is available for use when linking against the standard +//! library. + +#![experimental] +#![macro_escape] + +/// The entry point for panic of Rust tasks. +/// +/// This macro is used to inject panic into a Rust task, causing the task to +/// unwind and panic entirely. Each task's panic can be reaped as the +/// `Box` type, and the single-argument form of the `panic!` macro will be +/// the value which is transmitted. +/// +/// The multi-argument form of this macro panics with a string and has the +/// `format!` syntax for building a string. +/// +/// # Example +/// +/// ```should_fail +/// # #![allow(unreachable_code)] +/// panic!(); +/// panic!("this is a terrible mistake!"); +/// panic!(4i); // panic with the value of 4 to be collected elsewhere +/// panic!("this is a {} {message}", "fancy", message = "message"); +/// ``` +#[macro_export] +macro_rules! panic( + () => ({ + panic!("explicit panic") + }); + ($msg:expr) => ({ + loop { } + }); + ($fmt:expr, $($arg:tt)*) => ({ + loop { } + }); +) + +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// assert!(true); +/// # fn some_computation() -> bool { true } +/// assert!(some_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` +#[macro_export] +macro_rules! assert( + ($cond:expr) => ( + if !$cond { + panic!(concat!("assertion failed: ", stringify!($cond))) + } + ); + ($cond:expr, $($arg:expr),+) => ( + if !$cond { + panic!($($arg),+) + } + ); +) + +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! assert_eq( + ($given:expr , $expected:expr) => ({ + match (&($given), &($expected)) { + (given_val, expected_val) => { + // check both directions of equality.... + if !((*given_val == *expected_val) && + (*expected_val == *given_val)) { + panic!("assertion failed: `(left == right) && (right == left)` \ + (left: `{}`, right: `{}`)", *given_val, *expected_val) + } + } + } + }) +) + +/// Ensure that a boolean expression is `true` at runtime. +/// +/// This will invoke the `panic!` macro if the provided expression cannot be +/// evaluated to `true` at runtime. +/// +/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing +/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for +/// checks that are too expensive to be present in a release build but may be +/// helpful during development. +/// +/// # Example +/// +/// ``` +/// // the panic message for these assertions is the stringified value of the +/// // expression given. +/// debug_assert!(true); +/// # fn some_expensive_computation() -> bool { true } +/// debug_assert!(some_expensive_computation()); +/// +/// // assert with a custom message +/// # let x = true; +/// debug_assert!(x, "x wasn't true!"); +/// # let a = 3i; let b = 27i; +/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert( + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) +) + +/// Asserts that two expressions are equal to each other, testing equality in +/// both directions. +/// +/// On panic, this macro will print the values of the expressions. +/// +/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by +/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` +/// useful for checks that are too expensive to be present in a release build +/// but may be helpful during development. +/// +/// # Example +/// +/// ``` +/// let a = 3i; +/// let b = 1i + 2i; +/// debug_assert_eq!(a, b); +/// ``` +#[macro_export] +macro_rules! debug_assert_eq( + ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) +) + +/// A utility macro for indicating unreachable code. It will panic if +/// executed. This is occasionally useful to put after loops that never +/// terminate normally, but instead directly return from a function. +/// +/// # Example +/// +/// ```{.rust} +/// struct Item { weight: uint } +/// +/// fn choose_weighted_item(v: &[Item]) -> Item { +/// assert!(!v.is_empty()); +/// let mut so_far = 0u; +/// for item in v.iter() { +/// so_far += item.weight; +/// if so_far > 100 { +/// return *item; +/// } +/// } +/// // The above loop always returns, so we must hint to the +/// // type checker that it isn't possible to get down here +/// unreachable!(); +/// } +/// ``` +#[macro_export] +macro_rules! unreachable( + () => ({ + panic!("internal error: entered unreachable code") + }); + ($msg:expr) => ({ + unreachable!("{}", $msg) + }); + ($fmt:expr, $($arg:tt)*) => ({ + panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) + }); +) + +/// A standardised placeholder for marking unfinished code. It panics with the +/// message `"not yet implemented"` when executed. +#[macro_export] +macro_rules! unimplemented( + () => (panic!("not yet implemented")) +) + +/// Use the syntax described in `std::fmt` to create a value of type `String`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// format!("test"); +/// format!("hello {}", "world!"); +/// format!("x = {}, y = {y}", 10i, y = 30i); +/// ``` +#[macro_export] +#[stable] +macro_rules! format( + ($($arg:tt)*) => ( + format_args!(::std::fmt::format, $($arg)*) + ) +) + +/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. +/// See `std::fmt` for more information. +/// +/// # Example +/// +/// ``` +/// # #![allow(unused_must_use)] +/// +/// let mut w = Vec::new(); +/// write!(&mut w, "test"); +/// write!(&mut w, "formatted {}", "arguments"); +/// ``` +#[macro_export] +#[stable] +macro_rules! write( + ($dst:expr, $($arg:tt)*) => ({ + let dst = &mut *$dst; + format_args!(|args| { dst.write_fmt(args) }, $($arg)*) + }) +) + +/// Equivalent to the `write!` macro, except that a newline is appended after +/// the message is written. +#[macro_export] +#[stable] +macro_rules! writeln( + ($dst:expr, $fmt:expr $($arg:tt)*) => ( + write!($dst, concat!($fmt, "\n") $($arg)*) + ) +) + +/// Equivalent to the `println!` macro except that a newline is not printed at +/// the end of the message. +#[macro_export] +#[stable] +macro_rules! print( + ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) +) + +/// Macro for printing to a task's stdout handle. +/// +/// Each task can override its stdout handle via `std::io::stdio::set_stdout`. +/// The syntax of this macro is the same as that used for `format!`. For more +/// information, see `std::fmt` and `std::io::stdio`. +/// +/// # Example +/// +/// ``` +/// println!("hello there!"); +/// println!("format {} arguments", "some"); +/// ``` +#[macro_export] +#[stable] +macro_rules! println( + ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) +) + +/// Helper macro for unwrapping `Result` values while returning early with an +/// error if the value of the expression is `Err`. For more information, see +/// `std::io`. +#[macro_export] +macro_rules! try ( + ($expr:expr) => ({ + match $expr { + Ok(val) => val, + Err(err) => return Err(::std::error::FromError::from_error(err)) + } + }) +) + +/// Create a `std::vec::Vec` containing the arguments. +#[macro_export] +macro_rules! vec[ + ($($x:expr),*) => ({ + use std::slice::BoxedSlicePrelude; + let xs: ::std::boxed::Box<[_]> = box [$($x),*]; + xs.into_vec() + }); + ($($x:expr,)*) => (vec![$($x),*]) +] + +/// A macro to select an event from a number of receivers. +/// +/// This macro is used to wait for the first event to occur on a number of +/// receivers. It places no restrictions on the types of receivers given to +/// this macro, this can be viewed as a heterogeneous select. +/// +/// # Example +/// +/// ``` +/// let (tx1, rx1) = channel(); +/// let (tx2, rx2) = channel(); +/// # fn long_running_task() {} +/// # fn calculate_the_answer() -> int { 42i } +/// +/// spawn(proc() { long_running_task(); tx1.send(()) }); +/// spawn(proc() { tx2.send(calculate_the_answer()) }); +/// +/// select! ( +/// () = rx1.recv() => println!("the long running task finished first"), +/// answer = rx2.recv() => { +/// println!("the answer was: {}", answer); +/// } +/// ) +/// ``` +/// +/// For more information about select, see the `std::comm::Select` structure. +#[macro_export] +#[experimental] +macro_rules! select { + ( + $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ + ) => ({ + use std::comm::Select; + let sel = Select::new(); + $( let mut $rx = sel.handle(&$rx); )+ + unsafe { + $( $rx.add(); )+ + } + let ret = sel.wait(); + $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ + { unreachable!() } + }) +} + +// When testing the standard library, we link to the liblog crate to get the +// logging macros. In doing so, the liblog crate was linked against the real +// version of libstd, and uses a different std::fmt module than the test crate +// uses. To get around this difference, we redefine the log!() macro here to be +// just a dumb version of what it should be. +#[cfg(test)] +macro_rules! log ( + ($lvl:expr, $($args:tt)*) => ( + if log_enabled!($lvl) { println!($($args)*) } + ) +) + +/// Built-in macros to the compiler itself. +/// +/// These macros do not have any corresponding definition with a `macro_rules!` +/// macro, but are documented here. Their implementations can be found hardcoded +/// into libsyntax itself. +#[cfg(dox)] +pub mod builtin { + /// The core macro for formatted string creation & output. + /// + /// This macro takes as its first argument a callable expression which will + /// receive as its first argument a value of type `&fmt::Arguments`. This + /// value can be passed to the functions in `std::fmt` for performing useful + /// functions. All other formatting macros (`format!`, `write!`, + /// `println!`, etc) are proxied through this one. + /// + /// For more information, see the documentation in `std::fmt`. + /// + /// # Example + /// + /// ```rust + /// use std::fmt; + /// + /// let s = format_args!(fmt::format, "hello {}", "world"); + /// assert_eq!(s, format!("hello {}", "world")); + /// + /// format_args!(|args| { + /// // pass `args` to another function, etc. + /// }, "hello {}", "world"); + /// ``` + #[macro_export] + macro_rules! format_args( ($closure:expr, $fmt:expr $($args:tt)*) => ({ + /* compiler built-in */ + }) ) + + /// Inspect an environment variable at compile time. + /// + /// This macro will expand to the value of the named environment variable at + /// compile time, yielding an expression of type `&'static str`. + /// + /// If the environment variable is not defined, then a compilation error + /// will be emitted. To not emit a compile error, use the `option_env!` + /// macro instead. + /// + /// # Example + /// + /// ```rust + /// let path: &'static str = env!("PATH"); + /// println!("the $PATH variable at the time of compiling was: {}", path); + /// ``` + #[macro_export] + macro_rules! env( ($name:expr) => ({ /* compiler built-in */ }) ) + + /// Optionally inspect an environment variable at compile time. + /// + /// If the named environment variable is present at compile time, this will + /// expand into an expression of type `Option<&'static str>` whose value is + /// `Some` of the value of the environment variable. If the environment + /// variable is not present, then this will expand to `None`. + /// + /// A compile time error is never emitted when using this macro regardless + /// of whether the environment variable is present or not. + /// + /// # Example + /// + /// ```rust + /// let key: Option<&'static str> = option_env!("SECRET_KEY"); + /// println!("the secret key might be: {}", key); + /// ``` + #[macro_export] + macro_rules! option_env( ($name:expr) => ({ /* compiler built-in */ }) ) + + /// Concatenate literals into a static byte slice. + /// + /// This macro takes any number of comma-separated literal expressions, + /// yielding an expression of type `&'static [u8]` which is the + /// concatenation (left to right) of all the literals in their byte format. + /// + /// This extension currently only supports string literals, character + /// literals, and integers less than 256. The byte slice returned is the + /// utf8-encoding of strings and characters. + /// + /// # Example + /// + /// ``` + /// let rust = bytes!("r", 'u', "st", 255); + /// assert_eq!(rust[1], b'u'); + /// assert_eq!(rust[4], 255); + /// ``` + #[macro_export] + macro_rules! bytes( ($($e:expr),*) => ({ /* compiler built-in */ }) ) + + /// Concatenate identifiers into one identifier. + /// + /// This macro takes any number of comma-separated identifiers, and + /// concatenates them all into one, yielding an expression which is a new + /// identifier. Note that hygiene makes it such that this macro cannot + /// capture local variables, and macros are only allowed in item, + /// statement or expression position, meaning this macro may be difficult to + /// use in some situations. + /// + /// # Example + /// + /// ``` + /// #![feature(concat_idents)] + /// + /// # fn main() { + /// fn foobar() -> int { 23 } + /// + /// let f = concat_idents!(foo, bar); + /// println!("{}", f()); + /// # } + /// ``` + #[macro_export] + macro_rules! concat_idents( ($($e:ident),*) => ({ /* compiler built-in */ }) ) + + /// Concatenates literals into a static string slice. + /// + /// This macro takes any number of comma-separated literals, yielding an + /// expression of type `&'static str` which represents all of the literals + /// concatenated left-to-right. + /// + /// Integer and floating point literals are stringified in order to be + /// concatenated. + /// + /// # Example + /// + /// ``` + /// let s = concat!("test", 10i, 'b', true); + /// assert_eq!(s, "test10btrue"); + /// ``` + #[macro_export] + macro_rules! concat( ($($e:expr),*) => ({ /* compiler built-in */ }) ) + + /// A macro which expands to the line number on which it was invoked. + /// + /// The expanded expression has type `uint`, and the returned line is not + /// the invocation of the `line!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `line!()` macro. + /// + /// # Example + /// + /// ``` + /// let current_line = line!(); + /// println!("defined on line: {}", current_line); + /// ``` + #[macro_export] + macro_rules! line( () => ({ /* compiler built-in */ }) ) + + /// A macro which expands to the column number on which it was invoked. + /// + /// The expanded expression has type `uint`, and the returned column is not + /// the invocation of the `column!()` macro itself, but rather the first macro + /// invocation leading up to the invocation of the `column!()` macro. + /// + /// # Example + /// + /// ``` + /// let current_col = column!(); + /// println!("defined on column: {}", current_col); + /// ``` + #[macro_export] + macro_rules! column( () => ({ /* compiler built-in */ }) ) + + /// A macro which expands to the file name from which it was invoked. + /// + /// The expanded expression has type `&'static str`, and the returned file + /// is not the invocation of the `file!()` macro itself, but rather the + /// first macro invocation leading up to the invocation of the `file!()` + /// macro. + /// + /// # Example + /// + /// ``` + /// let this_file = file!(); + /// println!("defined in file: {}", this_file); + /// ``` + #[macro_export] + macro_rules! file( () => ({ /* compiler built-in */ }) ) + + /// A macro which stringifies its argument. + /// + /// This macro will yield an expression of type `&'static str` which is the + /// stringification of all the tokens passed to the macro. No restrictions + /// are placed on the syntax of the macro invocation itself. + /// + /// # Example + /// + /// ``` + /// let one_plus_one = stringify!(1 + 1); + /// assert_eq!(one_plus_one, "1 + 1"); + /// ``` + #[macro_export] + macro_rules! stringify( ($t:tt) => ({ /* compiler built-in */ }) ) + + /// Includes a utf8-encoded file as a string. + /// + /// This macro will yield an expression of type `&'static str` which is the + /// contents of the filename specified. The file is located relative to the + /// current file (similarly to how modules are found), + /// + /// # Example + /// + /// ```rust,ignore + /// let secret_key = include_str!("secret-key.ascii"); + /// ``` + #[macro_export] + macro_rules! include_str( ($file:expr) => ({ /* compiler built-in */ }) ) + + /// Includes a file as a byte slice. + /// + /// This macro will yield an expression of type `&'static [u8]` which is + /// the contents of the filename specified. The file is located relative to + /// the current file (similarly to how modules are found), + /// + /// # Example + /// + /// ```rust,ignore + /// let secret_key = include_bin!("secret-key.bin"); + /// ``` + #[macro_export] + macro_rules! include_bin( ($file:expr) => ({ /* compiler built-in */ }) ) + + /// Expands to a string that represents the current module path. + /// + /// The current module path can be thought of as the hierarchy of modules + /// leading back up to the crate root. The first component of the path + /// returned is the name of the crate currently being compiled. + /// + /// # Example + /// + /// ```rust + /// mod test { + /// pub fn foo() { + /// assert!(module_path!().ends_with("test")); + /// } + /// } + /// + /// test::foo(); + /// ``` + #[macro_export] + macro_rules! module_path( () => ({ /* compiler built-in */ }) ) + + /// Boolean evaluation of configuration flags. + /// + /// In addition to the `#[cfg]` attribute, this macro is provided to allow + /// boolean expression evaluation of configuration flags. This frequently + /// leads to less duplicated code. + /// + /// The syntax given to this macro is the same syntax as the `cfg` + /// attribute. + /// + /// # Example + /// + /// ```rust + /// let my_directory = if cfg!(windows) { + /// "windows-specific-directory" + /// } else { + /// "unix-directory" + /// }; + /// ``` + #[macro_export] + macro_rules! cfg( ($cfg:tt) => ({ /* compiler built-in */ }) ) +} diff --git a/src/libst2/num/f32.rs b/src/libst2/num/f32.rs new file mode 100644 index 0000000000000..6c48d747299b2 --- /dev/null +++ b/src/libst2/num/f32.rs @@ -0,0 +1,261 @@ +// 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. + +//! Operations and constants for 32-bits floats (`f32` type) + +#![stable] +#![allow(missing_docs)] +#![allow(unsigned_negation)] +#![doc(primitive = "f32")] + +use prelude::*; + +use intrinsics; +use libc::c_int; +use num::{Float, FloatMath}; +use num::strconv; + +pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; +pub use core::f32::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; +pub use core::f32::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; +pub use core::f32::consts; + +#[allow(dead_code)] +mod cmath { + use libc::{c_float, c_int}; + + #[link_name = "m"] + extern { + pub fn acosf(n: c_float) -> c_float; + pub fn asinf(n: c_float) -> c_float; + pub fn atanf(n: c_float) -> c_float; + pub fn atan2f(a: c_float, b: c_float) -> c_float; + pub fn cbrtf(n: c_float) -> c_float; + pub fn coshf(n: c_float) -> c_float; + pub fn erff(n: c_float) -> c_float; + pub fn erfcf(n: c_float) -> c_float; + pub fn expm1f(n: c_float) -> c_float; + pub fn fdimf(a: c_float, b: c_float) -> c_float; + pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; + pub fn fmaxf(a: c_float, b: c_float) -> c_float; + pub fn fminf(a: c_float, b: c_float) -> c_float; + pub fn fmodf(a: c_float, b: c_float) -> c_float; + pub fn nextafterf(x: c_float, y: c_float) -> c_float; + pub fn hypotf(x: c_float, y: c_float) -> c_float; + pub fn ldexpf(x: c_float, n: c_int) -> c_float; + pub fn logbf(n: c_float) -> c_float; + pub fn log1pf(n: c_float) -> c_float; + pub fn ilogbf(n: c_float) -> c_int; + pub fn modff(n: c_float, iptr: &mut c_float) -> c_float; + pub fn sinhf(n: c_float) -> c_float; + pub fn tanf(n: c_float) -> c_float; + pub fn tanhf(n: c_float) -> c_float; + pub fn tgammaf(n: c_float) -> c_float; + + #[cfg(unix)] + pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; + + #[cfg(windows)] + #[link_name="__lgammaf_r"] + pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; + } +} + +#[unstable = "trait is unstable"] +impl FloatMath for f32 { + /// Constructs a floating point number by multiplying `x` by 2 raised to the + /// power of `exp` + #[inline] + fn ldexp(x: f32, exp: int) -> f32 { unimplemented!() } + + /// Breaks the number into a normalized fraction and a base-2 exponent, + /// satisfying: + /// + /// - `self = x * pow(2, exp)` + /// - `0.5 <= abs(x) < 1.0` + #[inline] + fn frexp(self) -> (f32, int) { unimplemented!() } + + /// Returns the next representable floating-point value in the direction of + /// `other`. + #[inline] + fn next_after(self, other: f32) -> f32 { unimplemented!() } + + #[inline] + fn max(self, other: f32) -> f32 { unimplemented!() } + + #[inline] + fn min(self, other: f32) -> f32 { unimplemented!() } + + #[inline] + fn abs_sub(self, other: f32) -> f32 { unimplemented!() } + + #[inline] + fn cbrt(self) -> f32 { unimplemented!() } + + #[inline] + fn hypot(self, other: f32) -> f32 { unimplemented!() } + + #[inline] + fn sin(self) -> f32 { unimplemented!() } + + #[inline] + fn cos(self) -> f32 { unimplemented!() } + + #[inline] + fn tan(self) -> f32 { unimplemented!() } + + #[inline] + fn asin(self) -> f32 { unimplemented!() } + + #[inline] + fn acos(self) -> f32 { unimplemented!() } + + #[inline] + fn atan(self) -> f32 { unimplemented!() } + + #[inline] + fn atan2(self, other: f32) -> f32 { unimplemented!() } + + /// Simultaneously computes the sine and cosine of the number + #[inline] + fn sin_cos(self) -> (f32, f32) { unimplemented!() } + + /// Returns the exponential of the number, minus `1`, in a way that is + /// accurate even if the number is close to zero + #[inline] + fn exp_m1(self) -> f32 { unimplemented!() } + + /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more + /// accurately than if the operations were performed separately + #[inline] + fn ln_1p(self) -> f32 { unimplemented!() } + + #[inline] + fn sinh(self) -> f32 { unimplemented!() } + + #[inline] + fn cosh(self) -> f32 { unimplemented!() } + + #[inline] + fn tanh(self) -> f32 { unimplemented!() } + + /// Inverse hyperbolic sine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic sine of `self` will be returned + /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` + /// - `NAN` if `self` is `NAN` + #[inline] + fn asinh(self) -> f32 { unimplemented!() } + + /// Inverse hyperbolic cosine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic cosine of `self` will be returned + /// - `INFINITY` if `self` is `INFINITY` + /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) + #[inline] + fn acosh(self) -> f32 { unimplemented!() } + + /// Inverse hyperbolic tangent + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic tangent of `self` will be returned + /// - `self` if `self` is `0.0` or `-0.0` + /// - `INFINITY` if `self` is `1.0` + /// - `NEG_INFINITY` if `self` is `-1.0` + /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` + /// (including `INFINITY` and `NEG_INFINITY`) + #[inline] + fn atanh(self) -> f32 { unimplemented!() } +} + +// +// Section: String Conversions +// + +/// Converts a float to a string +/// +/// # Arguments +/// +/// * num - The float value +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_string(num: f32) -> String { unimplemented!() } + +/// Converts a float to a string in hexadecimal format +/// +/// # Arguments +/// +/// * num - The float value +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_hex(num: f32) -> String { unimplemented!() } + +/// Converts a float to a string in a given radix, and a flag indicating +/// whether it's a special value +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_radix_special(num: f32, rdx: uint) -> (String, bool) { unimplemented!() } + +/// Converts a float to a string with exactly the number of +/// provided significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exact(num: f32, dig: uint) -> String { unimplemented!() } + +/// Converts a float to a string with a maximum number of +/// significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_digits(num: f32, dig: uint) -> String { unimplemented!() } + +/// Converts a float to a string using the exponential notation with exactly the number of +/// provided digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> String { unimplemented!() } + +/// Converts a float to a string using the exponential notation with the maximum number of +/// digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String { unimplemented!() } diff --git a/src/libst2/num/f64.rs b/src/libst2/num/f64.rs new file mode 100644 index 0000000000000..5c196c8229662 --- /dev/null +++ b/src/libst2/num/f64.rs @@ -0,0 +1,269 @@ +// 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. + +//! Operations and constants for 64-bits floats (`f64` type) + +#![stable] +#![allow(missing_docs)] +#![doc(primitive = "f64")] + +use prelude::*; + +use intrinsics; +use libc::c_int; +use num::{Float, FloatMath}; +use num::strconv; + +pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; +pub use core::f64::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; +pub use core::f64::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; +pub use core::f64::consts; + +#[allow(dead_code)] +mod cmath { + use libc::{c_double, c_int}; + + #[link_name = "m"] + extern { + pub fn acos(n: c_double) -> c_double; + pub fn asin(n: c_double) -> c_double; + pub fn atan(n: c_double) -> c_double; + pub fn atan2(a: c_double, b: c_double) -> c_double; + pub fn cbrt(n: c_double) -> c_double; + pub fn cosh(n: c_double) -> c_double; + pub fn erf(n: c_double) -> c_double; + pub fn erfc(n: c_double) -> c_double; + pub fn expm1(n: c_double) -> c_double; + pub fn fdim(a: c_double, b: c_double) -> c_double; + pub fn fmax(a: c_double, b: c_double) -> c_double; + pub fn fmin(a: c_double, b: c_double) -> c_double; + pub fn fmod(a: c_double, b: c_double) -> c_double; + pub fn nextafter(x: c_double, y: c_double) -> c_double; + pub fn frexp(n: c_double, value: &mut c_int) -> c_double; + pub fn hypot(x: c_double, y: c_double) -> c_double; + pub fn ldexp(x: c_double, n: c_int) -> c_double; + pub fn logb(n: c_double) -> c_double; + pub fn log1p(n: c_double) -> c_double; + pub fn ilogb(n: c_double) -> c_int; + pub fn modf(n: c_double, iptr: &mut c_double) -> c_double; + pub fn sinh(n: c_double) -> c_double; + pub fn tan(n: c_double) -> c_double; + pub fn tanh(n: c_double) -> c_double; + pub fn tgamma(n: c_double) -> c_double; + + // These are commonly only available for doubles + + pub fn j0(n: c_double) -> c_double; + pub fn j1(n: c_double) -> c_double; + pub fn jn(i: c_int, n: c_double) -> c_double; + + pub fn y0(n: c_double) -> c_double; + pub fn y1(n: c_double) -> c_double; + pub fn yn(i: c_int, n: c_double) -> c_double; + + #[cfg(unix)] + pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; + #[cfg(windows)] + #[link_name="__lgamma_r"] + pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; + } +} + +#[unstable = "trait is unstable"] +impl FloatMath for f64 { + /// Constructs a floating point number by multiplying `x` by 2 raised to the + /// power of `exp` + #[inline] + fn ldexp(x: f64, exp: int) -> f64 { unimplemented!() } + + /// Breaks the number into a normalized fraction and a base-2 exponent, + /// satisfying: + /// + /// - `self = x * pow(2, exp)` + /// - `0.5 <= abs(x) < 1.0` + #[inline] + fn frexp(self) -> (f64, int) { unimplemented!() } + + /// Returns the next representable floating-point value in the direction of + /// `other`. + #[inline] + fn next_after(self, other: f64) -> f64 { unimplemented!() } + + #[inline] + fn max(self, other: f64) -> f64 { unimplemented!() } + + #[inline] + fn min(self, other: f64) -> f64 { unimplemented!() } + + #[inline] + fn abs_sub(self, other: f64) -> f64 { unimplemented!() } + + #[inline] + fn cbrt(self) -> f64 { unimplemented!() } + + #[inline] + fn hypot(self, other: f64) -> f64 { unimplemented!() } + + #[inline] + fn sin(self) -> f64 { unimplemented!() } + + #[inline] + fn cos(self) -> f64 { unimplemented!() } + + #[inline] + fn tan(self) -> f64 { unimplemented!() } + + #[inline] + fn asin(self) -> f64 { unimplemented!() } + + #[inline] + fn acos(self) -> f64 { unimplemented!() } + + #[inline] + fn atan(self) -> f64 { unimplemented!() } + + #[inline] + fn atan2(self, other: f64) -> f64 { unimplemented!() } + + /// Simultaneously computes the sine and cosine of the number + #[inline] + fn sin_cos(self) -> (f64, f64) { unimplemented!() } + + /// Returns the exponential of the number, minus `1`, in a way that is + /// accurate even if the number is close to zero + #[inline] + fn exp_m1(self) -> f64 { unimplemented!() } + + /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more + /// accurately than if the operations were performed separately + #[inline] + fn ln_1p(self) -> f64 { unimplemented!() } + + #[inline] + fn sinh(self) -> f64 { unimplemented!() } + + #[inline] + fn cosh(self) -> f64 { unimplemented!() } + + #[inline] + fn tanh(self) -> f64 { unimplemented!() } + + /// Inverse hyperbolic sine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic sine of `self` will be returned + /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` + /// - `NAN` if `self` is `NAN` + #[inline] + fn asinh(self) -> f64 { unimplemented!() } + + /// Inverse hyperbolic cosine + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic cosine of `self` will be returned + /// - `INFINITY` if `self` is `INFINITY` + /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) + #[inline] + fn acosh(self) -> f64 { unimplemented!() } + + /// Inverse hyperbolic tangent + /// + /// # Returns + /// + /// - on success, the inverse hyperbolic tangent of `self` will be returned + /// - `self` if `self` is `0.0` or `-0.0` + /// - `INFINITY` if `self` is `1.0` + /// - `NEG_INFINITY` if `self` is `-1.0` + /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` + /// (including `INFINITY` and `NEG_INFINITY`) + #[inline] + fn atanh(self) -> f64 { unimplemented!() } +} + +// +// Section: String Conversions +// + +/// Converts a float to a string +/// +/// # Arguments +/// +/// * num - The float value +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_string(num: f64) -> String { unimplemented!() } + +/// Converts a float to a string in hexadecimal format +/// +/// # Arguments +/// +/// * num - The float value +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_hex(num: f64) -> String { unimplemented!() } + +/// Converts a float to a string in a given radix, and a flag indicating +/// whether it's a special value +/// +/// # Arguments +/// +/// * num - The float value +/// * radix - The base to use +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_radix_special(num: f64, rdx: uint) -> (String, bool) { unimplemented!() } + +/// Converts a float to a string with exactly the number of +/// provided significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exact(num: f64, dig: uint) -> String { unimplemented!() } + +/// Converts a float to a string with a maximum number of +/// significant digits +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of significant digits +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_digits(num: f64, dig: uint) -> String { unimplemented!() } + +/// Converts a float to a string using the exponential notation with exactly the number of +/// provided digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exp_exact(num: f64, dig: uint, upper: bool) -> String { unimplemented!() } + +/// Converts a float to a string using the exponential notation with the maximum number of +/// digits after the decimal point in the significand +/// +/// # Arguments +/// +/// * num - The float value +/// * digits - The number of digits after the decimal point +/// * upper - Use `E` instead of `e` for the exponent sign +#[inline] +#[experimental = "may be removed or relocated"] +pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String { unimplemented!() } diff --git a/src/libst2/num/float_macros.rs b/src/libst2/num/float_macros.rs new file mode 100644 index 0000000000000..4b3727ead6148 --- /dev/null +++ b/src/libst2/num/float_macros.rs @@ -0,0 +1,22 @@ +// 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. + +#![experimental] +#![macro_escape] +#![doc(hidden)] + +macro_rules! assert_approx_eq( + ($a:expr, $b:expr) => ({ + use num::Float; + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +) diff --git a/src/libst2/num/i16.rs b/src/libst2/num/i16.rs new file mode 100644 index 0000000000000..333d1d7df0b5c --- /dev/null +++ b/src/libst2/num/i16.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for signed 16-bits integers (`i16` type) + +#![stable] +#![doc(primitive = "i16")] + +pub use core::i16::{BITS, BYTES, MIN, MAX}; + +int_module!(i16) diff --git a/src/libst2/num/i32.rs b/src/libst2/num/i32.rs new file mode 100644 index 0000000000000..44b5397bf74e5 --- /dev/null +++ b/src/libst2/num/i32.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for signed 32-bits integers (`i32` type) + +#![stable] +#![doc(primitive = "i32")] + +pub use core::i32::{BITS, BYTES, MIN, MAX}; + +int_module!(i32) diff --git a/src/libst2/num/i64.rs b/src/libst2/num/i64.rs new file mode 100644 index 0000000000000..de6fa0d3ef841 --- /dev/null +++ b/src/libst2/num/i64.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for signed 64-bits integers (`i64` type) + +#![stable] +#![doc(primitive = "i64")] + +pub use core::i64::{BITS, BYTES, MIN, MAX}; + +int_module!(i64) diff --git a/src/libst2/num/i8.rs b/src/libst2/num/i8.rs new file mode 100644 index 0000000000000..3b9fbcb768bee --- /dev/null +++ b/src/libst2/num/i8.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for signed 8-bits integers (`i8` type) + +#![stable] +#![doc(primitive = "i8")] + +pub use core::i8::{BITS, BYTES, MIN, MAX}; + +int_module!(i8) diff --git a/src/libst2/num/int.rs b/src/libst2/num/int.rs new file mode 100644 index 0000000000000..36c021efe0a39 --- /dev/null +++ b/src/libst2/num/int.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for architecture-sized signed integers (`int` type) + +#![unstable] +#![doc(primitive = "int")] + +pub use core::int::{BITS, BYTES, MIN, MAX}; + +int_module!(int) diff --git a/src/libst2/num/int_macros.rs b/src/libst2/num/int_macros.rs new file mode 100644 index 0000000000000..2f1162d28e558 --- /dev/null +++ b/src/libst2/num/int_macros.rs @@ -0,0 +1,17 @@ +// 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. + +#![experimental] +#![macro_escape] +#![doc(hidden)] + +macro_rules! int_module (($T:ty) => ( + +)) diff --git a/src/libst2/num/mod.rs b/src/libst2/num/mod.rs new file mode 100644 index 0000000000000..dd2a8e8cc8fb7 --- /dev/null +++ b/src/libst2/num/mod.rs @@ -0,0 +1,143 @@ +// 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. + +//! Numeric traits and functions for generic mathematics +//! +//! These are implemented for the primitive numeric types in `std::{u8, u16, +//! u32, u64, uint, i8, i16, i32, i64, int, f32, f64}`. + +#![stable] +#![allow(missing_docs)] + +#[cfg(test)] use cmp::PartialEq; +#[cfg(test)] use fmt::Show; +#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; + +pub use core::num::{Num, div_rem, Zero, zero, One, one}; +pub use core::num::{Unsigned, pow, Bounded}; +pub use core::num::{Primitive, Int, SignedInt, UnsignedInt}; +pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; +pub use core::num::{next_power_of_two, is_power_of_two}; +pub use core::num::{checked_next_power_of_two}; +pub use core::num::{from_int, from_i8, from_i16, from_i32, from_i64}; +pub use core::num::{from_uint, from_u8, from_u16, from_u32, from_u64}; +pub use core::num::{from_f32, from_f64}; +pub use core::num::{FromStrRadix, from_str_radix}; +pub use core::num::{FPCategory, FPNaN, FPInfinite, FPZero, FPSubnormal}; +pub use core::num::{FPNormal, Float}; + +#[experimental = "may be removed or relocated"] +pub mod strconv; + +/// Mathematical operations on primitive floating point numbers. +#[unstable = "may be altered to inline the Float trait"] +pub trait FloatMath: Float { + /// Constructs a floating point number created by multiplying `x` by 2 + /// raised to the power of `exp`. + fn ldexp(x: Self, exp: int) -> Self; + /// Breaks the number into a normalized fraction and a base-2 exponent, + /// satisfying: + /// + /// * `self = x * pow(2, exp)` + /// + /// * `0.5 <= abs(x) < 1.0` + fn frexp(self) -> (Self, int); + + /// Returns the next representable floating-point value in the direction of + /// `other`. + fn next_after(self, other: Self) -> Self; + + /// Returns the maximum of the two numbers. + fn max(self, other: Self) -> Self; + /// Returns the minimum of the two numbers. + fn min(self, other: Self) -> Self; + + /// The positive difference of two numbers. Returns `0.0` if the number is + /// less than or equal to `other`, otherwise the difference between`self` + /// and `other` is returned. + fn abs_sub(self, other: Self) -> Self; + + /// Take the cubic root of a number. + fn cbrt(self) -> Self; + /// Calculate the length of the hypotenuse of a right-angle triangle given + /// legs of length `x` and `y`. + fn hypot(self, other: Self) -> Self; + + /// Computes the sine of a number (in radians). + fn sin(self) -> Self; + /// Computes the cosine of a number (in radians). + fn cos(self) -> Self; + /// Computes the tangent of a number (in radians). + fn tan(self) -> Self; + + /// Computes the arcsine of a number. Return value is in radians in + /// the range [-pi/2, pi/2] or NaN if the number is outside the range + /// [-1, 1]. + fn asin(self) -> Self; + /// Computes the arccosine of a number. Return value is in radians in + /// the range [0, pi] or NaN if the number is outside the range + /// [-1, 1]. + fn acos(self) -> Self; + /// Computes the arctangent of a number. Return value is in radians in the + /// range [-pi/2, pi/2]; + fn atan(self) -> Self; + /// Computes the four quadrant arctangent of a number, `y`, and another + /// number `x`. Return value is in radians in the range [-pi, pi]. + fn atan2(self, other: Self) -> Self; + /// Simultaneously computes the sine and cosine of the number, `x`. Returns + /// `(sin(x), cos(x))`. + fn sin_cos(self) -> (Self, Self); + + /// Returns the exponential of the number, minus 1, in a way that is + /// accurate even if the number is close to zero. + fn exp_m1(self) -> Self; + /// Returns the natural logarithm of the number plus 1 (`ln(1+n)`) more + /// accurately than if the operations were performed separately. + fn ln_1p(self) -> Self; + + /// Hyperbolic sine function. + fn sinh(self) -> Self; + /// Hyperbolic cosine function. + fn cosh(self) -> Self; + /// Hyperbolic tangent function. + fn tanh(self) -> Self; + /// Inverse hyperbolic sine function. + fn asinh(self) -> Self; + /// Inverse hyperbolic cosine function. + fn acosh(self) -> Self; + /// Inverse hyperbolic tangent function. + fn atanh(self) -> Self; +} + +// DEPRECATED + +#[deprecated = "Use `FloatMath::abs_sub`"] +pub fn abs_sub(x: T, y: T) -> T { unimplemented!() } + +/// Helper function for testing numeric operations +#[cfg(test)] +pub fn test_num(ten: T, two: T) where + T: PartialEq + NumCast + + Add + Sub + + Mul + Div + + Rem + Show +{ + assert_eq!(ten.add(&two), cast(12i).unwrap()); + assert_eq!(ten.sub(&two), cast(8i).unwrap()); + assert_eq!(ten.mul(&two), cast(20i).unwrap()); + assert_eq!(ten.div(&two), cast(5i).unwrap()); + assert_eq!(ten.rem(&two), cast(0i).unwrap()); + + assert_eq!(ten.add(&two), ten + two); + assert_eq!(ten.sub(&two), ten - two); + assert_eq!(ten.mul(&two), ten * two); + assert_eq!(ten.div(&two), ten / two); + assert_eq!(ten.rem(&two), ten % two); +} diff --git a/src/libst2/num/strconv.rs b/src/libst2/num/strconv.rs new file mode 100644 index 0000000000000..649298d9c0818 --- /dev/null +++ b/src/libst2/num/strconv.rs @@ -0,0 +1,558 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15679 + +#![allow(missing_docs)] + +pub use self::ExponentFormat::*; +pub use self::SignificantDigits::*; +pub use self::SignFormat::*; + +use char; +use char::Char; +use num; +use num::{Int, Float, FPNaN, FPInfinite, ToPrimitive}; +use slice::{SlicePrelude, CloneSliceAllocPrelude}; +use str::StrPrelude; +use string::String; +use vec::Vec; + +/// A flag that specifies whether to use exponential (scientific) notation. +pub enum ExponentFormat { + /// Do not use exponential notation. + ExpNone, + /// Use exponential notation with the exponent having a base of 10 and the + /// exponent sign being `e` or `E`. For example, 1000 would be printed + /// 1e3. + ExpDec, + /// Use exponential notation with the exponent having a base of 2 and the + /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3. + ExpBin, +} + +/// The number of digits used for emitting the fractional part of a number, if +/// any. +pub enum SignificantDigits { + /// All calculable digits will be printed. + /// + /// Note that bignums or fractions may cause a surprisingly large number + /// of digits to be printed. + DigAll, + + /// At most the given number of digits will be printed, truncating any + /// trailing zeroes. + DigMax(uint), + + /// Precisely the given number of digits will be printed. + DigExact(uint) +} + +/// How to emit the sign of a number. +pub enum SignFormat { + /// No sign will be printed. The exponent sign will also be emitted. + SignNone, + /// `-` will be printed for negative values, but no sign will be emitted + /// for positive numbers. + SignNeg, + /// `+` will be printed for positive values, and `-` will be printed for + /// negative values. + SignAll, +} + +/** + * Converts an integral number to its string representation as a byte vector. + * This is meant to be a common base implementation for all integral string + * conversion functions like `to_string()` or `to_str_radix()`. + * + * # Arguments + * - `num` - The number to convert. Accepts any number that + * implements the numeric traits. + * - `radix` - Base to use. Accepts only the values 2-36. + * - `sign` - How to emit the sign. Options are: + * - `SignNone`: No sign at all. Basically emits `abs(num)`. + * - `SignNeg`: Only `-` on negative values. + * - `SignAll`: Both `+` on positive, and `-` on negative numbers. + * - `f` - a callback which will be invoked for each ascii character + * which composes the string representation of this integer + * + * # Return value + * A tuple containing the byte vector, and a boolean flag indicating + * whether it represents a special value like `inf`, `-inf`, `NaN` or not. + * It returns a tuple because there can be ambiguity between a special value + * and a number representation at higher bases. + * + * # Panics + * - Panics if `radix` < 2 or `radix` > 36. + */ +fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8|) { + assert!(2 <= radix && radix <= 36); + + let _0: T = Int::zero(); + + let neg = num < _0; + let radix_gen: T = num::cast(radix).unwrap(); + + let mut deccum = num; + // This is just for integral types, the largest of which is a u64. The + // smallest base that we can have is 2, so the most number of digits we're + // ever going to have is 64 + let mut buf = [0u8, ..64]; + let mut cur = 0; + + // Loop at least once to make sure at least a `0` gets emitted. + loop { + // Calculate the absolute value of each digit instead of only + // doing it once for the whole number because a + // representable negative number doesn't necessary have an + // representable additive inverse of the same type + // (See twos complement). But we assume that for the + // numbers [-35 .. 0] we always have [0 .. 35]. + let current_digit_signed = deccum % radix_gen; + let current_digit = if current_digit_signed < _0 { + _0 - current_digit_signed + } else { + current_digit_signed + }; + buf[cur] = match current_digit.to_u8().unwrap() { + i @ 0...9 => b'0' + i, + i => b'a' + (i - 10), + }; + cur += 1; + + deccum = deccum / radix_gen; + // No more digits to calculate for the non-fractional part -> break + if deccum == _0 { break; } + } + + // Decide what sign to put in front + match sign { + SignNeg | SignAll if neg => { f(b'-'); } + SignAll => { f(b'+'); } + _ => () + } + + // We built the number in reverse order, so un-reverse it here + while cur > 0 { + cur -= 1; + f(buf[cur]); + } +} + +/** + * Converts a number to its string representation as a byte vector. + * This is meant to be a common base implementation for all numeric string + * conversion functions like `to_string()` or `to_str_radix()`. + * + * # Arguments + * - `num` - The number to convert. Accepts any number that + * implements the numeric traits. + * - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation + * is used, then this base is only used for the significand. The exponent + * itself always printed using a base of 10. + * - `negative_zero` - Whether to treat the special value `-0` as + * `-0` or as `+0`. + * - `sign` - How to emit the sign. See `SignFormat`. + * - `digits` - The amount of digits to use for emitting the fractional + * part, if any. See `SignificantDigits`. + * - `exp_format` - Whether or not to use the exponential (scientific) notation. + * See `ExponentFormat`. + * - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if + * exponential notation is desired. + * + * # Return value + * A tuple containing the byte vector, and a boolean flag indicating + * whether it represents a special value like `inf`, `-inf`, `NaN` or not. + * It returns a tuple because there can be ambiguity between a special value + * and a number representation at higher bases. + * + * # Panics + * - Panics if `radix` < 2 or `radix` > 36. + * - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict + * between digit and exponent sign `'e'`. + * - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict + * between digit and exponent sign `'p'`. + */ +pub fn float_to_str_bytes_common( + num: T, radix: uint, negative_zero: bool, + sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool + ) -> (Vec, bool) { + assert!(2 <= radix && radix <= 36); + match exp_format { + ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' + => panic!("float_to_str_bytes_common: radix {} incompatible with \ + use of 'e' as decimal exponent", radix), + ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' + => panic!("float_to_str_bytes_common: radix {} incompatible with \ + use of 'p' as binary exponent", radix), + _ => () + } + + let _0: T = Float::zero(); + let _1: T = Float::one(); + + match num.classify() { + FPNaN => { return (b"NaN".to_vec(), true); } + FPInfinite if num > _0 => { + return match sign { + SignAll => (b"+inf".to_vec(), true), + _ => (b"inf".to_vec(), true) + }; + } + FPInfinite if num < _0 => { + return match sign { + SignNone => (b"inf".to_vec(), true), + _ => (b"-inf".to_vec(), true), + }; + } + _ => {} + } + + let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); + let mut buf = Vec::new(); + let radix_gen: T = num::cast(radix as int).unwrap(); + + let (num, exp) = match exp_format { + ExpNone => (num, 0i32), + ExpDec | ExpBin => { + if num == _0 { + (num, 0i32) + } else { + let (exp, exp_base) = match exp_format { + ExpDec => (num.abs().log10().floor(), num::cast::(10.0f64).unwrap()), + ExpBin => (num.abs().log2().floor(), num::cast::(2.0f64).unwrap()), + ExpNone => unreachable!() + }; + + (num / exp_base.powf(exp), num::cast::(exp).unwrap()) + } + } + }; + + // First emit the non-fractional part, looping at least once to make + // sure at least a `0` gets emitted. + let mut deccum = num.trunc(); + loop { + // Calculate the absolute value of each digit instead of only + // doing it once for the whole number because a + // representable negative number doesn't necessary have an + // representable additive inverse of the same type + // (See twos complement). But we assume that for the + // numbers [-35 .. 0] we always have [0 .. 35]. + let current_digit = (deccum % radix_gen).abs(); + + // Decrease the deccumulator one digit at a time + deccum = deccum / radix_gen; + deccum = deccum.trunc(); + + buf.push(char::from_digit(current_digit.to_int().unwrap() as uint, radix) + .unwrap() as u8); + + // No more digits to calculate for the non-fractional part -> break + if deccum == _0 { break; } + } + + // If limited digits, calculate one digit more for rounding. + let (limit_digits, digit_count, exact) = match digits { + DigAll => (false, 0u, false), + DigMax(count) => (true, count+1, false), + DigExact(count) => (true, count+1, true) + }; + + // Decide what sign to put in front + match sign { + SignNeg | SignAll if neg => { + buf.push(b'-'); + } + SignAll => { + buf.push(b'+'); + } + _ => () + } + + buf.reverse(); + + // Remember start of the fractional digits. + // Points one beyond end of buf if none get generated, + // or at the '.' otherwise. + let start_fractional_digits = buf.len(); + + // Now emit the fractional part, if any + deccum = num.fract(); + if deccum != _0 || (limit_digits && exact && digit_count > 0) { + buf.push(b'.'); + let mut dig = 0u; + + // calculate new digits while + // - there is no limit and there are digits left + // - or there is a limit, it's not reached yet and + // - it's exact + // - or it's a maximum, and there are still digits left + while (!limit_digits && deccum != _0) + || (limit_digits && dig < digit_count && ( + exact + || (!exact && deccum != _0) + ) + ) { + // Shift first fractional digit into the integer part + deccum = deccum * radix_gen; + + // Calculate the absolute value of each digit. + // See note in first loop. + let current_digit = deccum.trunc().abs(); + + buf.push(char::from_digit( + current_digit.to_int().unwrap() as uint, radix).unwrap() as u8); + + // Decrease the deccumulator one fractional digit at a time + deccum = deccum.fract(); + dig += 1u; + } + + // If digits are limited, and that limit has been reached, + // cut off the one extra digit, and depending on its value + // round the remaining ones. + if limit_digits && dig == digit_count { + let ascii2value = |chr: u8| { + (chr as char).to_digit(radix).unwrap() + }; + let value2ascii = |val: uint| { + char::from_digit(val, radix).unwrap() as u8 + }; + + let extra_digit = ascii2value(buf.pop().unwrap()); + if extra_digit >= radix / 2 { // -> need to round + let mut i: int = buf.len() as int - 1; + loop { + // If reached left end of number, have to + // insert additional digit: + if i < 0 + || buf[i as uint] == b'-' + || buf[i as uint] == b'+' { + buf.insert((i + 1) as uint, value2ascii(1)); + break; + } + + // Skip the '.' + if buf[i as uint] == b'.' { i -= 1; continue; } + + // Either increment the digit, + // or set to 0 if max and carry the 1. + let current_digit = ascii2value(buf[i as uint]); + if current_digit < (radix - 1) { + buf[i as uint] = value2ascii(current_digit+1); + break; + } else { + buf[i as uint] = value2ascii(0); + i -= 1; + } + } + } + } + } + + // if number of digits is not exact, remove all trailing '0's up to + // and including the '.' + if !exact { + let buf_max_i = buf.len() - 1; + + // index to truncate from + let mut i = buf_max_i; + + // discover trailing zeros of fractional part + while i > start_fractional_digits && buf[i] == b'0' { + i -= 1; + } + + // Only attempt to truncate digits if buf has fractional digits + if i >= start_fractional_digits { + // If buf ends with '.', cut that too. + if buf[i] == b'.' { i -= 1 } + + // only resize buf if we actually remove digits + if i < buf_max_i { + buf = buf.slice(0, i + 1).to_vec(); + } + } + } // If exact and trailing '.', just cut that + else { + let max_i = buf.len() - 1; + if buf[max_i] == b'.' { + buf = buf.slice(0, max_i).to_vec(); + } + } + + match exp_format { + ExpNone => (), + _ => { + buf.push(match exp_format { + ExpDec if exp_upper => 'E', + ExpDec if !exp_upper => 'e', + ExpBin if exp_upper => 'P', + ExpBin if !exp_upper => 'p', + _ => unreachable!() + } as u8); + + int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c)); + } + } + + (buf, false) +} + +/** + * Converts a number to its string representation. This is a wrapper for + * `to_str_bytes_common()`, for details see there. + */ +#[inline] +pub fn float_to_str_common( + num: T, radix: uint, negative_zero: bool, + sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool + ) -> (String, bool) { + let (bytes, special) = float_to_str_bytes_common(num, radix, + negative_zero, sign, digits, exp_format, exp_capital); + (String::from_utf8(bytes).unwrap(), special) +} + +// Some constants for from_str_bytes_common's input validation, +// they define minimum radix values for which the character is a valid digit. +static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; +static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; + +#[cfg(test)] +mod tests { + use string::ToString; + + #[test] + fn test_int_to_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert_eq!(i8_val.to_string(), "127".to_string()); + + i8_val += 1 as i8; + assert_eq!(i8_val.to_string(), "-128".to_string()); + + let mut i16_val: i16 = 32_767_i16; + assert_eq!(i16_val.to_string(), "32767".to_string()); + + i16_val += 1 as i16; + assert_eq!(i16_val.to_string(), "-32768".to_string()); + + let mut i32_val: i32 = 2_147_483_647_i32; + assert_eq!(i32_val.to_string(), "2147483647".to_string()); + + i32_val += 1 as i32; + assert_eq!(i32_val.to_string(), "-2147483648".to_string()); + + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert_eq!(i64_val.to_string(), "9223372036854775807".to_string()); + + i64_val += 1 as i64; + assert_eq!(i64_val.to_string(), "-9223372036854775808".to_string()); + } +} + +#[cfg(test)] +mod bench { + extern crate test; + + mod uint { + use super::test::Bencher; + use rand::{weak_rng, Rng}; + use std::fmt; + + #[inline] + fn to_string(x: uint, base: u8) { + format!("{}", fmt::radix(x, base)); + } + + #[bench] + fn to_str_bin(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 2); }) + } + + #[bench] + fn to_str_oct(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 8); }) + } + + #[bench] + fn to_str_dec(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 10); }) + } + + #[bench] + fn to_str_hex(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 16); }) + } + + #[bench] + fn to_str_base_36(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 36); }) + } + } + + mod int { + use super::test::Bencher; + use rand::{weak_rng, Rng}; + use std::fmt; + + #[inline] + fn to_string(x: int, base: u8) { + format!("{}", fmt::radix(x, base)); + } + + #[bench] + fn to_str_bin(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 2); }) + } + + #[bench] + fn to_str_oct(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 8); }) + } + + #[bench] + fn to_str_dec(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 10); }) + } + + #[bench] + fn to_str_hex(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 16); }) + } + + #[bench] + fn to_str_base_36(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { to_string(rng.gen::(), 36); }) + } + } + + mod f64 { + use super::test::Bencher; + use rand::{weak_rng, Rng}; + use f64; + + #[bench] + fn float_to_string(b: &mut Bencher) { + let mut rng = weak_rng(); + b.iter(|| { f64::to_string(rng.gen()); }) + } + } +} diff --git a/src/libst2/num/u16.rs b/src/libst2/num/u16.rs new file mode 100644 index 0000000000000..a83a66c23a526 --- /dev/null +++ b/src/libst2/num/u16.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for unsigned 16-bits integers (`u16` type) + +#![stable] +#![doc(primitive = "u16")] + +pub use core::u16::{BITS, BYTES, MIN, MAX}; + +uint_module!(u16) diff --git a/src/libst2/num/u32.rs b/src/libst2/num/u32.rs new file mode 100644 index 0000000000000..7271203b23b6c --- /dev/null +++ b/src/libst2/num/u32.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for unsigned 32-bits integers (`u32` type) + +#![stable] +#![doc(primitive = "u32")] + +pub use core::u32::{BITS, BYTES, MIN, MAX}; + +uint_module!(u32) diff --git a/src/libst2/num/u64.rs b/src/libst2/num/u64.rs new file mode 100644 index 0000000000000..25de2f3b25565 --- /dev/null +++ b/src/libst2/num/u64.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for unsigned 64-bits integer (`u64` type) + +#![stable] +#![doc(primitive = "u64")] + +pub use core::u64::{BITS, BYTES, MIN, MAX}; + +uint_module!(u64) diff --git a/src/libst2/num/u8.rs b/src/libst2/num/u8.rs new file mode 100644 index 0000000000000..22dedeecf3b10 --- /dev/null +++ b/src/libst2/num/u8.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for unsigned 8-bits integers (`u8` type) + +#![stable] +#![doc(primitive = "u8")] + +pub use core::u8::{BITS, BYTES, MIN, MAX}; + +uint_module!(u8) diff --git a/src/libst2/num/uint.rs b/src/libst2/num/uint.rs new file mode 100644 index 0000000000000..a425aab3aa10c --- /dev/null +++ b/src/libst2/num/uint.rs @@ -0,0 +1,18 @@ +// 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. + +//! Operations and constants for architecture-sized unsigned integers (`uint` type) + +#![unstable] +#![doc(primitive = "uint")] + +pub use core::uint::{BITS, BYTES, MIN, MAX}; + +uint_module!(uint) diff --git a/src/libst2/num/uint_macros.rs b/src/libst2/num/uint_macros.rs new file mode 100644 index 0000000000000..de27fef50dad3 --- /dev/null +++ b/src/libst2/num/uint_macros.rs @@ -0,0 +1,37 @@ +// 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. + +#![experimental] +#![macro_escape] +#![doc(hidden)] +#![allow(unsigned_negation)] + +macro_rules! uint_module (($T:ty) => ( + +// String conversion functions and impl num -> str + +/// Convert to a string as a byte slice in a given base. +/// +/// Use in place of x.to_string() when you do not need to store the string permanently +/// +/// # Examples +/// +/// ``` +/// #![allow(deprecated)] +/// +/// std::uint::to_str_bytes(123, 10, |v| { +/// assert!(v == "123".as_bytes()); +/// }); +/// ``` +#[inline] +#[deprecated = "just use .to_string(), or a BufWriter with write! if you mustn't allocate"] +pub fn to_str_bytes(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U { unimplemented!() } + +)) diff --git a/src/libst2/os.rs b/src/libst2/os.rs new file mode 100644 index 0000000000000..db36c8204d7b1 --- /dev/null +++ b/src/libst2/os.rs @@ -0,0 +1,894 @@ +// 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. + +/*! + * Higher-level interfaces to libc::* functions and operating system services. + * + * In general these take and return rust types, use rust idioms (enums, + * closures, vectors) rather than C idioms, and do more extensive safety + * checks. + * + * This module is not meant to only contain 1:1 mappings to libc entries; any + * os-interface code that is reasonably useful and broadly applicable can go + * here. Including utility routines that merely build on other os code. + * + * We assume the general case is that users do not care, and do not want to + * be made to care, which operating system they are on. While they may want + * to special case various special cases -- and so we will not _hide_ the + * facts of which OS the user is on -- they should be given the opportunity + * to write OS-ignorant code by default. + */ + +#![experimental] + +#![allow(missing_docs)] +#![allow(non_snake_case)] + +pub use self::MemoryMapKind::*; +pub use self::MapOption::*; +pub use self::MapError::*; + +use clone::Clone; +use error::{FromError, Error}; +use fmt; +use io::{IoResult, IoError}; +use iter::Iterator; +use libc::{c_void, c_int}; +use libc; +use boxed::Box; +use ops::Drop; +use option::{Some, None, Option}; +use os; +use path::{Path, GenericPath, BytesContainer}; +use sys; +use sys::os as os_imp; +use ptr::RawPtr; +use ptr; +use result::{Err, Ok, Result}; +use slice::{AsSlice, SlicePrelude, PartialEqSlicePrelude}; +use slice::CloneSliceAllocPrelude; +use str::{Str, StrPrelude, StrAllocating}; +use string::{String, ToString}; +use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; +use vec::Vec; + +#[cfg(unix)] use c_str::ToCStr; +#[cfg(unix)] use libc::c_char; + +/// Get the number of cores available +pub fn num_cpus() -> uint { unimplemented!() } + +pub const TMPBUF_SZ : uint = 1000u; +const BUF_BYTES : uint = 2048u; + +/// Returns the current working directory as a `Path`. +/// +/// # Errors +/// +/// Returns an `Err` if the current working directory value is invalid. +/// Possible cases: +/// +/// * Current directory does not exist. +/// * There are insufficient permissions to access the current directory. +/// * The internal buffer is not large enough to hold the path. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// // We assume that we are in a valid directory like "/home". +/// let current_working_directory = os::getcwd().unwrap(); +/// println!("The current directory is {}", current_working_directory.display()); +/// // /home +/// ``` +#[cfg(unix)] +pub fn getcwd() -> IoResult { unimplemented!() } + +/// Returns the current working directory as a `Path`. +/// +/// # Errors +/// +/// Returns an `Err` if the current working directory value is invalid. +/// Possible cases: +/// +/// * Current directory does not exist. +/// * There are insufficient permissions to access the current directory. +/// * The internal buffer is not large enough to hold the path. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// // We assume that we are in a valid directory like "C:\\Windows". +/// let current_working_directory = os::getcwd().unwrap(); +/// println!("The current directory is {}", current_working_directory.display()); +/// // C:\\Windows +/// ``` +#[cfg(windows)] +pub fn getcwd() -> IoResult { unimplemented!() } + +#[cfg(windows)] +pub mod windows { + use libc::types::os::arch::extra::DWORD; + use libc; + use option::{None, Option}; + use option; + use os::TMPBUF_SZ; + use slice::{SlicePrelude}; + use string::String; + use str::StrPrelude; + use vec::Vec; + + pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) + -> Option { unimplemented!() } +} + +/* +Accessing environment variables is not generally threadsafe. +Serialize access through a global lock. +*/ +fn with_env_lock(f: || -> T) -> T { unimplemented!() } + +/// Returns a vector of (variable, value) pairs, for all the environment +/// variables of the current process. +/// +/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()` +/// for details. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// // We will iterate through the references to the element returned by os::env(); +/// for &(ref key, ref value) in os::env().iter() { +/// println!("'{}': '{}'", key, value ); +/// } +/// ``` +pub fn env() -> Vec<(String,String)> { unimplemented!() } + +/// Returns a vector of (variable, value) byte-vector pairs for all the +/// environment variables of the current process. +pub fn env_as_bytes() -> Vec<(Vec,Vec)> { unimplemented!() } + +#[cfg(unix)] +/// Fetches the environment variable `n` from the current process, returning +/// None if the variable isn't set. +/// +/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See +/// `String::from_utf8_lossy()` for details. +/// +/// # Panics +/// +/// Panics if `n` has any interior NULs. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// let key = "HOME"; +/// match os::getenv(key) { +/// Some(val) => println!("{}: {}", key, val), +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +pub fn getenv(n: &str) -> Option { unimplemented!() } + +#[cfg(unix)] +/// Fetches the environment variable `n` byte vector from the current process, +/// returning None if the variable isn't set. +/// +/// # Panics +/// +/// Panics if `n` has any interior NULs. +pub fn getenv_as_bytes(n: &str) -> Option> { unimplemented!() } + +#[cfg(windows)] +/// Fetches the environment variable `n` from the current process, returning +/// None if the variable isn't set. +pub fn getenv(n: &str) -> Option { unimplemented!() } + +#[cfg(windows)] +/// Fetches the environment variable `n` byte vector from the current process, +/// returning None if the variable isn't set. +pub fn getenv_as_bytes(n: &str) -> Option> { unimplemented!() } + +/// Sets the environment variable `n` to the value `v` for the currently running +/// process. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// let key = "KEY"; +/// os::setenv(key, "VALUE"); +/// match os::getenv(key) { +/// Some(ref val) => println!("{}: {}", key, val), +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +pub fn setenv(n: &str, v: T) { unimplemented!() } + +/// Remove a variable from the environment entirely. +pub fn unsetenv(n: &str) { unimplemented!() } + +/// Parses input according to platform conventions for the `PATH` +/// environment variable. +/// +/// # Example +/// ```rust +/// use std::os; +/// +/// let key = "PATH"; +/// match os::getenv_as_bytes(key) { +/// Some(paths) => { +/// for path in os::split_paths(paths).iter() { +/// println!("'{}'", path.display()); +/// } +/// } +/// None => println!("{} is not defined in the environment.", key) +/// } +/// ``` +pub fn split_paths(unparsed: T) -> Vec { unimplemented!() } + +/// A low-level OS in-memory pipe. +pub struct Pipe { + /// A file descriptor representing the reading end of the pipe. Data written + /// on the `out` file descriptor can be read from this file descriptor. + pub reader: c_int, + /// A file descriptor representing the write end of the pipe. Data written + /// to this file descriptor can be read from the `input` file descriptor. + pub writer: c_int, +} + +/// Creates a new low-level OS in-memory pipe. +/// +/// This function can fail to succeed if there are no more resources available +/// to allocate a pipe. +/// +/// This function is also unsafe as there is no destructor associated with the +/// `Pipe` structure will return. If it is not arranged for the returned file +/// descriptors to be closed, the file descriptors will leak. For safe handling +/// of this scenario, use `std::io::PipeStream` instead. +pub unsafe fn pipe() -> IoResult { unimplemented!() } + +/// Returns the proper dll filename for the given basename of a file +/// as a String. +#[cfg(not(target_os="ios"))] +pub fn dll_filename(base: &str) -> String { unimplemented!() } + +/// Optionally returns the filesystem path to the current executable which is +/// running but with the executable name. +/// +/// # Examples +/// +/// ```rust +/// use std::os; +/// +/// match os::self_exe_name() { +/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()), +/// None => println!("Unable to get the path of this executable!") +/// }; +/// ``` +pub fn self_exe_name() -> Option { unimplemented!() } + +/// Optionally returns the filesystem path to the current executable which is +/// running. +/// +/// Like self_exe_name() but without the binary's name. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// match os::self_exe_path() { +/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()), +/// None => println!("Impossible to fetch the path of this executable.") +/// }; +/// ``` +pub fn self_exe_path() -> Option { unimplemented!() } + +/// Optionally returns the path to the current user's home directory if known. +/// +/// # Unix +/// +/// Returns the value of the 'HOME' environment variable if it is set +/// and not equal to the empty string. +/// +/// # Windows +/// +/// Returns the value of the 'HOME' environment variable if it is +/// set and not equal to the empty string. Otherwise, returns the value of the +/// 'USERPROFILE' environment variable if it is set and not equal to the empty +/// string. +/// +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// match os::homedir() { +/// Some(ref p) => println!("{}", p.display()), +/// None => println!("Impossible to get your home dir!") +/// } +/// ``` +pub fn homedir() -> Option { unimplemented!() } + +/** + * Returns the path to a temporary directory. + * + * On Unix, returns the value of the 'TMPDIR' environment variable if it is + * set, otherwise for non-Android it returns '/tmp'. If Android, since there + * is no global temporary folder (it is usually allocated per-app), we return + * '/data/local/tmp'. + * + * On Windows, returns the value of, in order, the 'TMP', 'TEMP', + * 'USERPROFILE' environment variable if any are set and not the empty + * string. Otherwise, tmpdir returns the path to the Windows directory. + */ +pub fn tmpdir() -> Path { unimplemented!() } + +/// +/// Convert a relative path to an absolute path +/// +/// If the given path is relative, return it prepended with the current working +/// directory. If the given path is already an absolute path, return it +/// as is. +/// +/// # Example +/// ```rust +/// use std::os; +/// use std::path::Path; +/// +/// // Assume we're in a path like /home/someuser +/// let rel_path = Path::new(".."); +/// let abs_path = os::make_absolute(&rel_path).unwrap(); +/// println!("The absolute path is {}", abs_path.display()); +/// // Prints "The absolute path is /home" +/// ``` +// NB: this is here rather than in path because it is a form of environment +// querying; what it does depends on the process working directory, not just +// the input paths. +pub fn make_absolute(p: &Path) -> IoResult { unimplemented!() } + +/// Changes the current working directory to the specified path, returning +/// whether the change was completed successfully or not. +/// +/// # Example +/// ```rust +/// use std::os; +/// use std::path::Path; +/// +/// let root = Path::new("/"); +/// assert!(os::change_dir(&root).is_ok()); +/// println!("Successfully changed working directory to {}!", root.display()); +/// ``` +pub fn change_dir(p: &Path) -> IoResult<()> { unimplemented!() } + +/// Returns the platform-specific value of errno +pub fn errno() -> uint { unimplemented!() } + +/// Return the string corresponding to an `errno()` value of `errnum`. +/// +/// # Example +/// ```rust +/// use std::os; +/// +/// // Same as println!("{}", last_os_error()); +/// println!("{}", os::error_string(os::errno() as uint)); +/// ``` +pub fn error_string(errnum: uint) -> String { unimplemented!() } + +/// Get a string representing the platform-dependent last error +pub fn last_os_error() -> String { unimplemented!() } + +static EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT; + +/** + * Sets the process exit code + * + * Sets the exit code returned by the process if all supervised tasks + * terminate successfully (without panicking). If the current root task panics + * and is supervised by the scheduler then any user-specified exit status is + * ignored and the process exits with the default panic status. + * + * Note that this is not synchronized against modifications of other threads. + */ +pub fn set_exit_status(code: int) { unimplemented!() } + +/// Fetches the process's current exit code. This defaults to 0 and can change +/// by calling `set_exit_status`. +pub fn get_exit_status() -> int { unimplemented!() } + +#[cfg(target_os = "macos")] +unsafe fn load_argc_and_argv(argc: int, + argv: *const *const c_char) -> Vec> { unimplemented!() } + +/** + * Returns the command line arguments + * + * Returns a list of the command line arguments. + */ +#[cfg(target_os = "macos")] +fn real_args_as_bytes() -> Vec> { unimplemented!() } + +// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs +// and use underscores in their names - they're most probably +// are considered private and therefore should be avoided +// Here is another way to get arguments using Objective C +// runtime +// +// In general it looks like: +// res = Vec::new() +// let args = [[NSProcessInfo processInfo] arguments] +// for i in range(0, [args count]) +// res.push([args objectAtIndex:i]) +// res +#[cfg(target_os = "ios")] +fn real_args_as_bytes() -> Vec> { unimplemented!() } + +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "dragonfly"))] +fn real_args_as_bytes() -> Vec> { unimplemented!() } + +#[cfg(not(windows))] +fn real_args() -> Vec { unimplemented!() } + +#[cfg(windows)] +fn real_args() -> Vec { unimplemented!() } + +#[cfg(windows)] +fn real_args_as_bytes() -> Vec> { unimplemented!() } + +type LPCWSTR = *const u16; + +#[cfg(windows)] +#[link_name="kernel32"] +extern "system" { + fn GetCommandLineW() -> LPCWSTR; + fn LocalFree(ptr: *mut c_void); +} + +#[cfg(windows)] +#[link_name="shell32"] +extern "system" { + fn CommandLineToArgvW(lpCmdLine: LPCWSTR, + pNumArgs: *mut c_int) -> *mut *mut u16; +} + +/// Returns the arguments which this program was started with (normally passed +/// via the command line). +/// +/// The first element is traditionally the path to the executable, but it can be +/// set to arbitrary text, and it may not even exist, so this property should not +/// be relied upon for security purposes. +/// +/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD. +/// See `String::from_utf8_lossy` for details. +/// # Example +/// +/// ```rust +/// use std::os; +/// +/// // Prints each argument on a separate line +/// for argument in os::args().iter() { +/// println!("{}", argument); +/// } +/// ``` +pub fn args() -> Vec { unimplemented!() } + +/// Returns the arguments which this program was started with (normally passed +/// via the command line) as byte vectors. +pub fn args_as_bytes() -> Vec> { unimplemented!() } + +#[cfg(target_os = "macos")] +extern { + // These functions are in crt_externs.h. + pub fn _NSGetArgc() -> *mut c_int; + pub fn _NSGetArgv() -> *mut *mut *mut c_char; +} + +// Round up `from` to be divisible by `to` +fn round_up(from: uint, to: uint) -> uint { unimplemented!() } + +/// Returns the page size of the current architecture in bytes. +#[cfg(unix)] +pub fn page_size() -> uint { unimplemented!() } + +/// Returns the page size of the current architecture in bytes. +#[cfg(windows)] +pub fn page_size() -> uint { unimplemented!() } + +/// A memory mapped file or chunk of memory. This is a very system-specific +/// interface to the OS's memory mapping facilities (`mmap` on POSIX, +/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at +/// abstracting platform differences, besides in error values returned. Consider +/// yourself warned. +/// +/// The memory map is released (unmapped) when the destructor is run, so don't +/// let it leave scope by accident if you want it to stick around. +pub struct MemoryMap { + data: *mut u8, + len: uint, + kind: MemoryMapKind, +} + +/// Type of memory map +pub enum MemoryMapKind { + /// Virtual memory map. Usually used to change the permissions of a given + /// chunk of memory. Corresponds to `VirtualAlloc` on Windows. + MapFile(*const u8), + /// Virtual memory map. Usually used to change the permissions of a given + /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on + /// Windows. + MapVirtual +} + +/// Options the memory map is created with +pub enum MapOption { + /// The memory should be readable + MapReadable, + /// The memory should be writable + MapWritable, + /// The memory should be executable + MapExecutable, + /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on + /// POSIX. + MapAddr(*const u8), + /// Create a memory mapping for a file with a given fd. + MapFd(c_int), + /// When using `MapFd`, the start of the map is `uint` bytes from the start + /// of the file. + MapOffset(uint), + /// On POSIX, this can be used to specify the default flags passed to + /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`, + /// `MAP_ANON`. This will override both of those. This is platform-specific + /// (the exact values used) and ignored on Windows. + MapNonStandardFlags(c_int), +} + +/// Possible errors when creating a map. +pub enum MapError { + /// ## The following are POSIX-specific + /// + /// fd was not open for reading or, if using `MapWritable`, was not open for + /// writing. + ErrFdNotAvail, + /// fd was not valid + ErrInvalidFd, + /// Either the address given by `MapAddr` or offset given by `MapOffset` was + /// not a multiple of `MemoryMap::granularity` (unaligned to page size). + ErrUnaligned, + /// With `MapFd`, the fd does not support mapping. + ErrNoMapSupport, + /// If using `MapAddr`, the address + `min_len` was outside of the process's + /// address space. If using `MapFd`, the target of the fd didn't have enough + /// resources to fulfill the request. + ErrNoMem, + /// A zero-length map was requested. This is invalid according to + /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html). + /// Not all platforms obey this, but this wrapper does. + ErrZeroLength, + /// Unrecognized error. The inner value is the unrecognized errno. + ErrUnknown(int), + /// ## The following are Windows-specific + /// + /// Unsupported combination of protection flags + /// (`MapReadable`/`MapWritable`/`MapExecutable`). + ErrUnsupProt, + /// When using `MapFd`, `MapOffset` was given (Windows does not support this + /// at all) + ErrUnsupOffset, + /// When using `MapFd`, there was already a mapping to the file. + ErrAlreadyExists, + /// Unrecognized error from `VirtualAlloc`. The inner value is the return + /// value of GetLastError. + ErrVirtualAlloc(uint), + /// Unrecognized error from `CreateFileMapping`. The inner value is the + /// return value of `GetLastError`. + ErrCreateFileMappingW(uint), + /// Unrecognized error from `MapViewOfFile`. The inner value is the return + /// value of `GetLastError`. + ErrMapViewOfFile(uint) +} + +impl fmt::Show for MapError { + fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl Error for MapError { + fn description(&self) -> &str { unimplemented!() } + fn detail(&self) -> Option { unimplemented!() } +} + +impl FromError for Box { + fn from_error(err: MapError) -> Box { unimplemented!() } +} + +#[cfg(unix)] +impl MemoryMap { + /// Create a new mapping with the given `options`, at least `min_len` bytes + /// long. `min_len` must be greater than zero; see the note on + /// `ErrZeroLength`. + pub fn new(min_len: uint, options: &[MapOption]) -> Result { unimplemented!() } + + /// Granularity that the offset or address must be for `MapOffset` and + /// `MapAddr` respectively. + pub fn granularity() -> uint { unimplemented!() } +} + +#[cfg(unix)] +impl Drop for MemoryMap { + /// Unmap the mapping. Panics the task if `munmap` panics. + fn drop(&mut self) { unimplemented!() } +} + +#[cfg(windows)] +impl MemoryMap { + /// Create a new mapping with the given `options`, at least `min_len` bytes long. + pub fn new(min_len: uint, options: &[MapOption]) -> Result { unimplemented!() } + + /// Granularity of MapAddr() and MapOffset() parameter values. + /// This may be greater than the value returned by page_size(). + pub fn granularity() -> uint { unimplemented!() } +} + +#[cfg(windows)] +impl Drop for MemoryMap { + /// Unmap the mapping. Panics the task if any of `VirtualFree`, + /// `UnmapViewOfFile`, or `CloseHandle` fail. + fn drop(&mut self) { unimplemented!() } +} + +impl MemoryMap { + /// Returns the pointer to the memory created or modified by this map. + pub fn data(&self) -> *mut u8 { unimplemented!() } + /// Returns the number of bytes this map applies to. + pub fn len(&self) -> uint { unimplemented!() } + /// Returns the type of mapping this represents. + pub fn kind(&self) -> MemoryMapKind { unimplemented!() } +} + +#[cfg(target_os = "linux")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `linux`. + pub const SYSNAME: &'static str = "linux"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, `lib`. + pub const DLL_PREFIX: &'static str = "lib"; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.so`. + pub const DLL_SUFFIX: &'static str = ".so"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `so`. + pub const DLL_EXTENSION: &'static str = "so"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "macos")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `macos`. + pub const SYSNAME: &'static str = "macos"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, `lib`. + pub const DLL_PREFIX: &'static str = "lib"; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.dylib`. + pub const DLL_SUFFIX: &'static str = ".dylib"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `dylib`. + pub const DLL_EXTENSION: &'static str = "dylib"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "ios")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `ios`. + pub const SYSNAME: &'static str = "ios"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "freebsd")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `freebsd`. + pub const SYSNAME: &'static str = "freebsd"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, `lib`. + pub const DLL_PREFIX: &'static str = "lib"; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.so`. + pub const DLL_SUFFIX: &'static str = ".so"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `so`. + pub const DLL_EXTENSION: &'static str = "so"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "dragonfly")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `dragonfly`. + pub const SYSNAME: &'static str = "dragonfly"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, `lib`. + pub const DLL_PREFIX: &'static str = "lib"; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.so`. + pub const DLL_SUFFIX: &'static str = ".so"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `so`. + pub const DLL_EXTENSION: &'static str = "so"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "android")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "unix"; + + /// A string describing the specific operating system in use: in this + /// case, `android`. + pub const SYSNAME: &'static str = "android"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, `lib`. + pub const DLL_PREFIX: &'static str = "lib"; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.so`. + pub const DLL_SUFFIX: &'static str = ".so"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `so`. + pub const DLL_EXTENSION: &'static str = "so"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, the empty string. + pub const EXE_SUFFIX: &'static str = ""; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, the empty string. + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "windows")] +pub mod consts { + pub use os::arch_consts::ARCH; + + pub const FAMILY: &'static str = "windows"; + + /// A string describing the specific operating system in use: in this + /// case, `windows`. + pub const SYSNAME: &'static str = "windows"; + + /// Specifies the filename prefix used for shared libraries on this + /// platform: in this case, the empty string. + pub const DLL_PREFIX: &'static str = ""; + + /// Specifies the filename suffix used for shared libraries on this + /// platform: in this case, `.dll`. + pub const DLL_SUFFIX: &'static str = ".dll"; + + /// Specifies the file extension used for shared libraries on this + /// platform that goes after the dot: in this case, `dll`. + pub const DLL_EXTENSION: &'static str = "dll"; + + /// Specifies the filename suffix used for executable binaries on this + /// platform: in this case, `.exe`. + pub const EXE_SUFFIX: &'static str = ".exe"; + + /// Specifies the file extension, if any, used for executable binaries + /// on this platform: in this case, `exe`. + pub const EXE_EXTENSION: &'static str = "exe"; +} + +#[cfg(target_arch = "x86")] +mod arch_consts { + pub const ARCH: &'static str = "x86"; +} + +#[cfg(target_arch = "x86_64")] +mod arch_consts { + pub const ARCH: &'static str = "x86_64"; +} + +#[cfg(target_arch = "arm")] +mod arch_consts { + pub const ARCH: &'static str = "arm"; +} + +#[cfg(target_arch = "mips")] +mod arch_consts { + pub const ARCH: &'static str = "mips"; +} + +#[cfg(target_arch = "mipsel")] +mod arch_consts { + pub const ARCH: &'static str = "mipsel"; +} diff --git a/src/libst2/path/mod.rs b/src/libst2/path/mod.rs new file mode 100644 index 0000000000000..6ee6d3ef79b0d --- /dev/null +++ b/src/libst2/path/mod.rs @@ -0,0 +1,780 @@ +// Copyright 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. + +/*! + +Cross-platform path support + +This module implements support for two flavors of paths. `PosixPath` represents +a path on any unix-like system, whereas `WindowsPath` represents a path on +Windows. This module also exposes a typedef `Path` which is equal to the +appropriate platform-specific path variant. + +Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which +contains the set of methods that behave the same for both paths. They each also +implement some methods that could not be expressed in `GenericPath`, yet behave +identically for both path flavors, such as `.components()`. + +The three main design goals of this module are 1) to avoid unnecessary +allocation, 2) to behave the same regardless of which flavor of path is being +used, and 3) to support paths that cannot be represented in UTF-8 (as Linux has +no restriction on paths beyond disallowing NUL). + +## Usage + +Usage of this module is fairly straightforward. Unless writing platform-specific +code, `Path` should be used to refer to the platform-native path. + +Creation of a path is typically done with either `Path::new(some_str)` or +`Path::new(some_vec)`. This path can be modified with `.push()` and +`.pop()` (and other setters). The resulting Path can either be passed to another +API that expects a path, or can be turned into a `&[u8]` with `.as_vec()` or a +`Option<&str>` with `.as_str()`. Similarly, attributes of the path can be queried +with methods such as `.filename()`. There are also methods that return a new +path instead of modifying the receiver, such as `.join()` or `.dir_path()`. + +Paths are always kept in normalized form. This means that creating the path +`Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt +to mutate the path will always leave it in normalized form. + +When rendering a path to some form of output, there is a method `.display()` +which is compatible with the `format!()` parameter `{}`. This will render the +path as a string, replacing all non-utf8 sequences with the Replacement +Character (U+FFFD). As such it is not suitable for passing to any API that +actually operates on the path; it is only intended for display. + +## Example + +```rust +use std::io::fs::PathExtensions; + +let mut path = Path::new("/tmp/path"); +println!("path: {}", path.display()); +path.set_filename("foo"); +path.push("bar"); +println!("new path: {}", path.display()); +println!("path exists: {}", path.exists()); +``` + +*/ + +#![experimental] + +use core::kinds::Sized; +use c_str::CString; +use clone::Clone; +use fmt; +use iter::Iterator; +use option::{Option, None, Some}; +use str; +use str::{MaybeOwned, Str, StrPrelude}; +use string::String; +use slice::{AsSlice, CloneSliceAllocPrelude}; +use slice::{PartialEqSlicePrelude, SlicePrelude}; +use vec::Vec; + +/// Typedef for POSIX file paths. +/// See `posix::Path` for more info. +pub use self::posix::Path as PosixPath; + +/// Typedef for Windows file paths. +/// See `windows::Path` for more info. +pub use self::windows::Path as WindowsPath; + +/// Typedef for the platform-native path type +#[cfg(unix)] +pub use self::posix::Path as Path; +/// Typedef for the platform-native path type +#[cfg(windows)] +pub use self::windows::Path as Path; + +/// Typedef for the platform-native component iterator +#[cfg(unix)] +pub use self::posix::Components as Components; +/// Typedef for the platform-native component iterator +#[cfg(windows)] +pub use self::windows::Components as Components; + +/// Typedef for the platform-native str component iterator +#[cfg(unix)] +pub use self::posix::StrComponents as StrComponents; +/// Typedef for the platform-native str component iterator +#[cfg(windows)] +pub use self::windows::StrComponents as StrComponents; + +/// Alias for the platform-native separator character. +#[cfg(unix)] +pub use self::posix::SEP as SEP; +/// Alias for the platform-native separator character. +#[cfg(windows)] +pub use self::windows::SEP as SEP; + +/// Alias for the platform-native separator byte. +#[cfg(unix)] +pub use self::posix::SEP_BYTE as SEP_BYTE; +/// Alias for the platform-native separator byte. +#[cfg(windows)] +pub use self::windows::SEP_BYTE as SEP_BYTE; + +/// Typedef for the platform-native separator char func +#[cfg(unix)] +pub use self::posix::is_sep as is_sep; +/// Typedef for the platform-native separator char func +#[cfg(windows)] +pub use self::windows::is_sep as is_sep; +/// Typedef for the platform-native separator byte func +#[cfg(unix)] +pub use self::posix::is_sep_byte as is_sep_byte; +/// Typedef for the platform-native separator byte func +#[cfg(windows)] +pub use self::windows::is_sep_byte as is_sep_byte; + +pub mod posix; +pub mod windows; + +/// A trait that represents the generic operations available on paths +pub trait GenericPath: Clone + GenericPathUnsafe { + /// Creates a new Path from a byte vector or string. + /// The resulting Path will always be normalized. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let path = Path::new("foo/bar"); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the path contains a NUL. + /// + /// See individual Path impls for additional restrictions. + #[inline] + fn new(path: T) -> Self { unimplemented!() } + + /// Creates a new Path from a byte vector or string, if possible. + /// The resulting Path will always be normalized. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let x: &[u8] = b"foo\0"; + /// assert!(Path::new_opt(x).is_none()); + /// # } + /// ``` + #[inline] + fn new_opt(path: T) -> Option { unimplemented!() } + + /// Returns the path as a string, if possible. + /// If the path is not representable in utf-8, this returns None. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("/abc/def"); + /// assert_eq!(p.as_str(), Some("/abc/def")); + /// # } + /// ``` + #[inline] + fn as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// Returns the path as a byte vector + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def"); + /// assert_eq!(p.as_vec(), b"abc/def"); + /// # } + /// ``` + fn as_vec<'a>(&'a self) -> &'a [u8]; + + /// Converts the Path into an owned byte vector + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def"); + /// assert_eq!(p.into_vec(), b"abc/def".to_vec()); + /// // attempting to use p now results in "error: use of moved value" + /// # } + /// ``` + fn into_vec(self) -> Vec; + + /// Returns an object that implements `Show` for printing paths + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def"); + /// println!("{}", p.display()); // prints "abc/def" + /// # } + /// ``` + fn display<'a>(&'a self) -> Display<'a, Self> { unimplemented!() } + + /// Returns an object that implements `Show` for printing filenames + /// + /// If there is no filename, nothing will be printed. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def"); + /// println!("{}", p.filename_display()); // prints "def" + /// # } + /// ``` + fn filename_display<'a>(&'a self) -> Display<'a, Self> { unimplemented!() } + + /// Returns the directory component of `self`, as a byte vector (with no trailing separator). + /// If `self` has no directory component, returns ['.']. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def/ghi"); + /// assert_eq!(p.dirname(), b"abc/def"); + /// # } + /// ``` + fn dirname<'a>(&'a self) -> &'a [u8]; + + /// Returns the directory component of `self`, as a string, if possible. + /// See `dirname` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def/ghi"); + /// assert_eq!(p.dirname_str(), Some("abc/def")); + /// # } + /// ``` + #[inline] + fn dirname_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// Returns the file component of `self`, as a byte vector. + /// If `self` represents the root of the file hierarchy, returns None. + /// If `self` is "." or "..", returns None. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def/ghi"); + /// assert_eq!(p.filename(), Some(b"ghi")); + /// # } + /// ``` + fn filename<'a>(&'a self) -> Option<&'a [u8]>; + + /// Returns the file component of `self`, as a string, if possible. + /// See `filename` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def/ghi"); + /// assert_eq!(p.filename_str(), Some("ghi")); + /// # } + /// ``` + #[inline] + fn filename_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// Returns the stem of the filename of `self`, as a byte vector. + /// The stem is the portion of the filename just before the last '.'. + /// If there is no '.', the entire filename is returned. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("/abc/def.txt"); + /// assert_eq!(p.filestem(), Some(b"def")); + /// # } + /// ``` + fn filestem<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } + + /// Returns the stem of the filename of `self`, as a string, if possible. + /// See `filestem` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("/abc/def.txt"); + /// assert_eq!(p.filestem_str(), Some("def")); + /// # } + /// ``` + #[inline] + fn filestem_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// Returns the extension of the filename of `self`, as an optional byte vector. + /// The extension is the portion of the filename just after the last '.'. + /// If there is no extension, None is returned. + /// If the filename ends in '.', the empty vector is returned. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def.txt"); + /// assert_eq!(p.extension(), Some(b"txt")); + /// # } + /// ``` + fn extension<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } + + /// Returns the extension of the filename of `self`, as a string, if possible. + /// See `extension` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def.txt"); + /// assert_eq!(p.extension_str(), Some("txt")); + /// # } + /// ``` + #[inline] + fn extension_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// Replaces the filename portion of the path with the given byte vector or string. + /// If the replacement name is [], this is equivalent to popping the path. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("abc/def.txt"); + /// p.set_filename("foo.dat"); + /// assert!(p == Path::new("abc/foo.dat")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the filename contains a NUL. + #[inline] + fn set_filename(&mut self, filename: T) { unimplemented!() } + + /// Replaces the extension with the given byte vector or string. + /// If there is no extension in `self`, this adds one. + /// If the argument is [] or "", this removes the extension. + /// If `self` has no filename, this is a no-op. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("abc/def.txt"); + /// p.set_extension("csv"); + /// assert!(p == Path::new("abc/def.csv")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the extension contains a NUL. + fn set_extension(&mut self, extension: T) { unimplemented!() } + + /// Returns a new Path constructed by replacing the filename with the given + /// byte vector or string. + /// See `set_filename` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("abc/def.txt"); + /// assert!(p.with_filename("foo.dat") == Path::new("abc/foo.dat")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the filename contains a NUL. + #[inline] + fn with_filename(&self, filename: T) -> Self { unimplemented!() } + + /// Returns a new Path constructed by setting the extension to the given + /// byte vector or string. + /// See `set_extension` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("abc/def.txt"); + /// assert!(p.with_extension("csv") == Path::new("abc/def.csv")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the extension contains a NUL. + #[inline] + fn with_extension(&self, extension: T) -> Self { unimplemented!() } + + /// Returns the directory component of `self`, as a Path. + /// If `self` represents the root of the filesystem hierarchy, returns `self`. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def/ghi"); + /// assert!(p.dir_path() == Path::new("abc/def")); + /// # } + /// ``` + fn dir_path(&self) -> Self { unimplemented!() } + + /// Returns a Path that represents the filesystem root that `self` is rooted in. + /// + /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// assert!(Path::new("abc/def").root_path() == None); + /// assert!(Path::new("/abc/def").root_path() == Some(Path::new("/"))); + /// # } + /// ``` + fn root_path(&self) -> Option; + + /// Pushes a path (as a byte vector or string) onto `self`. + /// If the argument represents an absolute path, it replaces `self`. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("foo/bar"); + /// p.push("baz.txt"); + /// assert!(p == Path::new("foo/bar/baz.txt")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the path contains a NUL. + #[inline] + fn push(&mut self, path: T) { unimplemented!() } + + /// Pushes multiple paths (as byte vectors or strings) onto `self`. + /// See `push` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("foo"); + /// p.push_many(&["bar", "baz.txt"]); + /// assert!(p == Path::new("foo/bar/baz.txt")); + /// # } + /// ``` + #[inline] + fn push_many(&mut self, paths: &[T]) { unimplemented!() } + + /// Removes the last path component from the receiver. + /// Returns `true` if the receiver was modified, or `false` if it already + /// represented the root of the file hierarchy. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let mut p = Path::new("foo/bar/baz.txt"); + /// p.pop(); + /// assert!(p == Path::new("foo/bar")); + /// # } + /// ``` + fn pop(&mut self) -> bool; + + /// Returns a new Path constructed by joining `self` with the given path + /// (as a byte vector or string). + /// If the given path is absolute, the new Path will represent just that. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("/foo"); + /// assert!(p.join("bar.txt") == Path::new("/foo/bar.txt")); + /// # } + /// ``` + /// + /// # Panics + /// + /// Panics the task if the path contains a NUL. + #[inline] + fn join(&self, path: T) -> Self { unimplemented!() } + + /// Returns a new Path constructed by joining `self` with the given paths + /// (as byte vectors or strings). + /// See `join` for details. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("foo"); + /// let fbbq = Path::new("foo/bar/baz/quux.txt"); + /// assert!(p.join_many(&["bar", "baz", "quux.txt"]) == fbbq); + /// # } + /// ``` + #[inline] + fn join_many(&self, paths: &[T]) -> Self { unimplemented!() } + + /// Returns whether `self` represents an absolute path. + /// An absolute path is defined as one that, when joined to another path, will + /// yield back the same absolute path. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("/abc/def"); + /// assert!(p.is_absolute()); + /// # } + /// ``` + fn is_absolute(&self) -> bool; + + /// Returns whether `self` represents a relative path. + /// Typically this is the inverse of `is_absolute`. + /// But for Windows paths, it also means the path is not volume-relative or + /// relative to the current working directory. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("abc/def"); + /// assert!(p.is_relative()); + /// # } + /// ``` + fn is_relative(&self) -> bool { unimplemented!() } + + /// Returns whether `self` is equal to, or is an ancestor of, the given path. + /// If both paths are relative, they are compared as though they are relative + /// to the same parent path. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("foo/bar/baz/quux.txt"); + /// let fb = Path::new("foo/bar"); + /// let bq = Path::new("baz/quux.txt"); + /// assert!(fb.is_ancestor_of(&p)); + /// # } + /// ``` + fn is_ancestor_of(&self, other: &Self) -> bool; + + /// Returns the Path that, were it joined to `base`, would yield `self`. + /// If no such path exists, None is returned. + /// If `self` is absolute and `base` is relative, or on Windows if both + /// paths refer to separate drives, an absolute path is returned. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("foo/bar/baz/quux.txt"); + /// let fb = Path::new("foo/bar"); + /// let bq = Path::new("baz/quux.txt"); + /// assert!(p.path_relative_from(&fb) == Some(bq)); + /// # } + /// ``` + fn path_relative_from(&self, base: &Self) -> Option; + + /// Returns whether the relative path `child` is a suffix of `self`. + /// + /// # Example + /// + /// ``` + /// # foo(); + /// # #[cfg(windows)] fn foo() {} + /// # #[cfg(unix)] fn foo() { + /// let p = Path::new("foo/bar/baz/quux.txt"); + /// let bq = Path::new("baz/quux.txt"); + /// assert!(p.ends_with_path(&bq)); + /// # } + /// ``` + fn ends_with_path(&self, child: &Self) -> bool; +} + +/// A trait that represents something bytes-like (e.g. a &[u8] or a &str) +pub trait BytesContainer for Sized? { + /// Returns a &[u8] representing the receiver + fn container_as_bytes<'a>(&'a self) -> &'a [u8]; + /// Returns the receiver interpreted as a utf-8 string, if possible + #[inline] + fn container_as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + /// Returns whether .container_as_str() is guaranteed to not fail + // FIXME (#8888): Remove unused arg once :: works + #[inline] + fn is_str(_: Option<&Self>) -> bool { unimplemented!() } +} + +/// A trait that represents the unsafe operations on GenericPaths +pub trait GenericPathUnsafe { + /// Creates a new Path without checking for null bytes. + /// The resulting Path will always be normalized. + unsafe fn new_unchecked(path: T) -> Self; + + /// Replaces the filename portion of the path without checking for null + /// bytes. + /// See `set_filename` for details. + unsafe fn set_filename_unchecked(&mut self, filename: T); + + /// Pushes a path onto `self` without checking for null bytes. + /// See `push` for details. + unsafe fn push_unchecked(&mut self, path: T); +} + +/// Helper struct for printing paths with format!() +pub struct Display<'a, P:'a> { + path: &'a P, + filename: bool +} + +impl<'a, P: GenericPath> fmt::Show for Display<'a, P> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } +} + +impl<'a, P: GenericPath> Display<'a, P> { + /// Returns the path as a possibly-owned string. + /// + /// If the path is not UTF-8, invalid sequences will be replaced with the + /// Unicode replacement char. This involves allocation. + #[inline] + pub fn as_maybe_owned(&self) -> MaybeOwned<'a> { unimplemented!() } +} + +impl BytesContainer for str { + #[inline] + fn container_as_bytes(&self) -> &[u8] { unimplemented!() } + #[inline] + fn container_as_str(&self) -> Option<&str> { unimplemented!() } + #[inline] + fn is_str(_: Option<&str>) -> bool { unimplemented!() } +} + +impl BytesContainer for String { + #[inline] + fn container_as_bytes(&self) -> &[u8] { unimplemented!() } + #[inline] + fn container_as_str(&self) -> Option<&str> { unimplemented!() } + #[inline] + fn is_str(_: Option<&String>) -> bool { unimplemented!() } +} + +impl BytesContainer for [u8] { + #[inline] + fn container_as_bytes(&self) -> &[u8] { unimplemented!() } +} + +impl BytesContainer for Vec { + #[inline] + fn container_as_bytes(&self) -> &[u8] { unimplemented!() } +} + +impl BytesContainer for CString { + #[inline] + fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } +} + +impl<'a> BytesContainer for str::MaybeOwned<'a> { + #[inline] + fn container_as_bytes<'b>(&'b self) -> &'b [u8] { unimplemented!() } + #[inline] + fn container_as_str<'b>(&'b self) -> Option<&'b str> { unimplemented!() } + #[inline] + fn is_str(_: Option<&str::MaybeOwned>) -> bool { unimplemented!() } +} + +impl<'a, Sized? T: BytesContainer> BytesContainer for &'a T { + #[inline] + fn container_as_bytes(&self) -> &[u8] { unimplemented!() } + #[inline] + fn container_as_str(&self) -> Option<&str> { unimplemented!() } + #[inline] + fn is_str(_: Option<& &'a T>) -> bool { unimplemented!() } +} + +#[inline(always)] +fn contains_nul(v: &T) -> bool { unimplemented!() } diff --git a/src/libst2/path/posix.rs b/src/libst2/path/posix.rs new file mode 100644 index 0000000000000..d364b196027e9 --- /dev/null +++ b/src/libst2/path/posix.rs @@ -0,0 +1,167 @@ +// Copyright 2013-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. + +//! POSIX file path handling + +use c_str::{CString, ToCStr}; +use clone::Clone; +use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use hash; +use io::Writer; +use iter::{DoubleEndedIterator, AdditiveIterator, Extend, Iterator, Map}; +use kinds::Sized; +use option::{Option, None, Some}; +use str::{FromStr, Str}; +use str; +use slice::{CloneSliceAllocPrelude, Splits, AsSlice, VectorVector, + PartialEqSlicePrelude, SlicePrelude}; +use vec::Vec; + +use super::{BytesContainer, GenericPath, GenericPathUnsafe}; + +/// Iterator that yields successive components of a Path as &[u8] +pub type Components<'a> = Splits<'a, u8>; + +/// Iterator that yields successive components of a Path as Option<&str> +pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>, + Components<'a>>; + +/// Represents a POSIX file path +#[deriving(Clone)] +pub struct Path { + repr: Vec, // assumed to never be empty or contain NULs + sepidx: Option // index of the final separator in repr +} + +/// The standard path separator character +pub const SEP: char = '/'; + +/// The standard path separator byte +pub const SEP_BYTE: u8 = SEP as u8; + +/// Returns whether the given byte is a path separator +#[inline] +pub fn is_sep_byte(u: &u8) -> bool { unimplemented!() } + +/// Returns whether the given char is a path separator +#[inline] +pub fn is_sep(c: char) -> bool { unimplemented!() } + +impl PartialEq for Path { + #[inline] + fn eq(&self, other: &Path) -> bool { unimplemented!() } +} + +impl Eq for Path {} + +impl PartialOrd for Path { + fn partial_cmp(&self, other: &Path) -> Option { unimplemented!() } +} + +impl Ord for Path { + fn cmp(&self, other: &Path) -> Ordering { unimplemented!() } +} + +impl FromStr for Path { + fn from_str(s: &str) -> Option { unimplemented!() } +} + +// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so +// we cannot usefully take ToCStr arguments by reference (without forcing an +// additional & around &str). So we are instead temporarily adding an instance +// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by ToCStr should be passed by +// reference. + +impl ToCStr for Path { + #[inline] + fn to_c_str(&self) -> CString { unimplemented!() } + + #[inline] + unsafe fn to_c_str_unchecked(&self) -> CString { unimplemented!() } +} + +impl hash::Hash for Path { + #[inline] + fn hash(&self, state: &mut S) { unimplemented!() } +} + +impl BytesContainer for Path { + #[inline] + fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } +} + +impl GenericPathUnsafe for Path { + unsafe fn new_unchecked(path: T) -> Path { unimplemented!() } + + unsafe fn set_filename_unchecked(&mut self, filename: T) { unimplemented!() } + + unsafe fn push_unchecked(&mut self, path: T) { unimplemented!() } +} + +impl GenericPath for Path { + #[inline] + fn as_vec<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + fn into_vec(self) -> Vec { unimplemented!() } + + fn dirname<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + fn filename<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } + + fn pop(&mut self) -> bool { unimplemented!() } + + fn root_path(&self) -> Option { unimplemented!() } + + #[inline] + fn is_absolute(&self) -> bool { unimplemented!() } + + fn is_ancestor_of(&self, other: &Path) -> bool { unimplemented!() } + + fn path_relative_from(&self, base: &Path) -> Option { unimplemented!() } + + fn ends_with_path(&self, child: &Path) -> bool { unimplemented!() } +} + +impl Path { + /// Returns a new Path from a byte vector or string + /// + /// # Panics + /// + /// Panics the task if the vector contains a NUL. + #[inline] + pub fn new(path: T) -> Path { unimplemented!() } + + /// Returns a new Path from a byte vector or string, if possible + #[inline] + pub fn new_opt(path: T) -> Option { unimplemented!() } + + /// Returns a normalized byte vector representation of a path, by removing all empty + /// components, and unnecessary . and .. components. + fn normalize>(v: &V) -> Vec { unimplemented!() } + + /// Returns an iterator that yields each component of the path in turn. + /// Does not distinguish between absolute and relative paths, e.g. + /// /a/b/c and a/b/c yield the same set of components. + /// A path of "/" yields no components. A path of "." yields one component. + pub fn components<'a>(&'a self) -> Components<'a> { unimplemented!() } + + /// Returns an iterator that yields each component of the path as Option<&str>. + /// See components() for details. + pub fn str_components<'a>(&'a self) -> StrComponents<'a> { unimplemented!() } +} + +// None result means the byte vector didn't need normalizing +fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { unimplemented!() } + +#[allow(non_upper_case_globals)] +static dot_static: &'static [u8] = b"."; +#[allow(non_upper_case_globals)] +static dot_dot_static: &'static [u8] = b".."; diff --git a/src/libst2/path/windows.rs b/src/libst2/path/windows.rs new file mode 100644 index 0000000000000..1bd3b9a0b207e --- /dev/null +++ b/src/libst2/path/windows.rs @@ -0,0 +1,383 @@ +// Copyright 2013-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. +// +// ignore-lexer-test FIXME #15883 + +//! Windows file path handling + +pub use self::PathPrefix::*; + +use ascii::AsciiCast; +use c_str::{CString, ToCStr}; +use clone::Clone; +use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; +use hash; +use io::Writer; +use iter::{AdditiveIterator, DoubleEndedIterator, Extend, Iterator, Map}; +use mem; +use option::{Option, Some, None}; +use slice::{AsSlice, SlicePrelude}; +use str::{CharSplits, FromStr, Str, StrAllocating, StrVector, StrPrelude}; +use string::String; +use unicode::char::UnicodeChar; +use vec::Vec; + +use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; + +/// Iterator that yields successive components of a Path as &str +/// +/// Each component is yielded as Option<&str> for compatibility with PosixPath, but +/// every component in WindowsPath is guaranteed to be Some. +pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>, + CharSplits<'a, char>>; + +/// Iterator that yields successive components of a Path as &[u8] +pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8], + StrComponents<'a>>; + +/// Represents a Windows path +// Notes for Windows path impl: +// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs +// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information +// about windows paths. +// That same page puts a bunch of restrictions on allowed characters in a path. +// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here +// as `∃P | P.join("\foo.txt") != "\foo.txt"`. +// `C:` is interesting, that means "the current directory on drive C". +// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be +// ignored for now, though, and only added in a hypothetical .to_pwstr() function. +// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the +// processing of "." and ".." components and / as a separator. +// Experimentally, \\?\foo is not the same thing as \foo. +// Also, \\foo is not valid either (certainly not equivalent to \foo). +// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent +// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be +// best to just ignore that and normalize it to C:\foo\bar. +// +// Based on all this, I think the right approach is to do the following: +// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible +// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure). +// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly. +// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing +// server\share. +// * If \\?\, parse disk from following component, if present. Don't error for missing disk. +// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled +// here, they probably aren't, but I'm not going to worry about that. +// * Else if starts with \\, treat following two components as server\share. Don't error for missing +// server\share. +// * Otherwise, attempt to parse drive from start of path. +// +// The only error condition imposed here is valid utf-8. All other invalid paths are simply +// preserved by the data structure; let the Windows API error out on them. +#[deriving(Clone)] +pub struct Path { + repr: String, // assumed to never be empty + prefix: Option, + sepidx: Option // index of the final separator in the non-prefix portion of repr +} + +impl PartialEq for Path { + #[inline] + fn eq(&self, other: &Path) -> bool { unimplemented!() } +} + +impl Eq for Path {} + +impl PartialOrd for Path { + fn partial_cmp(&self, other: &Path) -> Option { unimplemented!() } +} + +impl Ord for Path { + fn cmp(&self, other: &Path) -> Ordering { unimplemented!() } +} + +impl FromStr for Path { + fn from_str(s: &str) -> Option { unimplemented!() } +} + +// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so +// we cannot usefully take ToCStr arguments by reference (without forcing an +// additional & around &str). So we are instead temporarily adding an instance +// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path +// instance should be removed, and arguments bound by ToCStr should be passed by +// reference. + +impl ToCStr for Path { + #[inline] + fn to_c_str(&self) -> CString { unimplemented!() } + + #[inline] + unsafe fn to_c_str_unchecked(&self) -> CString { unimplemented!() } +} + +impl hash::Hash for Path { + #[cfg(not(test))] + #[inline] + fn hash(&self, state: &mut S) { unimplemented!() } + + #[cfg(test)] + #[inline] + fn hash(&self, _: &mut S) { unimplemented!() } +} + +impl BytesContainer for Path { + #[inline] + fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } + #[inline] + fn container_as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + #[inline] + fn is_str(_: Option<&Path>) -> bool { unimplemented!() } +} + +impl GenericPathUnsafe for Path { + /// See `GenericPathUnsafe::from_vec_unchecked`. + /// + /// # Panics + /// + /// Panics if not valid UTF-8. + #[inline] + unsafe fn new_unchecked(path: T) -> Path { unimplemented!() } + + /// See `GenericPathUnsafe::set_filename_unchecked`. + /// + /// # Panics + /// + /// Panics if not valid UTF-8. + unsafe fn set_filename_unchecked(&mut self, filename: T) { unimplemented!() } + + /// See `GenericPathUnsafe::push_unchecked`. + /// + /// Concatenating two Windows Paths is rather complicated. + /// For the most part, it will behave as expected, except in the case of + /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no + /// concept of per-volume cwds like Windows does, we can't behave exactly + /// like Windows will. Instead, if the receiver is an absolute path on + /// the same volume as the new path, it will be treated as the cwd that + /// the new path is relative to. Otherwise, the new path will be treated + /// as if it were absolute and will replace the receiver outright. + unsafe fn push_unchecked(&mut self, path: T) { unimplemented!() } +} + +impl GenericPath for Path { + #[inline] + fn new_opt(path: T) -> Option { unimplemented!() } + + /// See `GenericPath::as_str` for info. + /// Always returns a `Some` value. + #[inline] + fn as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + #[inline] + fn as_vec<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + #[inline] + fn into_vec(self) -> Vec { unimplemented!() } + + #[inline] + fn dirname<'a>(&'a self) -> &'a [u8] { unimplemented!() } + + /// See `GenericPath::dirname_str` for info. + /// Always returns a `Some` value. + fn dirname_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + #[inline] + fn filename<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } + + /// See `GenericPath::filename_str` for info. + /// Always returns a `Some` value if `filename` returns a `Some` value. + fn filename_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + /// See `GenericPath::filestem_str` for info. + /// Always returns a `Some` value if `filestem` returns a `Some` value. + #[inline] + fn filestem_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + #[inline] + fn extension_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } + + fn dir_path(&self) -> Path { unimplemented!() } + + #[inline] + fn pop(&mut self) -> bool { unimplemented!() } + + fn root_path(&self) -> Option { unimplemented!() } + + /// See `GenericPath::is_absolute` for info. + /// + /// A Windows Path is considered absolute only if it has a non-volume prefix, + /// or if it has a volume prefix and the path starts with '\'. + /// A path of `\foo` is not considered absolute because it's actually + /// relative to the "current volume". A separate method `Path::is_vol_relative` + /// is provided to indicate this case. Similarly a path of `C:foo` is not + /// considered absolute because it's relative to the cwd on volume C:. A + /// separate method `Path::is_cwd_relative` is provided to indicate this case. + #[inline] + fn is_absolute(&self) -> bool { unimplemented!() } + + #[inline] + fn is_relative(&self) -> bool { unimplemented!() } + + fn is_ancestor_of(&self, other: &Path) -> bool { unimplemented!() } + + fn path_relative_from(&self, base: &Path) -> Option { unimplemented!() } + + fn ends_with_path(&self, child: &Path) -> bool { unimplemented!() } +} + +impl Path { + /// Returns a new `Path` from a `BytesContainer`. + /// + /// # Panics + /// + /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8. + /// + /// # Example + /// + /// ``` + /// println!("{}", Path::new(r"C:\some\path").display()); + /// ``` + #[inline] + pub fn new(path: T) -> Path { unimplemented!() } + + /// Returns a new `Some(Path)` from a `BytesContainer`. + /// + /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8. + /// + /// # Example + /// + /// ``` + /// let path = Path::new_opt(r"C:\some\path"); + /// + /// match path { + /// Some(path) => println!("{}", path.display()), + /// None => println!("There was a problem with your path."), + /// } + /// ``` + #[inline] + pub fn new_opt(path: T) -> Option { unimplemented!() } + + /// Returns an iterator that yields each component of the path in turn as a Option<&str>. + /// Every component is guaranteed to be Some. + /// Does not yield the path prefix (including server/share components in UNC paths). + /// Does not distinguish between volume-relative and relative paths, e.g. + /// \a\b\c and a\b\c. + /// Does not distinguish between absolute and cwd-relative paths, e.g. + /// C:\foo and C:foo. + pub fn str_components<'a>(&'a self) -> StrComponents<'a> { unimplemented!() } + + /// Returns an iterator that yields each component of the path in turn as a &[u8]. + /// See str_components() for details. + pub fn components<'a>(&'a self) -> Components<'a> { unimplemented!() } + + fn equiv_prefix(&self, other: &Path) -> bool { unimplemented!() } + + fn normalize_(s: S) -> (Option, String) { unimplemented!() } + + fn normalize__(s: &str, prefix: Option) -> Option { unimplemented!() } + + fn update_sepidx(&mut self) { unimplemented!() } + + fn prefix_len(&self) -> uint { unimplemented!() } + + // Returns a tuple (before, after, end) where before is the index of the separator + // and after is the index just after the separator. + // end is the length of the string, normally, or the index of the final character if it is + // a non-semantic trailing separator in a verbatim string. + // If the prefix is considered the separator, before and after are the same. + fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> { unimplemented!() } + + fn has_nonsemantic_trailing_slash(&self) -> bool { unimplemented!() } + + fn update_normalized(&mut self, s: S) { unimplemented!() } +} + +/// Returns whether the path is considered "volume-relative", which means a path +/// that looks like "\foo". Paths of this form are relative to the current volume, +/// but absolute within that volume. +#[inline] +pub fn is_vol_relative(path: &Path) -> bool { unimplemented!() } + +/// Returns whether the path is considered "cwd-relative", which means a path +/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths +/// of this form are relative to the cwd on the given volume. +#[inline] +pub fn is_cwd_relative(path: &Path) -> bool { unimplemented!() } + +/// Returns the PathPrefix for this Path +#[inline] +pub fn prefix(path: &Path) -> Option { unimplemented!() } + +/// Returns whether the Path's prefix is a verbatim prefix, i.e. `\\?\` +#[inline] +pub fn is_verbatim(path: &Path) -> bool { unimplemented!() } + +/// Returns the non-verbatim equivalent of the input path, if possible. +/// If the input path is a device namespace path, None is returned. +/// If the input path is not verbatim, it is returned as-is. +/// If the input path is verbatim, but the same path can be expressed as +/// non-verbatim, the non-verbatim version is returned. +/// Otherwise, None is returned. +pub fn make_non_verbatim(path: &Path) -> Option { unimplemented!() } + +/// The standard path separator character +pub const SEP: char = '\\'; +/// The standard path separator byte +pub const SEP_BYTE: u8 = SEP as u8; + +/// The alternative path separator character +pub const SEP2: char = '/'; +/// The alternative path separator character +pub const SEP2_BYTE: u8 = SEP2 as u8; + +/// Returns whether the given char is a path separator. +/// Allows both the primary separator '\' and the alternative separator '/'. +#[inline] +pub fn is_sep(c: char) -> bool { unimplemented!() } + +/// Returns whether the given char is a path separator. +/// Only allows the primary separator '\'; use is_sep to allow '/'. +#[inline] +pub fn is_sep_verbatim(c: char) -> bool { unimplemented!() } + +/// Returns whether the given byte is a path separator. +/// Allows both the primary separator '\' and the alternative separator '/'. +#[inline] +pub fn is_sep_byte(u: &u8) -> bool { unimplemented!() } + +/// Returns whether the given byte is a path separator. +/// Only allows the primary separator '\'; use is_sep_byte to allow '/'. +#[inline] +pub fn is_sep_byte_verbatim(u: &u8) -> bool { unimplemented!() } + +/// Prefix types for Path +#[deriving(PartialEq, Clone, Show)] +pub enum PathPrefix { + /// Prefix `\\?\`, uint is the length of the following component + VerbatimPrefix(uint), + /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components + VerbatimUNCPrefix(uint, uint), + /// Prefix `\\?\C:\` (for any alphabetic character) + VerbatimDiskPrefix, + /// Prefix `\\.\`, uint is the length of the following component + DeviceNSPrefix(uint), + /// UNC prefix `\\server\share`, uints are the lengths of the server/share + UNCPrefix(uint, uint), + /// Prefix `C:` for any alphabetic character + DiskPrefix +} + +fn parse_prefix<'a>(mut path: &'a str) -> Option { unimplemented!() } + +// None result means the string didn't need normalizing +fn normalize_helper<'a>(s: &'a str, prefix: Option) -> (bool, Option>) { unimplemented!() } + +fn prefix_is_verbatim(p: Option) -> bool { unimplemented!() } + +fn prefix_len(p: Option) -> uint { unimplemented!() } diff --git a/src/libst2/prelude.rs b/src/libst2/prelude.rs new file mode 100644 index 0000000000000..65f45c3f97e14 --- /dev/null +++ b/src/libst2/prelude.rs @@ -0,0 +1,94 @@ +// Copyright 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. + +//! The Rust prelude +//! +//! Because `std` is required by most serious Rust software, it is +//! imported at the topmost level of every crate by default, as if the +//! first line of each crate was +//! +//! ```ignore +//! extern crate std; +//! ``` +//! +//! This means that the contents of std can be accessed from any context +//! with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, +//! etc. +//! +//! Additionally, `std` contains a `prelude` module that reexports many of the +//! most common traits, types and functions. The contents of the prelude are +//! imported into every *module* by default. Implicitly, all modules behave as if +//! they contained the following prologue: +//! +//! ```ignore +//! use std::prelude::*; +//! ``` +//! +//! The prelude is primarily concerned with exporting *traits* that are so +//! pervasive that it would be obnoxious to import for every use, particularly +//! those that define methods on primitive types. It does include a few +//! particularly useful standalone functions, like `from_str`, `range`, and +//! `drop`, `spawn`, and `channel`. + +#![experimental] + +// Reexported core operators +#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Sync}; +#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; +#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor}; +#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut}; +#[doc(no_inline)] pub use ops::{Shl, Shr}; +#[doc(no_inline)] pub use ops::{Index, IndexMut}; +#[doc(no_inline)] pub use ops::{Slice, SliceMut}; +#[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce}; + +// Reexported functions +#[doc(no_inline)] pub use iter::{range, repeat}; +#[doc(no_inline)] pub use mem::drop; +#[doc(no_inline)] pub use str::from_str; + +// Reexported types and traits + +#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; +#[doc(no_inline)] pub use ascii::IntoBytes; +#[doc(no_inline)] pub use c_str::ToCStr; +#[doc(no_inline)] pub use char::{Char, UnicodeChar}; +#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; +#[doc(no_inline)] pub use cmp::{Ordering, Equiv}; +#[doc(no_inline)] pub use cmp::Ordering::{Less, Equal, Greater}; +#[doc(no_inline)] pub use iter::{FromIterator, Extend, ExactSize}; +#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator}; +#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator}; +#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; +#[doc(no_inline)] pub use num::{ToPrimitive, FromPrimitive}; +#[doc(no_inline)] pub use boxed::Box; +#[doc(no_inline)] pub use option::Option; +#[doc(no_inline)] pub use option::Option::{Some, None}; +#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; +#[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr}; +#[doc(no_inline)] pub use result::Result; +#[doc(no_inline)] pub use result::Result::{Ok, Err}; +#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek, BufferPrelude}; +#[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude}; +#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrPrelude}; +#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; +#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; +#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; +#[doc(no_inline)] pub use slice::{SlicePrelude, AsSlice, CloneSlicePrelude}; +#[doc(no_inline)] pub use slice::{VectorVector, PartialEqSlicePrelude, OrdSlicePrelude}; +#[doc(no_inline)] pub use slice::{CloneSliceAllocPrelude, OrdSliceAllocPrelude, SliceAllocPrelude}; +#[doc(no_inline)] pub use string::{IntoString, String, ToString}; +#[doc(no_inline)] pub use vec::Vec; + +// Reexported runtime types +#[doc(no_inline)] pub use comm::{sync_channel, channel}; +#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver}; +#[doc(no_inline)] pub use task::spawn; diff --git a/src/libst2/rand/mod.rs b/src/libst2/rand/mod.rs new file mode 100644 index 0000000000000..b1e5c7aad0819 --- /dev/null +++ b/src/libst2/rand/mod.rs @@ -0,0 +1,362 @@ +// Copyright 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. + +//! Utilities for random number generation +//! +//! The key functions are `random()` and `Rng::gen()`. These are polymorphic +//! and so can be used to generate any type that implements `Rand`. Type inference +//! means that often a simple call to `rand::random()` or `rng.gen()` will +//! suffice, but sometimes an annotation is required, e.g. `rand::random::()`. +//! +//! See the `distributions` submodule for sampling random numbers from +//! distributions like normal and exponential. +//! +//! # Task-local RNG +//! +//! There is built-in support for a RNG associated with each task stored +//! in task-local storage. This RNG can be accessed via `task_rng`, or +//! used implicitly via `random`. This RNG is normally randomly seeded +//! from an operating-system source of randomness, e.g. `/dev/urandom` on +//! Unix systems, and will automatically reseed itself from this source +//! after generating 32 KiB of random data. +//! +//! # Cryptographic security +//! +//! An application that requires an entropy source for cryptographic purposes +//! must use `OsRng`, which reads randomness from the source that the operating +//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). +//! The other random number generators provided by this module are not suitable +//! for such purposes. +//! +//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. +//! This module uses `/dev/urandom` for the following reasons: +//! +//! - On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. +//! This does not mean that `/dev/random` provides better output than +//! `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom +//! number generator (CSPRNG) based on entropy pool for random number generation, +//! so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. +//! However, this means that `/dev/urandom` can yield somewhat predictable randomness +//! if the entropy pool is very small, such as immediately after first booting. +//! Linux 3,17 added `getrandom(2)` system call which solves the issue: it blocks if entropy +//! pool is not initialized yet, but it does not block once initialized. +//! `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not. +//! If an application does not have `getrandom` and likely to be run soon after first booting, +//! or on a system with very few entropy sources, one should consider using `/dev/random` via +//! `ReaderRng`. +//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference +//! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` +//! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) +//! +//! # Examples +//! +//! ```rust +//! use std::rand; +//! use std::rand::Rng; +//! +//! let mut rng = rand::task_rng(); +//! if rng.gen() { // random bool +//! println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) +//! } +//! ``` +//! +//! ```rust +//! use std::rand; +//! +//! let tuple = rand::random::<(f64, char)>(); +//! println!("{}", tuple) +//! ``` +//! +//! ## Monte Carlo estimation of π +//! +//! For this example, imagine we have a square with sides of length 2 and a unit +//! circle, both centered at the origin. Since the area of a unit circle is π, +//! we have: +//! +//! ```notrust +//! (area of unit circle) / (area of square) = π / 4 +//! ``` +//! +//! So if we sample many points randomly from the square, roughly π / 4 of them +//! should be inside the circle. +//! +//! We can use the above fact to estimate the value of π: pick many points in the +//! square at random, calculate the fraction that fall within the circle, and +//! multiply this fraction by 4. +//! +//! ``` +//! use std::rand; +//! use std::rand::distributions::{IndependentSample, Range}; +//! +//! fn main() { +//! let between = Range::new(-1f64, 1.); +//! let mut rng = rand::task_rng(); +//! +//! let total = 1_000_000u; +//! let mut in_circle = 0u; +//! +//! for _ in range(0u, total) { +//! let a = between.ind_sample(&mut rng); +//! let b = between.ind_sample(&mut rng); +//! if a*a + b*b <= 1. { +//! in_circle += 1; +//! } +//! } +//! +//! // prints something close to 3.14159... +//! println!("{}", 4. * (in_circle as f64) / (total as f64)); +//! } +//! ``` +//! +//! ## Monty Hall Problem +//! +//! This is a simulation of the [Monty Hall Problem][]: +//! +//! > Suppose you're on a game show, and you're given the choice of three doors: +//! > Behind one door is a car; behind the others, goats. You pick a door, say No. 1, +//! > and the host, who knows what's behind the doors, opens another door, say No. 3, +//! > which has a goat. He then says to you, "Do you want to pick door No. 2?" +//! > Is it to your advantage to switch your choice? +//! +//! The rather unintuitive answer is that you will have a 2/3 chance of winning if +//! you switch and a 1/3 chance of winning of you don't, so it's better to switch. +//! +//! This program will simulate the game show and with large enough simulation steps +//! it will indeed confirm that it is better to switch. +//! +//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem +//! +//! ``` +//! use std::rand; +//! use std::rand::Rng; +//! use std::rand::distributions::{IndependentSample, Range}; +//! +//! struct SimulationResult { +//! win: bool, +//! switch: bool, +//! } +//! +//! // Run a single simulation of the Monty Hall problem. +//! fn simulate(random_door: &Range, rng: &mut R) -> SimulationResult { +//! let car = random_door.ind_sample(rng); +//! +//! // This is our initial choice +//! let mut choice = random_door.ind_sample(rng); +//! +//! // The game host opens a door +//! let open = game_host_open(car, choice, rng); +//! +//! // Shall we switch? +//! let switch = rng.gen(); +//! if switch { +//! choice = switch_door(choice, open); +//! } +//! +//! SimulationResult { win: choice == car, switch: switch } +//! } +//! +//! // Returns the door the game host opens given our choice and knowledge of +//! // where the car is. The game host will never open the door with the car. +//! fn game_host_open(car: uint, choice: uint, rng: &mut R) -> uint { +//! let choices = free_doors(&[car, choice]); +//! rand::sample(rng, choices.into_iter(), 1)[0] +//! } +//! +//! // Returns the door we switch to, given our current choice and +//! // the open door. There will only be one valid door. +//! fn switch_door(choice: uint, open: uint) -> uint { +//! free_doors(&[choice, open])[0] +//! } +//! +//! fn free_doors(blocked: &[uint]) -> Vec { +//! range(0u, 3).filter(|x| !blocked.contains(x)).collect() +//! } +//! +//! fn main() { +//! // The estimation will be more accurate with more simulations +//! let num_simulations = 10000u; +//! +//! let mut rng = rand::task_rng(); +//! let random_door = Range::new(0u, 3); +//! +//! let (mut switch_wins, mut switch_losses) = (0u, 0u); +//! let (mut keep_wins, mut keep_losses) = (0u, 0u); +//! +//! println!("Running {} simulations...", num_simulations); +//! for _ in range(0, num_simulations) { +//! let result = simulate(&random_door, &mut rng); +//! +//! match (result.win, result.switch) { +//! (true, true) => switch_wins += 1, +//! (true, false) => keep_wins += 1, +//! (false, true) => switch_losses += 1, +//! (false, false) => keep_losses += 1, +//! } +//! } +//! +//! let total_switches = switch_wins + switch_losses; +//! let total_keeps = keep_wins + keep_losses; +//! +//! println!("Switched door {} times with {} wins and {} losses", +//! total_switches, switch_wins, switch_losses); +//! +//! println!("Kept our choice {} times with {} wins and {} losses", +//! total_keeps, keep_wins, keep_losses); +//! +//! // With a large number of simulations, the values should converge to +//! // 0.667 and 0.333 respectively. +//! println!("Estimated chance to win if we switch: {}", +//! switch_wins as f32 / total_switches as f32); +//! println!("Estimated chance to win if we don't: {}", +//! keep_wins as f32 / total_keeps as f32); +//! } +//! ``` + +#![experimental] + +use cell::RefCell; +use clone::Clone; +use io::IoResult; +use iter::Iterator; +use mem; +use rc::Rc; +use result::{Ok, Err}; +use vec::Vec; + +#[cfg(not(target_word_size="64"))] +use core_rand::IsaacRng as IsaacWordRng; +#[cfg(target_word_size="64")] +use core_rand::Isaac64Rng as IsaacWordRng; + +pub use core_rand::{Rand, Rng, SeedableRng, Open01, Closed01}; +pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng}; +pub use core_rand::{distributions, reseeding}; +pub use rand::os::OsRng; + +pub mod os; +pub mod reader; + +/// The standard RNG. This is designed to be efficient on the current +/// platform. +pub struct StdRng { rng: IsaacWordRng } + +impl StdRng { + /// Create a randomly seeded instance of `StdRng`. + /// + /// This is a very expensive operation as it has to read + /// randomness from the operating system and use this in an + /// expensive seeding operation. If one is only generating a small + /// number of random numbers, or doesn't need the utmost speed for + /// generating each number, `task_rng` and/or `random` may be more + /// appropriate. + /// + /// Reading the randomness from the OS may fail, and any error is + /// propagated via the `IoResult` return value. + pub fn new() -> IoResult { unimplemented!() } +} + +impl Rng for StdRng { + #[inline] + fn next_u32(&mut self) -> u32 { unimplemented!() } + + #[inline] + fn next_u64(&mut self) -> u64 { unimplemented!() } +} + +impl<'a> SeedableRng<&'a [uint]> for StdRng { + fn reseed(&mut self, seed: &'a [uint]) { unimplemented!() } + + fn from_seed(seed: &'a [uint]) -> StdRng { unimplemented!() } +} + +/// Create a weak random number generator with a default algorithm and seed. +/// +/// It returns the fastest `Rng` algorithm currently available in Rust without +/// consideration for cryptography or security. If you require a specifically +/// seeded `Rng` for consistency over time you should pick one algorithm and +/// create the `Rng` yourself. +/// +/// This will read randomness from the operating system to seed the +/// generator. +pub fn weak_rng() -> XorShiftRng { unimplemented!() } + +/// Controls how the task-local RNG is reseeded. +struct TaskRngReseeder; + +impl reseeding::Reseeder for TaskRngReseeder { + fn reseed(&mut self, rng: &mut StdRng) { unimplemented!() } +} +static TASK_RNG_RESEED_THRESHOLD: uint = 32_768; +type TaskRngInner = reseeding::ReseedingRng; + +/// The task-local RNG. +pub struct TaskRng { + rng: Rc>, +} + +/// Retrieve the lazily-initialized task-local random number +/// generator, seeded by the system. Intended to be used in method +/// chaining style, e.g. `task_rng().gen::()`. +/// +/// The RNG provided will reseed itself from the operating system +/// after generating a certain amount of randomness. +/// +/// The internal RNG used is platform and architecture dependent, even +/// if the operating system random number generator is rigged to give +/// the same sequence always. If absolute consistency is required, +/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. +pub fn task_rng() -> TaskRng { unimplemented!() } + +impl Rng for TaskRng { + fn next_u32(&mut self) -> u32 { unimplemented!() } + + fn next_u64(&mut self) -> u64 { unimplemented!() } + + #[inline] + fn fill_bytes(&mut self, bytes: &mut [u8]) { unimplemented!() } +} + +/// Generates a random value using the task-local random number generator. +/// +/// `random()` can generate various types of random things, and so may require +/// type hinting to generate the specific type you want. +/// +/// # Examples +/// +/// ```rust +/// use std::rand; +/// +/// let x = rand::random(); +/// println!("{}", 2u * x); +/// +/// let y = rand::random::(); +/// println!("{}", y); +/// +/// if rand::random() { // generates a boolean +/// println!("Better lucky than good!"); +/// } +/// ``` +#[inline] +pub fn random() -> T { unimplemented!() } + +/// Randomly sample up to `amount` elements from an iterator. +/// +/// # Example +/// +/// ```rust +/// use std::rand::{task_rng, sample}; +/// +/// let mut rng = task_rng(); +/// let sample = sample(&mut rng, range(1i, 100), 5); +/// println!("{}", sample); +/// ``` +pub fn sample, R: Rng>(rng: &mut R, + mut iter: I, + amount: uint) -> Vec { unimplemented!() } diff --git a/src/libst2/rand/os.rs b/src/libst2/rand/os.rs new file mode 100644 index 0000000000000..2a4d8347c30c9 --- /dev/null +++ b/src/libst2/rand/os.rs @@ -0,0 +1,384 @@ +// Copyright 2013-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. + +//! Interfaces to the operating system provided random number +//! generators. + +pub use self::imp::OsRng; + +#[cfg(all(unix, not(target_os = "ios")))] +mod imp { + extern crate libc; + + use self::OsRngInner::*; + + use io::{IoResult, File}; + use path::Path; + use rand::Rng; + use rand::reader::ReaderRng; + use result::{Ok, Err}; + use slice::SlicePrelude; + use mem; + use os::errno; + + #[cfg(all(target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] + fn getrandom(buf: &mut [u8]) -> libc::c_long { + extern "C" { + fn syscall(number: libc::c_long, ...) -> libc::c_long; + } + + #[cfg(target_arch = "x86_64")] + const NR_GETRANDOM: libc::c_long = 318; + #[cfg(target_arch = "x86")] + const NR_GETRANDOM: libc::c_long = 355; + #[cfg(target_arch = "arm")] + const NR_GETRANDOM: libc::c_long = 384; + + unsafe { + syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u) + } + } + + #[cfg(not(all(target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] + fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } + + fn getrandom_fill_bytes(v: &mut [u8]) { + let mut read = 0; + let len = v.len(); + while read < len { + let result = getrandom(v[mut read..]); + if result == -1 { + let err = errno() as libc::c_int; + if err == libc::EINTR { + continue; + } else { + panic!("unexpected getrandom error: {}", err); + } + } else { + read += result as uint; + } + } + } + + fn getrandom_next_u32() -> u32 { + let mut buf: [u8, ..4] = [0u8, ..4]; + getrandom_fill_bytes(&mut buf); + unsafe { mem::transmute::<[u8, ..4], u32>(buf) } + } + + fn getrandom_next_u64() -> u64 { + let mut buf: [u8, ..8] = [0u8, ..8]; + getrandom_fill_bytes(&mut buf); + unsafe { mem::transmute::<[u8, ..8], u64>(buf) } + } + + #[cfg(all(target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] + fn is_getrandom_available() -> bool { + use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed}; + + static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL; + static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL; + + if !GETRANDOM_CHECKED.load(Relaxed) { + let mut buf: [u8, ..0] = []; + let result = getrandom(&mut buf); + let available = if result == -1 { + let err = errno() as libc::c_int; + err != libc::ENOSYS + } else { + true + }; + GETRANDOM_AVAILABLE.store(available, Relaxed); + GETRANDOM_CHECKED.store(true, Relaxed); + available + } else { + GETRANDOM_AVAILABLE.load(Relaxed) + } + } + + #[cfg(not(all(target_os = "linux", + any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] + fn is_getrandom_available() -> bool { false } + + /// A random number generator that retrieves randomness straight from + /// the operating system. Platform sources: + /// + /// - Unix-like systems (Linux, Android, Mac OSX): read directly from + /// `/dev/urandom`, or from `getrandom(2)` system call if available. + /// - Windows: calls `CryptGenRandom`, using the default cryptographic + /// service provider with the `PROV_RSA_FULL` type. + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// This does not block. + pub struct OsRng { + inner: OsRngInner, + } + + enum OsRngInner { + OsGetrandomRng, + OsReaderRng(ReaderRng), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> IoResult { + if is_getrandom_available() { + return Ok(OsRng { inner: OsGetrandomRng }); + } + + let reader = try!(File::open(&Path::new("/dev/urandom"))); + let reader_rng = ReaderRng::new(reader); + + Ok(OsRng { inner: OsReaderRng(reader_rng) }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + match self.inner { + OsGetrandomRng => getrandom_next_u32(), + OsReaderRng(ref mut rng) => rng.next_u32(), + } + } + fn next_u64(&mut self) -> u64 { + match self.inner { + OsGetrandomRng => getrandom_next_u64(), + OsReaderRng(ref mut rng) => rng.next_u64(), + } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + match self.inner { + OsGetrandomRng => getrandom_fill_bytes(v), + OsReaderRng(ref mut rng) => rng.fill_bytes(v) + } + } + } +} + +#[cfg(target_os = "ios")] +mod imp { + extern crate libc; + + use io::{IoResult}; + use kinds::marker; + use mem; + use os; + use rand::Rng; + use result::{Ok}; + use self::libc::{c_int, size_t}; + use slice::{SlicePrelude}; + + /// A random number generator that retrieves randomness straight from + /// the operating system. Platform sources: + /// + /// - Unix-like systems (Linux, Android, Mac OSX): read directly from + /// `/dev/urandom`, or from `getrandom(2)` system call if available. + /// - Windows: calls `CryptGenRandom`, using the default cryptographic + /// service provider with the `PROV_RSA_FULL` type. + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// This does not block. + pub struct OsRng { + marker: marker::NoCopy + } + + #[repr(C)] + struct SecRandom; + + #[allow(non_upper_case_globals)] + static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; + + #[link(name = "Security", kind = "framework")] + extern "C" { + fn SecRandomCopyBytes(rnd: *const SecRandom, + count: size_t, bytes: *mut u8) -> c_int; + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> IoResult { + Ok(OsRng {marker: marker::NoCopy} ) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let mut v = [0u8, .. 4]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn next_u64(&mut self) -> u64 { + let mut v = [0u8, .. 8]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let ret = unsafe { + SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) + }; + if ret == -1 { + panic!("couldn't generate random bytes: {}", os::last_os_error()); + } + } + } +} + +#[cfg(windows)] +mod imp { + extern crate libc; + + use io::{IoResult, IoError}; + use mem; + use ops::Drop; + use os; + use rand::Rng; + use result::{Ok, Err}; + use self::libc::{DWORD, BYTE, LPCSTR, BOOL}; + use self::libc::types::os::arch::extra::{LONG_PTR}; + use slice::{SlicePrelude}; + + type HCRYPTPROV = LONG_PTR; + + /// A random number generator that retrieves randomness straight from + /// the operating system. Platform sources: + /// + /// - Unix-like systems (Linux, Android, Mac OSX): read directly from + /// `/dev/urandom`, or from `getrandom(2)` system call if available. + /// - Windows: calls `CryptGenRandom`, using the default cryptographic + /// service provider with the `PROV_RSA_FULL` type. + /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed + /// This does not block. + pub struct OsRng { + hcryptprov: HCRYPTPROV + } + + static PROV_RSA_FULL: DWORD = 1; + static CRYPT_SILENT: DWORD = 64; + static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; + + #[allow(non_snake_case)] + extern "system" { + fn CryptAcquireContextA(phProv: *mut HCRYPTPROV, + pszContainer: LPCSTR, + pszProvider: LPCSTR, + dwProvType: DWORD, + dwFlags: DWORD) -> BOOL; + fn CryptGenRandom(hProv: HCRYPTPROV, + dwLen: DWORD, + pbBuffer: *mut BYTE) -> BOOL; + fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL; + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> IoResult { + let mut hcp = 0; + let ret = unsafe { + CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR, + PROV_RSA_FULL, + CRYPT_VERIFYCONTEXT | CRYPT_SILENT) + }; + + if ret == 0 { + Err(IoError::last_error()) + } else { + Ok(OsRng { hcryptprov: hcp }) + } + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + let mut v = [0u8, .. 4]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn next_u64(&mut self) -> u64 { + let mut v = [0u8, .. 8]; + self.fill_bytes(&mut v); + unsafe { mem::transmute(v) } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let ret = unsafe { + CryptGenRandom(self.hcryptprov, v.len() as DWORD, + v.as_mut_ptr()) + }; + if ret == 0 { + panic!("couldn't generate random bytes: {}", os::last_os_error()); + } + } + } + + impl Drop for OsRng { + fn drop(&mut self) { + let ret = unsafe { + CryptReleaseContext(self.hcryptprov, 0) + }; + if ret == 0 { + panic!("couldn't release context: {}", os::last_os_error()); + } + } + } +} + +#[cfg(test)] +mod test { + use prelude::*; + + use super::OsRng; + use rand::Rng; + use task; + + #[test] + fn test_os_rng() { + let mut r = OsRng::new().unwrap(); + + r.next_u32(); + r.next_u64(); + + let mut v = [0u8, .. 1000]; + r.fill_bytes(&mut v); + } + + #[test] + fn test_os_rng_tasks() { + + let mut txs = vec!(); + for _ in range(0u, 20) { + let (tx, rx) = channel(); + txs.push(tx); + task::spawn(proc() { + // wait until all the tasks are ready to go. + rx.recv(); + + // deschedule to attempt to interleave things as much + // as possible (XXX: is this a good test?) + let mut r = OsRng::new().unwrap(); + task::deschedule(); + let mut v = [0u8, .. 1000]; + + for _ in range(0u, 100) { + r.next_u32(); + task::deschedule(); + r.next_u64(); + task::deschedule(); + r.fill_bytes(&mut v); + task::deschedule(); + } + }) + } + + // start all the tasks + for tx in txs.iter() { + tx.send(()) + } + } +} diff --git a/src/libst2/rand/reader.rs b/src/libst2/rand/reader.rs new file mode 100644 index 0000000000000..796bf7853f73b --- /dev/null +++ b/src/libst2/rand/reader.rs @@ -0,0 +1,123 @@ +// Copyright 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. + +//! A wrapper around any Reader to treat it as an RNG. + +use io::Reader; +use rand::Rng; +use result::{Ok, Err}; +use slice::SlicePrelude; + +/// An RNG that reads random bytes straight from a `Reader`. This will +/// work best with an infinite reader, but this is not required. +/// +/// # Panics +/// +/// It will panic if it there is insufficient data to fulfill a request. +/// +/// # Example +/// +/// ```rust +/// use std::rand::{reader, Rng}; +/// use std::io::MemReader; +/// +/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8))); +/// println!("{:x}", rng.gen::()); +/// ``` +pub struct ReaderRng { + reader: R +} + +impl ReaderRng { + /// Create a new `ReaderRng` from a `Reader`. + pub fn new(r: R) -> ReaderRng { + ReaderRng { + reader: r + } + } +} + +impl Rng for ReaderRng { + fn next_u32(&mut self) -> u32 { + // This is designed for speed: reading a LE integer on a LE + // platform just involves blitting the bytes into the memory + // of the u32, similarly for BE on BE; avoiding byteswapping. + if cfg!(target_endian="little") { + self.reader.read_le_u32().unwrap() + } else { + self.reader.read_be_u32().unwrap() + } + } + fn next_u64(&mut self) -> u64 { + // see above for explanation. + if cfg!(target_endian="little") { + self.reader.read_le_u64().unwrap() + } else { + self.reader.read_be_u64().unwrap() + } + } + fn fill_bytes(&mut self, v: &mut [u8]) { + if v.len() == 0 { return } + match self.reader.read_at_least(v.len(), v) { + Ok(_) => {} + Err(e) => panic!("ReaderRng.fill_bytes error: {}", e) + } + } +} + +#[cfg(test)] +mod test { + use prelude::*; + + use super::ReaderRng; + use io::MemReader; + use num::Int; + use rand::Rng; + + #[test] + fn test_reader_rng_u64() { + // transmute from the target to avoid endianness concerns. + let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, + 0 , 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 3]; + let mut rng = ReaderRng::new(MemReader::new(v)); + + assert_eq!(rng.next_u64(), 1_u64.to_be()); + assert_eq!(rng.next_u64(), 2_u64.to_be()); + assert_eq!(rng.next_u64(), 3_u64.to_be()); + } + #[test] + fn test_reader_rng_u32() { + let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; + let mut rng = ReaderRng::new(MemReader::new(v)); + + assert_eq!(rng.next_u32(), 1_u32.to_be()); + assert_eq!(rng.next_u32(), 2_u32.to_be()); + assert_eq!(rng.next_u32(), 3_u32.to_be()); + } + #[test] + fn test_reader_rng_fill_bytes() { + let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; + let mut w = [0u8, .. 8]; + + let mut rng = ReaderRng::new(MemReader::new(v.as_slice().to_vec())); + rng.fill_bytes(&mut w); + + assert!(v == w); + } + + #[test] + #[should_fail] + fn test_reader_rng_insufficient_bytes() { + let mut rng = ReaderRng::new(MemReader::new(vec!())); + let mut v = [0u8, .. 3]; + rng.fill_bytes(&mut v); + } +} diff --git a/src/libst2/rt/backtrace.rs b/src/libst2/rt/backtrace.rs new file mode 100644 index 0000000000000..ad7361fb53e4c --- /dev/null +++ b/src/libst2/rt/backtrace.rs @@ -0,0 +1,501 @@ +// 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 backtrace functionality (to print on panic) + +#![allow(non_camel_case_types)] + +use io::{IoResult, Writer}; +use iter::Iterator; +use option::{Some, None}; +use os; +use result::{Ok, Err}; +use str::{StrPrelude, from_str}; +use sync::atomic; +use unicode::char::UnicodeChar; + +pub use self::imp::write; + +// For now logging is turned off by default, and this function checks to see +// whether the magical environment variable is present to see if it's turned on. +pub fn log_enabled() -> bool { unimplemented!() } + +#[cfg(target_word_size = "64")] const HEX_WIDTH: uint = 18; +#[cfg(target_word_size = "32")] const HEX_WIDTH: uint = 10; + +// All rust symbols are in theory lists of "::"-separated identifiers. Some +// assemblers, however, can't handle these characters in symbol names. To get +// around this, we use C++-style mangling. The mangling method is: +// +// 1. Prefix the symbol with "_ZN" +// 2. For each element of the path, emit the length plus the element +// 3. End the path with "E" +// +// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar". +// +// We're the ones printing our backtraces, so we can't rely on anything else to +// demangle our symbols. It's *much* nicer to look at demangled symbols, so +// this function is implemented to give us nice pretty output. +// +// Note that this demangler isn't quite as fancy as it could be. We have lots +// of other information in our symbols like hashes, version, type information, +// etc. Additionally, this doesn't handle glue symbols at all. +fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { unimplemented!() } + +/// Backtrace support built on libgcc with some extra OS-specific support +/// +/// Some methods of getting a backtrace: +/// +/// * The backtrace() functions on unix. It turns out this doesn't work very +/// well for green threads on OSX, and the address to symbol portion of it +/// suffers problems that are described below. +/// +/// * Using libunwind. This is more difficult than it sounds because libunwind +/// isn't installed everywhere by default. It's also a bit of a hefty library, +/// so possibly not the best option. When testing, libunwind was excellent at +/// getting both accurate backtraces and accurate symbols across platforms. +/// This route was not chosen in favor of the next option, however. +/// +/// * We're already using libgcc_s for exceptions in rust (triggering task +/// unwinding and running destructors on the stack), and it turns out that it +/// conveniently comes with a function that also gives us a backtrace. All of +/// these functions look like _Unwind_*, but it's not quite the full +/// repertoire of the libunwind API. Due to it already being in use, this was +/// the chosen route of getting a backtrace. +/// +/// After choosing libgcc_s for backtraces, the sad part is that it will only +/// give us a stack trace of instruction pointers. Thankfully these instruction +/// pointers are accurate (they work for green and native threads), but it's +/// then up to us again to figure out how to translate these addresses to +/// symbols. As with before, we have a few options. Before, that, a little bit +/// of an interlude about symbols. This is my very limited knowledge about +/// symbol tables, and this information is likely slightly wrong, but the +/// general idea should be correct. +/// +/// When talking about symbols, it's helpful to know a few things about where +/// symbols are located. Some symbols are located in the dynamic symbol table +/// of the executable which in theory means that they're available for dynamic +/// linking and lookup. Other symbols end up only in the local symbol table of +/// the file. This loosely corresponds to pub and priv functions in Rust. +/// +/// Armed with this knowledge, we know that our solution for address to symbol +/// translation will need to consult both the local and dynamic symbol tables. +/// With that in mind, here's our options of translating an address to +/// a symbol. +/// +/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() +/// behind the scenes to translate, and this is why backtrace() was not used. +/// Conveniently, this method works fantastically on OSX. It appears dladdr() +/// uses magic to consult the local symbol table, or we're putting everything +/// in the dynamic symbol table anyway. Regardless, for OSX, this is the +/// method used for translation. It's provided by the system and easy to do.o +/// +/// Sadly, all other systems have a dladdr() implementation that does not +/// consult the local symbol table. This means that most functions are blank +/// because they don't have symbols. This means that we need another solution. +/// +/// * Use unw_get_proc_name(). This is part of the libunwind api (not the +/// libgcc_s version of the libunwind api), but involves taking a dependency +/// to libunwind. We may pursue this route in the future if we bundle +/// libunwind, but libunwind was unwieldy enough that it was not chosen at +/// this time to provide this functionality. +/// +/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a +/// semi-reasonable solution. The stdlib already knows how to spawn processes, +/// so in theory it could invoke readelf, parse the output, and consult the +/// local/dynamic symbol tables from there. This ended up not getting chosen +/// due to the craziness of the idea plus the advent of the next option. +/// +/// * Use `libbacktrace`. It turns out that this is a small library bundled in +/// the gcc repository which provides backtrace and symbol translation +/// functionality. All we really need from it is the backtrace functionality, +/// and we only really need this on everything that's not OSX, so this is the +/// chosen route for now. +/// +/// In summary, the current situation uses libgcc_s to get a trace of stack +/// pointers, and we use dladdr() or libbacktrace to translate these addresses +/// to symbols. This is a bit of a hokey implementation as-is, but it works for +/// all unix platforms we support right now, so it at least gets the job done. +#[cfg(unix)] +mod imp { + use c_str::CString; + use io::{IoResult, Writer}; + use libc; + use mem; + use option::{Some, None, Option}; + use result::{Ok, Err}; + use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + + /// As always - iOS on arm uses SjLj exceptions and + /// _Unwind_Backtrace is even not available there. Still, + /// backtraces could be extracted using a backtrace function, + /// which thanks god is public + /// + /// As mentioned in a huge comment block above, backtrace doesn't + /// play well with green threads, so while it is extremely nice + /// and simple to use it should be used only on iOS devices as the + /// only viable option. + #[cfg(all(target_os = "ios", target_arch = "arm"))] + #[inline(never)] + pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } + + #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + #[inline(never)] // if we know this is a function call, we can skip it when + // tracing + pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { unimplemented!() } + + #[cfg(not(any(target_os = "macos", target_os = "ios")))] + fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { unimplemented!() } + + // Finally, after all that work above, we can emit a symbol. + fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void, + s: Option) -> IoResult<()> { unimplemented!() } + + /// Unwind library interface used for backtraces + /// + /// Note that the native libraries come from librustrt, not this + /// module. + /// Note that dead code is allowed as here are just bindings + /// iOS doesn't use all of them it but adding more + /// platform-specific configs pollutes the code too much + #[allow(non_camel_case_types)] + #[allow(non_snake_case)] + #[allow(dead_code)] + mod uw { + pub use self::_Unwind_Reason_Code::*; + + use libc; + + #[repr(C)] + pub enum _Unwind_Reason_Code { + _URC_NO_REASON = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9, // used only by ARM EABI + } + + pub enum _Unwind_Context {} + + pub type _Unwind_Trace_Fn = + extern fn(ctx: *mut _Unwind_Context, + arg: *mut libc::c_void) -> _Unwind_Reason_Code; + + extern { + // No native _Unwind_Backtrace on iOS + #[cfg(not(all(target_os = "ios", target_arch = "arm")))] + pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, + trace_argument: *mut libc::c_void) + -> _Unwind_Reason_Code; + + #[cfg(all(not(target_os = "android"), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t; + + #[cfg(all(not(target_os = "android"), + not(all(target_os = "linux", target_arch = "arm"))))] + pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) + -> *mut libc::c_void; + } + + // On android, the function _Unwind_GetIP is a macro, and this is the + // expansion of the macro. This is all copy/pasted directly from the + // header file with the definition of _Unwind_GetIP. + #[cfg(any(target_os = "android", + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { unimplemented!() } + + // This function also doesn't exist on Android or ARM/Linux, so make it + // a no-op + #[cfg(any(target_os = "android", + all(target_os = "linux", target_arch = "arm")))] + pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) + -> *mut libc::c_void + { unimplemented!() } + } +} + +/// As always, windows has something very different than unix, we mainly want +/// to avoid having to depend too much on libunwind for windows. +/// +/// If you google around, you'll find a fair bit of references to built-in +/// functions to get backtraces on windows. It turns out that most of these are +/// in an external library called dbghelp. I was unable to find this library +/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent +/// of it. +/// +/// You'll also find that there's a function called CaptureStackBackTrace +/// mentioned frequently (which is also easy to use), but sadly I didn't have a +/// copy of that function in my mingw install (maybe it was broken?). Instead, +/// this takes the route of using StackWalk64 in order to walk the stack. +#[cfg(windows)] +#[allow(dead_code, non_snake_case)] +mod imp { + use c_str::CString; + use intrinsics; + use io::{IoResult, Writer}; + use libc; + use mem; + use ops::Drop; + use option::{Some, None}; + use path::Path; + use result::{Ok, Err}; + use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; + use slice::SlicePrelude; + use str::StrPrelude; + use dynamic_lib::DynamicLibrary; + + #[allow(non_snake_case)] + extern "system" { + fn GetCurrentProcess() -> libc::HANDLE; + fn GetCurrentThread() -> libc::HANDLE; + fn RtlCaptureContext(ctx: *mut arch::CONTEXT); + } + + type SymFromAddrFn = + extern "system" fn(libc::HANDLE, u64, *mut u64, + *mut SYMBOL_INFO) -> libc::BOOL; + type SymInitializeFn = + extern "system" fn(libc::HANDLE, *mut libc::c_void, + libc::BOOL) -> libc::BOOL; + type SymCleanupFn = + extern "system" fn(libc::HANDLE) -> libc::BOOL; + + type StackWalk64Fn = + extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE, + *mut STACKFRAME64, *mut arch::CONTEXT, + *mut libc::c_void, *mut libc::c_void, + *mut libc::c_void, *mut libc::c_void) -> libc::BOOL; + + const MAX_SYM_NAME: uint = 2000; + const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c; + const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200; + const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664; + + #[repr(C)] + struct SYMBOL_INFO { + SizeOfStruct: libc::c_ulong, + TypeIndex: libc::c_ulong, + Reserved: [u64, ..2], + Index: libc::c_ulong, + Size: libc::c_ulong, + ModBase: u64, + Flags: libc::c_ulong, + Value: u64, + Address: u64, + Register: libc::c_ulong, + Scope: libc::c_ulong, + Tag: libc::c_ulong, + NameLen: libc::c_ulong, + MaxNameLen: libc::c_ulong, + // note that windows has this as 1, but it basically just means that + // the name is inline at the end of the struct. For us, we just bump + // the struct size up to MAX_SYM_NAME. + Name: [libc::c_char, ..MAX_SYM_NAME], + } + + + #[repr(C)] + enum ADDRESS_MODE { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat, + } + + struct ADDRESS64 { + Offset: u64, + Segment: u16, + Mode: ADDRESS_MODE, + } + + struct STACKFRAME64 { + AddrPC: ADDRESS64, + AddrReturn: ADDRESS64, + AddrFrame: ADDRESS64, + AddrStack: ADDRESS64, + AddrBStore: ADDRESS64, + FuncTableEntry: *mut libc::c_void, + Params: [u64, ..4], + Far: libc::BOOL, + Virtual: libc::BOOL, + Reserved: [u64, ..3], + KdHelp: KDHELP64, + } + + struct KDHELP64 { + Thread: u64, + ThCallbackStack: libc::DWORD, + ThCallbackBStore: libc::DWORD, + NextCallback: libc::DWORD, + FramePointer: libc::DWORD, + KiCallUserMode: u64, + KeUserCallbackDispatcher: u64, + SystemRangeStart: u64, + KiUserExceptionDispatcher: u64, + StackBase: u64, + StackLimit: u64, + Reserved: [u64, ..5], + } + + #[cfg(target_arch = "x86")] + mod arch { + use libc; + + const MAXIMUM_SUPPORTED_EXTENSION: uint = 512; + + #[repr(C)] + pub struct CONTEXT { + ContextFlags: libc::DWORD, + Dr0: libc::DWORD, + Dr1: libc::DWORD, + Dr2: libc::DWORD, + Dr3: libc::DWORD, + Dr6: libc::DWORD, + Dr7: libc::DWORD, + FloatSave: FLOATING_SAVE_AREA, + SegGs: libc::DWORD, + SegFs: libc::DWORD, + SegEs: libc::DWORD, + SegDs: libc::DWORD, + Edi: libc::DWORD, + Esi: libc::DWORD, + Ebx: libc::DWORD, + Edx: libc::DWORD, + Ecx: libc::DWORD, + Eax: libc::DWORD, + Ebp: libc::DWORD, + Eip: libc::DWORD, + SegCs: libc::DWORD, + EFlags: libc::DWORD, + Esp: libc::DWORD, + SegSs: libc::DWORD, + ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION], + } + + #[repr(C)] + pub struct FLOATING_SAVE_AREA { + ControlWord: libc::DWORD, + StatusWord: libc::DWORD, + TagWord: libc::DWORD, + ErrorOffset: libc::DWORD, + ErrorSelector: libc::DWORD, + DataOffset: libc::DWORD, + DataSelector: libc::DWORD, + RegisterArea: [u8, ..80], + Cr0NpxState: libc::DWORD, + } + + pub fn init_frame(frame: &mut super::STACKFRAME64, + ctx: &CONTEXT) -> libc::DWORD { unimplemented!() } + } + + #[cfg(target_arch = "x86_64")] + mod arch { + use libc::{c_longlong, c_ulonglong}; + use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG}; + use simd; + + #[repr(C)] + pub struct CONTEXT { + _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte + P1Home: DWORDLONG, + P2Home: DWORDLONG, + P3Home: DWORDLONG, + P4Home: DWORDLONG, + P5Home: DWORDLONG, + P6Home: DWORDLONG, + + ContextFlags: DWORD, + MxCsr: DWORD, + + SegCs: WORD, + SegDs: WORD, + SegEs: WORD, + SegFs: WORD, + SegGs: WORD, + SegSs: WORD, + EFlags: DWORD, + + Dr0: DWORDLONG, + Dr1: DWORDLONG, + Dr2: DWORDLONG, + Dr3: DWORDLONG, + Dr6: DWORDLONG, + Dr7: DWORDLONG, + + Rax: DWORDLONG, + Rcx: DWORDLONG, + Rdx: DWORDLONG, + Rbx: DWORDLONG, + Rsp: DWORDLONG, + Rbp: DWORDLONG, + Rsi: DWORDLONG, + Rdi: DWORDLONG, + R8: DWORDLONG, + R9: DWORDLONG, + R10: DWORDLONG, + R11: DWORDLONG, + R12: DWORDLONG, + R13: DWORDLONG, + R14: DWORDLONG, + R15: DWORDLONG, + + Rip: DWORDLONG, + + FltSave: FLOATING_SAVE_AREA, + + VectorRegister: [M128A, .. 26], + VectorControl: DWORDLONG, + + DebugControl: DWORDLONG, + LastBranchToRip: DWORDLONG, + LastBranchFromRip: DWORDLONG, + LastExceptionToRip: DWORDLONG, + LastExceptionFromRip: DWORDLONG, + } + + #[repr(C)] + pub struct M128A { + _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte + Low: c_ulonglong, + High: c_longlong + } + + #[repr(C)] + pub struct FLOATING_SAVE_AREA { + _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte + _Dummy: [u8, ..512] // FIXME: Fill this out + } + + pub fn init_frame(frame: &mut super::STACKFRAME64, + ctx: &CONTEXT) -> DWORD { unimplemented!() } + } + + #[repr(C)] + struct Cleanup { + handle: libc::HANDLE, + SymCleanup: SymCleanupFn, + } + + impl Drop for Cleanup { + fn drop(&mut self) { unimplemented!() } + } + + pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } +} diff --git a/src/libst2/rt/mod.rs b/src/libst2/rt/mod.rs new file mode 100644 index 0000000000000..89573be5f2de5 --- /dev/null +++ b/src/libst2/rt/mod.rs @@ -0,0 +1,114 @@ +// Copyright 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. + +/*! Runtime services, including the task scheduler and I/O dispatcher + +The `rt` module provides the private runtime infrastructure necessary +to support core language features like the exchange and local heap, +logging, local data and unwinding. It also implements the default task +scheduler and task model. Initialization routines are provided for setting +up runtime resources in common configurations, including that used by +`rustc` when generating executables. + +It is intended that the features provided by `rt` can be factored in a +way such that the core library can be built with different 'profiles' +for different use cases, e.g. excluding the task scheduler. A number +of runtime features though are critical to the functioning of the +language and an implementation must be provided regardless of the +execution environment. + +Of foremost importance is the global exchange heap, in the module +`heap`. Very little practical Rust code can be written without +access to the global heap. Unlike most of `rt` the global heap is +truly a global resource and generally operates independently of the +rest of the runtime. + +All other runtime features are task-local, including the local heap, +local storage, logging and the stack unwinder. + +The relationship between `rt` and the rest of the core library is +not entirely clear yet and some modules will be moving into or +out of `rt` as development proceeds. + +Several modules in `core` are clients of `rt`: + +* `std::task` - The user-facing interface to the Rust task model. +* `std::local_data` - The interface to local data. +* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`. +* `std::cleanup` - Local heap destruction. +* `std::io` - In the future `std::io` will use an `rt` implementation. +* `std::logging` +* `std::comm` + +*/ + +#![experimental] + +// FIXME: this should not be here. +#![allow(missing_docs)] + +#![allow(dead_code)] + +use failure; +use rustrt; +use os; + +// Reexport some of our utilities which are expected by other crates. +pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; + +// Reexport functionality from librustrt and other crates underneath the +// standard library which work together to create the entire runtime. +pub use alloc::heap; +pub use rustrt::{begin_unwind, begin_unwind_fmt, at_exit}; + +// Simple backtrace functionality (to print on panic) +pub mod backtrace; + +// Just stuff +mod util; + +/// One-time runtime initialization. +/// +/// Initializes global state, including frobbing +/// the crate's logging flags, registering GC +/// metadata, and storing the process arguments. +#[allow(experimental)] +pub fn init(argc: int, argv: *const *const u8) { unimplemented!() } + +#[cfg(any(windows, android))] +static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; +#[cfg(all(unix, not(android)))] +static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); + +#[cfg(not(test))] +#[lang = "start"] +fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { unimplemented!() } + +/// Executes the given procedure after initializing the runtime with the given +/// argc/argv. +/// +/// This procedure is guaranteed to run on the thread calling this function, but +/// the stack bounds for this rust task will *not* be set. Care must be taken +/// for this function to not overflow its stack. +/// +/// This function will only return once *all* native threads in the system have +/// exited. +pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int { unimplemented!() } + +/// One-time runtime cleanup. +/// +/// This function is unsafe because it performs no checks to ensure that the +/// runtime has completely ceased running. It is the responsibility of the +/// caller to ensure that the runtime is entirely shut down and nothing will be +/// poking around at the internal components. +/// +/// Invoking cleanup while portions of the runtime are still in use may cause +/// undefined behavior. +pub unsafe fn cleanup() { unimplemented!() } diff --git a/src/libst2/rt/util.rs b/src/libst2/rt/util.rs new file mode 100644 index 0000000000000..8b87547a89626 --- /dev/null +++ b/src/libst2/rt/util.rs @@ -0,0 +1,38 @@ +// Copyright 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. + +use libc::uintptr_t; +use option::{Some, None, Option}; +use os; +use str::{FromStr, from_str, Str}; +use sync::atomic; + +/// Dynamically inquire about whether we're running under V. +/// You should usually not use this unless your test definitely +/// can't run correctly un-altered. Valgrind is there to help +/// you notice weirdness in normal, un-doctored code paths! +pub fn running_on_valgrind() -> bool { unimplemented!() } + +/// Valgrind has a fixed-sized array (size around 2000) of segment descriptors +/// wired into it; this is a hard limit and requires rebuilding valgrind if you +/// want to go beyond it. Normally this is not a problem, but in some tests, we +/// produce a lot of threads casually. Making lots of threads alone might not +/// be a problem _either_, except on OSX, the segments produced for new threads +/// _take a while_ to get reclaimed by the OS. Combined with the fact that libuv +/// schedulers fork off a separate thread for polling fsevents on OSX, we get a +/// perfect storm of creating "too many mappings" for valgrind to handle when +/// running certain stress tests in the runtime. +pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool { unimplemented!() } + +pub fn min_stack() -> uint { unimplemented!() } + +/// Get's the number of scheduler threads requested by the environment +/// either `RUST_THREADS` or `num_cpus`. +pub fn default_sched_threads() -> uint { unimplemented!() } diff --git a/src/libst2/rtdeps.rs b/src/libst2/rtdeps.rs new file mode 100644 index 0000000000000..35a8713711591 --- /dev/null +++ b/src/libst2/rtdeps.rs @@ -0,0 +1,52 @@ +// Copyright 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. + +//! This module contains the linkage attributes to all runtime dependencies of +//! the standard library This varies per-platform, but these libraries are +//! necessary for running libstd. + +#![experimental] + +// All platforms need to link to rustrt +#[cfg(not(test))] +#[link(name = "rust_builtin", kind = "static")] +extern {} + +// LLVM implements the `frem` instruction as a call to `fmod`, which lives in +// libm. Hence, we must explicitly link to it. +// +// On Linux, librt and libdl are indirect dependencies via rustrt, +// and binutils 2.22+ won't add them automatically +#[cfg(target_os = "linux")] +#[link(name = "dl")] +#[link(name = "pthread")] +extern {} + +#[cfg(target_os = "android")] +#[link(name = "dl")] +#[link(name = "log")] +extern {} + +#[cfg(target_os = "freebsd")] +#[link(name = "execinfo")] +#[link(name = "pthread")] +extern {} + +#[cfg(target_os = "dragonfly")] +#[link(name = "pthread")] +extern {} + +#[cfg(target_os = "macos")] +#[link(name = "System")] +extern {} + +#[cfg(target_os = "ios")] +#[link(name = "System")] +extern {} diff --git a/src/libst2/sync/future.rs b/src/libst2/sync/future.rs new file mode 100644 index 0000000000000..d62d1941fb6ac --- /dev/null +++ b/src/libst2/sync/future.rs @@ -0,0 +1,67 @@ +// 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. + +/*! + * A type representing values that may be computed concurrently and + * operations for working with them. + * + * # Example + * + * ```rust + * use std::sync::Future; + * # fn fib(n: uint) -> uint {42}; + * # fn make_a_sandwich() {}; + * let mut delayed_fib = Future::spawn(proc() { fib(5000) }); + * make_a_sandwich(); + * println!("fib(5000) = {}", delayed_fib.get()) + * ``` + */ + +#![allow(missing_docs)] + +use core::prelude::*; +use core::mem::replace; + +use self::FutureState::*; +use comm::{Receiver, channel}; +use task::spawn; + +/// A type encapsulating the result of a computation which may not be complete +pub struct Future { + state: FutureState, +} + +enum FutureState { + Pending(proc():Send -> A), + Evaluating, + Forced(A) +} + +/// Methods on the `future` type +impl Future { + pub fn get(&mut self) -> A { unimplemented!() } +} + +impl Future { + /// Gets the value from this future, forcing evaluation. + pub fn unwrap(mut self) -> A { unimplemented!() } + + pub fn get_ref<'a>(&'a mut self) -> &'a A { unimplemented!() } + + pub fn from_value(val: A) -> Future { unimplemented!() } + + pub fn from_fn(f: proc():Send -> A) -> Future { unimplemented!() } +} + +impl Future { + pub fn from_receiver(rx: Receiver) -> Future { unimplemented!() } + + pub fn spawn(blk: proc():Send -> A) -> Future { unimplemented!() } +} diff --git a/src/libst2/sync/mod.rs b/src/libst2/sync/mod.rs new file mode 100644 index 0000000000000..38e1e952f77e2 --- /dev/null +++ b/src/libst2/sync/mod.rs @@ -0,0 +1,33 @@ +// Copyright 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. + +//! Useful synchronization primitives +//! +//! This module contains useful safe and unsafe synchronization primitives. +//! Most of the primitives in this module do not provide any sort of locking +//! and/or blocking at all, but rather provide the necessary tools to build +//! other types of concurrent primitives. + +#![experimental] + +#[stable] +pub use core_sync::atomic; + +pub use core_sync::{deque, mpmc_bounded_queue, mpsc_queue, spsc_queue}; +pub use core_sync::{Arc, Weak, Mutex, MutexGuard, Condvar, Barrier}; +pub use core_sync::{RWLock, RWLockReadGuard, RWLockWriteGuard}; +pub use core_sync::{Semaphore, SemaphoreGuard}; +pub use core_sync::one::{Once, ONCE_INIT}; + +pub use self::future::Future; +pub use self::task_pool::TaskPool; + +mod future; +mod task_pool; diff --git a/src/libst2/sync/task_pool.rs b/src/libst2/sync/task_pool.rs new file mode 100644 index 0000000000000..87249af72ab4c --- /dev/null +++ b/src/libst2/sync/task_pool.rs @@ -0,0 +1,80 @@ +// 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. + +//! Abstraction of a task pool for basic parallelism. + +use core::prelude::*; + +use task::spawn; +use comm::{channel, Sender, Receiver}; +use sync::{Arc, Mutex}; + +struct Sentinel<'a> { + jobs: &'a Arc>>, + active: bool +} + +impl<'a> Sentinel<'a> { + fn new(jobs: &Arc>>) -> Sentinel { unimplemented!() } + + // Cancel and destroy this sentinel. + fn cancel(mut self) { unimplemented!() } +} + +#[unsafe_destructor] +impl<'a> Drop for Sentinel<'a> { + fn drop(&mut self) { unimplemented!() } +} + +/// A task pool used to execute functions in parallel. +/// +/// Spawns `n` worker tasks and replenishes the pool if any worker tasks +/// panic. +/// +/// # Example +/// +/// ```rust +/// # use std::sync::TaskPool; +/// # use std::iter::AdditiveIterator; +/// +/// let pool = TaskPool::new(4u); +/// +/// let (tx, rx) = channel(); +/// for _ in range(0, 8u) { +/// let tx = tx.clone(); +/// pool.execute(proc() { +/// tx.send(1u); +/// }); +/// } +/// +/// assert_eq!(rx.iter().take(8u).sum(), 8u); +/// ``` +pub struct TaskPool { + // How the taskpool communicates with subtasks. + // + // This is the only such Sender, so when it is dropped all subtasks will + // quit. + jobs: Sender +} + +impl TaskPool { + /// Spawns a new task pool with `tasks` tasks. + /// + /// # Panics + /// + /// This function will panic if `tasks` is 0. + pub fn new(tasks: uint) -> TaskPool { unimplemented!() } + + /// Executes the function `job` on a task in the pool. + pub fn execute(&self, job: proc():Send) { unimplemented!() } +} + +fn spawn_in_pool(jobs: Arc>>) { unimplemented!() } + diff --git a/src/libst2/sys/common/helper_thread.rs b/src/libst2/sys/common/helper_thread.rs new file mode 100644 index 0000000000000..bc2f3a8ac3555 --- /dev/null +++ b/src/libst2/sys/common/helper_thread.rs @@ -0,0 +1,78 @@ +// Copyright 2013-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. + +//! Implementation of the helper thread for the timer module +//! +//! This module contains the management necessary for the timer worker thread. +//! This thread is responsible for performing the send()s on channels for timers +//! that are using channels instead of a blocking call. +//! +//! The timer thread is lazily initialized, and it's shut down via the +//! `shutdown` function provided. It must be maintained as an invariant that +//! `shutdown` is only called when the entire program is finished. No new timers +//! can be created in the future and there must be no active timers at that +//! time. + +use mem; +use rustrt::bookkeeping; +use rustrt::mutex::StaticNativeMutex; +use rustrt; +use cell::UnsafeCell; +use sys::helper_signal; +use prelude::*; + +use task; + +/// A structure for management of a helper thread. +/// +/// This is generally a static structure which tracks the lifetime of a helper +/// thread. +/// +/// The fields of this helper are all public, but they should not be used, this +/// is for static initialization. +pub struct Helper { + /// Internal lock which protects the remaining fields + pub lock: StaticNativeMutex, + + // You'll notice that the remaining fields are UnsafeCell, and this is + // because all helper thread operations are done through &self, but we need + // these to be mutable (once `lock` is held). + + /// Lazily allocated channel to send messages to the helper thread. + pub chan: UnsafeCell<*mut Sender>, + + /// OS handle used to wake up a blocked helper thread + pub signal: UnsafeCell, + + /// Flag if this helper thread has booted and been initialized yet. + pub initialized: UnsafeCell, +} + +impl Helper { + /// Lazily boots a helper thread, becoming a no-op if the helper has already + /// been spawned. + /// + /// This function will check to see if the thread has been initialized, and + /// if it has it returns quickly. If initialization has not happened yet, + /// the closure `f` will be run (inside of the initialization lock) and + /// passed to the helper thread in a separate task. + /// + /// This function is safe to be called many times. + pub fn boot(&'static self, + f: || -> T, + helper: fn(helper_signal::signal, Receiver, T)) { unimplemented!() } + + /// Sends a message to a spawned worker thread. + /// + /// This is only valid if the worker thread has previously booted + pub fn send(&'static self, msg: M) { unimplemented!() } + + fn shutdown(&'static self) { unimplemented!() } +} diff --git a/src/libst2/sys/common/mod.rs b/src/libst2/sys/common/mod.rs new file mode 100644 index 0000000000000..254ad0719e6f1 --- /dev/null +++ b/src/libst2/sys/common/mod.rs @@ -0,0 +1,55 @@ +// 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. + +#![allow(missing_docs)] +#![allow(dead_code)] + +use io::{mod, IoError, IoResult}; +use prelude::*; +use sys::{last_error, retry, fs}; +use c_str::CString; +use num::Int; +use path::BytesContainer; +use collections; + +pub mod net; +pub mod helper_thread; +pub mod thread_local; + +// common error constructors + +pub fn eof() -> IoError { unimplemented!() } + +pub fn timeout(desc: &'static str) -> IoError { unimplemented!() } + +pub fn short_write(n: uint, desc: &'static str) -> IoError { unimplemented!() } + +pub fn unimpl() -> IoError { unimplemented!() } + +// unix has nonzero values as errors +pub fn mkerr_libc(ret: T) -> IoResult<()> { unimplemented!() } + +pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { unimplemented!() } + +// traits for extracting representations from + +pub trait AsFileDesc { + fn as_fd(&self) -> &fs::FileDesc; +} + +pub trait ProcessConfig { + fn program(&self) -> &CString; + fn args(&self) -> &[CString]; + fn env(&self) -> Option<&collections::HashMap>; + fn cwd(&self) -> Option<&CString>; + fn uid(&self) -> Option; + fn gid(&self) -> Option; + fn detach(&self) -> bool; +} diff --git a/src/libst2/sys/common/net.rs b/src/libst2/sys/common/net.rs new file mode 100644 index 0000000000000..f6b73ddfa9d75 --- /dev/null +++ b/src/libst2/sys/common/net.rs @@ -0,0 +1,298 @@ +// Copyright 2013-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. + +pub use self::SocketStatus::*; +pub use self::InAddr::*; + +use alloc::arc::Arc; +use libc::{mod, c_char, c_int}; +use mem; +use num::Int; +use ptr::{mod, null, null_mut}; +use rustrt::mutex; +use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; +use io::net::addrinfo; +use io::{IoResult, IoError}; +use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, + wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, + decode_error_detailed}; +use sys_common::{mod, keep_going, short_write, timeout}; +use prelude::*; +use cmp; +use io; + +// FIXME: move uses of Arc and deadline tracking to std::io + +#[deriving(Show)] +pub enum SocketStatus { + Readable, + Writable, +} + +//////////////////////////////////////////////////////////////////////////////// +// sockaddr and misc bindings +//////////////////////////////////////////////////////////////////////////////// + +pub fn htons(u: u16) -> u16 { unimplemented!() } +pub fn ntohs(u: u16) -> u16 { unimplemented!() } + +pub enum InAddr { + In4Addr(libc::in_addr), + In6Addr(libc::in6_addr), +} + +pub fn ip_to_inaddr(ip: IpAddr) -> InAddr { unimplemented!() } + +pub fn addr_to_sockaddr(addr: SocketAddr, + storage: &mut libc::sockaddr_storage) + -> libc::socklen_t { unimplemented!() } + +pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult { unimplemented!() } + +pub fn setsockopt(fd: sock_t, opt: libc::c_int, val: libc::c_int, + payload: T) -> IoResult<()> { unimplemented!() } + +pub fn getsockopt(fd: sock_t, opt: libc::c_int, + val: libc::c_int) -> IoResult { unimplemented!() } + +pub fn sockname(fd: sock_t, + f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr, + *mut libc::socklen_t) -> libc::c_int) + -> IoResult +{ unimplemented!() } + +pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, + len: uint) -> IoResult { unimplemented!() } + +//////////////////////////////////////////////////////////////////////////////// +// get_host_addresses +//////////////////////////////////////////////////////////////////////////////// + +extern "system" { + fn getaddrinfo(node: *const c_char, service: *const c_char, + hints: *const libc::addrinfo, + res: *mut *mut libc::addrinfo) -> c_int; + fn freeaddrinfo(res: *mut libc::addrinfo); +} + +pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, + hint: Option) + -> Result, IoError> +{ unimplemented!() } + +//////////////////////////////////////////////////////////////////////////////// +// Timeout helpers +// +// The read/write functions below are the helpers for reading/writing a socket +// with a possible deadline specified. This is generally viewed as a timed out +// I/O operation. +// +// From the application's perspective, timeouts apply to the I/O object, not to +// the underlying file descriptor (it's one timeout per object). This means that +// we can't use the SO_RCVTIMEO and corresponding send timeout option. +// +// The next idea to implement timeouts would be to use nonblocking I/O. An +// invocation of select() would wait (with a timeout) for a socket to be ready. +// Once its ready, we can perform the operation. Note that the operation *must* +// be nonblocking, even though select() says the socket is ready. This is +// because some other thread could have come and stolen our data (handles can be +// cloned). +// +// To implement nonblocking I/O, the first option we have is to use the +// O_NONBLOCK flag. Remember though that this is a global setting, affecting all +// I/O objects, so this was initially viewed as unwise. +// +// It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to +// send/recv, but the niftiness wears off once you realize it only works well on +// Linux [1] [2]. This means that it's pretty easy to get a nonblocking +// operation on Linux (no flag fiddling, no affecting other objects), but not on +// other platforms. +// +// To work around this constraint on other platforms, we end up using the +// original strategy of flipping the O_NONBLOCK flag. As mentioned before, this +// could cause other objects' blocking operations to suddenly become +// nonblocking. To get around this, a "blocking operation" which returns EAGAIN +// falls back to using the same code path as nonblocking operations, but with an +// infinite timeout (select + send/recv). This helps emulate blocking +// reads/writes despite the underlying descriptor being nonblocking, as well as +// optimizing the fast path of just hitting one syscall in the good case. +// +// As a final caveat, this implementation uses a mutex so only one thread is +// doing a nonblocking operation at at time. This is the operation that comes +// after the select() (at which point we think the socket is ready). This is +// done for sanity to ensure that the state of the O_NONBLOCK flag is what we +// expect (wouldn't want someone turning it on when it should be off!). All +// operations performed in the lock are *nonblocking* to avoid holding the mutex +// forever. +// +// So, in summary, Linux uses MSG_DONTWAIT and doesn't need mutexes, everyone +// else uses O_NONBLOCK and mutexes with some trickery to make sure blocking +// reads/writes are still blocking. +// +// Fun, fun! +// +// [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html +// [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait + +pub fn read(fd: sock_t, + deadline: u64, + lock: || -> T, + read: |bool| -> libc::c_int) -> IoResult { unimplemented!() } + +pub fn write(fd: sock_t, + deadline: u64, + buf: &[u8], + write_everything: bool, + lock: || -> T, + write: |bool, *const u8, uint| -> i64) -> IoResult { unimplemented!() } + +// See http://developerweb.net/viewtopic.php?id=3196 for where this is +// derived from. +pub fn connect_timeout(fd: sock_t, + addrp: *const libc::sockaddr, + len: libc::socklen_t, + timeout_ms: u64) -> IoResult<()> { unimplemented!() } + +pub fn await(fds: &[sock_t], deadline: Option, + status: SocketStatus) -> IoResult<()> { unimplemented!() } + +//////////////////////////////////////////////////////////////////////////////// +// Basic socket representation +//////////////////////////////////////////////////////////////////////////////// + +struct Inner { + fd: sock_t, + + // Unused on Linux, where this lock is not necessary. + #[allow(dead_code)] + lock: mutex::NativeMutex +} + +impl Inner { + fn new(fd: sock_t) -> Inner { unimplemented!() } +} + +impl Drop for Inner { + fn drop(&mut self) { unimplemented!() } +} + +pub struct Guard<'a> { + pub fd: sock_t, + pub guard: mutex::LockGuard<'a>, +} + +#[unsafe_destructor] +impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { unimplemented!() } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP streams +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpStream { + inner: Arc, + read_deadline: u64, + write_deadline: u64, +} + +impl TcpStream { + pub fn connect(addr: SocketAddr, timeout: Option) -> IoResult { unimplemented!() } + + pub fn new(fd: sock_t) -> TcpStream { unimplemented!() } + + pub fn fd(&self) -> sock_t { unimplemented!() } + + pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { unimplemented!() } + + pub fn set_keepalive(&mut self, seconds: Option) -> IoResult<()> { unimplemented!() } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { unimplemented!() } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { unimplemented!() } + #[cfg(not(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly")))] + fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> { unimplemented!() } + + #[cfg(target_os = "linux")] + fn lock_nonblocking(&self) { unimplemented!() } + + #[cfg(not(target_os = "linux"))] + fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } + + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + pub fn peer_name(&mut self) -> IoResult { unimplemented!() } + + pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } + pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } + + pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } + pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } + pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } + + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } +} + +impl Clone for TcpStream { + fn clone(&self) -> TcpStream { unimplemented!() } +} + +//////////////////////////////////////////////////////////////////////////////// +// UDP +//////////////////////////////////////////////////////////////////////////////// + +pub struct UdpSocket { + inner: Arc, + read_deadline: u64, + write_deadline: u64, +} + +impl UdpSocket { + pub fn bind(addr: SocketAddr) -> IoResult { unimplemented!() } + + pub fn fd(&self) -> sock_t { unimplemented!() } + + pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> { unimplemented!() } + + pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { unimplemented!() } + + pub fn set_membership(&mut self, addr: IpAddr, opt: libc::c_int) -> IoResult<()> { unimplemented!() } + + #[cfg(target_os = "linux")] + fn lock_nonblocking(&self) { unimplemented!() } + + #[cfg(not(target_os = "linux"))] + fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } + + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } + + pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { unimplemented!() } + + pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { unimplemented!() } + + pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } + pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } + + pub fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } + pub fn time_to_live(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } + + pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } + pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } + pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } +} + +impl Clone for UdpSocket { + fn clone(&self) -> UdpSocket { unimplemented!() } +} diff --git a/src/libst2/sys/common/thread_local.rs b/src/libst2/sys/common/thread_local.rs new file mode 100644 index 0000000000000..ce138f7aac43c --- /dev/null +++ b/src/libst2/sys/common/thread_local.rs @@ -0,0 +1,215 @@ +// 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. + +//! OS-based thread local storage +//! +//! This module provides an implementation of OS-based thread local storage, +//! using the native OS-provided facilities (think `TlsAlloc` or +//! `pthread_setspecific`). The interface of this differs from the other types +//! of thread-local-storage provided in this crate in that OS-based TLS can only +//! get/set pointers, +//! +//! This module also provides two flavors of TLS. One is intended for static +//! initialization, and does not contain a `Drop` implementation to deallocate +//! the OS-TLS key. The other is a type which does implement `Drop` and hence +//! has a safe interface. +//! +//! # Usage +//! +//! This module should likely not be used directly unless other primitives are +//! being built on. types such as `thread_local::scoped::Key` are likely much +//! more useful in practice than this OS-based version which likely requires +//! unsafe code to interoperate with. +//! +//! # Example +//! +//! Using a dynamically allocated TLS key. Note that this key can be shared +//! among many threads via an `Arc`. +//! +//! ```rust,ignore +//! let key = Key::new(None); +//! assert!(key.get().is_null()); +//! key.set(1 as *mut u8); +//! assert!(!key.get().is_null()); +//! +//! drop(key); // deallocate this TLS slot. +//! ``` +//! +//! Sometimes a statically allocated key is either required or easier to work +//! with, however. +//! +//! ```rust,ignore +//! static KEY: StaticKey = INIT; +//! +//! unsafe { +//! assert!(KEY.get().is_null()); +//! KEY.set(1 as *mut u8); +//! } +//! ``` + +#![allow(non_camel_case_types)] + +use prelude::*; + +use kinds::marker; +use mem; +use rustrt::exclusive::Exclusive; +use rustrt; +use sync::atomic::{mod, AtomicUint}; +use sync::{Once, ONCE_INIT}; + +use sys::thread_local as imp; + +/// A type for TLS keys that are statically allocated. +/// +/// This type is entirely `unsafe` to use as it does not protect against +/// use-after-deallocation or use-during-deallocation. +/// +/// The actual OS-TLS key is lazily allocated when this is used for the first +/// time. The key is also deallocated when the Rust runtime exits or `destroy` +/// is called, whichever comes first. +/// +/// # Example +/// +/// ```ignore +/// use tls::os::{StaticKey, INIT}; +/// +/// static KEY: StaticKey = INIT; +/// +/// unsafe { +/// assert!(KEY.get().is_null()); +/// KEY.set(1 as *mut u8); +/// } +/// ``` +pub struct StaticKey { + /// Inner static TLS key (internals), created with by `INIT_INNER` in this + /// module. + pub inner: StaticKeyInner, + /// Destructor for the TLS value. + /// + /// See `Key::new` for information about when the destructor runs and how + /// it runs. + pub dtor: Option, +} + +/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant. +pub struct StaticKeyInner { + key: AtomicUint, + nc: marker::NoCopy, +} + +/// A type for a safely managed OS-based TLS slot. +/// +/// This type allocates an OS TLS key when it is initialized and will deallocate +/// the key when it falls out of scope. When compared with `StaticKey`, this +/// type is entirely safe to use. +/// +/// Implementations will likely, however, contain unsafe code as this type only +/// operates on `*mut u8`, an unsafe pointer. +/// +/// # Example +/// +/// ```rust,ignore +/// use tls::os::Key; +/// +/// let key = Key::new(None); +/// assert!(key.get().is_null()); +/// key.set(1 as *mut u8); +/// assert!(!key.get().is_null()); +/// +/// drop(key); // deallocate this TLS slot. +/// ``` +pub struct Key { + key: imp::Key, +} + +/// Constant initialization value for static TLS keys. +/// +/// This value specifies no destructor by default. +pub const INIT: StaticKey = StaticKey { + inner: INIT_INNER, + dtor: None, +}; + +/// Constant initialization value for the inner part of static TLS keys. +/// +/// This value allows specific configuration of the destructor for a TLS key. +pub const INIT_INNER: StaticKeyInner = StaticKeyInner { + key: atomic::INIT_ATOMIC_UINT, + nc: marker::NoCopy, +}; + +static INIT_KEYS: Once = ONCE_INIT; +static mut KEYS: *mut Exclusive> = 0 as *mut _; + +impl StaticKey { + /// Gets the value associated with this TLS key + /// + /// This will lazily allocate a TLS key from the OS if one has not already + /// been allocated. + #[inline] + pub unsafe fn get(&self) -> *mut u8 { unimplemented!() } + + /// Sets this TLS key to a new value. + /// + /// This will lazily allocate a TLS key from the OS if one has not already + /// been allocated. + #[inline] + pub unsafe fn set(&self, val: *mut u8) { unimplemented!() } + + /// Deallocates this OS TLS key. + /// + /// This function is unsafe as there is no guarantee that the key is not + /// currently in use by other threads or will not ever be used again. + /// + /// Note that this does *not* run the user-provided destructor if one was + /// specified at definition time. Doing so must be done manually. + pub unsafe fn destroy(&self) { unimplemented!() } + + #[inline] + unsafe fn key(&self) -> imp::Key { unimplemented!() } + + unsafe fn lazy_init(&self) -> uint { unimplemented!() } +} + +impl Key { + /// Create a new managed OS TLS key. + /// + /// This key will be deallocated when the key falls out of scope. + /// + /// The argument provided is an optionally-specified destructor for the + /// value of this TLS key. When a thread exits and the value for this key + /// is non-null the destructor will be invoked. The TLS value will be reset + /// to null before the destructor is invoked. + /// + /// Note that the destructor will not be run when the `Key` goes out of + /// scope. + #[inline] + pub fn new(dtor: Option) -> Key { unimplemented!() } + + /// See StaticKey::get + #[inline] + pub fn get(&self) -> *mut u8 { unimplemented!() } + + /// See StaticKey::set + #[inline] + pub fn set(&self, val: *mut u8) { unimplemented!() } +} + +impl Drop for Key { + fn drop(&mut self) { unimplemented!() } +} + +fn init_keys() { unimplemented!() } + +fn register_key(key: imp::Key) { unimplemented!() } + +fn unregister_key(key: imp::Key) { unimplemented!() } + diff --git a/src/libst2/sys/unix/c.rs b/src/libst2/sys/unix/c.rs new file mode 100644 index 0000000000000..2b9791b87fe2e --- /dev/null +++ b/src/libst2/sys/unix/c.rs @@ -0,0 +1,257 @@ +// 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. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +pub use self::select::fd_set; +pub use self::signal::{sigaction, siginfo, sigset_t}; +pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP}; +pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; + +use libc; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIONBIO: libc::c_ulong = 0x8004667e; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIONBIO: libc::c_ulong = 0x5421; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIONBIO: libc::c_ulong = 0x667e; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIOCLEX: libc::c_ulong = 0x20006601; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIOCLEX: libc::c_ulong = 0x5451; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIOCLEX: libc::c_ulong = 0x6601; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const MSG_DONTWAIT: libc::c_int = 0x80; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub const MSG_DONTWAIT: libc::c_int = 0x40; + +pub const WNOHANG: libc::c_int = 1; + +extern { + pub fn gettimeofday(timeval: *mut libc::timeval, + tzp: *mut libc::c_void) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::c_int, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_void, + optlen: *mut libc::socklen_t) -> libc::c_int; + pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; + + + pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int, + options: libc::c_int) -> libc::pid_t; + + pub fn sigaction(signum: libc::c_int, + act: *const sigaction, + oldact: *mut sigaction) -> libc::c_int; + + pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod select { + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + fds_bits: [i32, ..(FD_SETSIZE / 32)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { unimplemented!() } +} + +#[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux"))] +mod select { + use uint; + use libc; + + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + // FIXME: shouldn't this be a c_ulong? + fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { unimplemented!() } +} + +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000004; + pub const SIGCHLD: libc::c_int = 17; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_errno: libc::c_int, + si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + pub sa_flags: libc::c_ulong, + sa_restorer: *mut libc::c_void, + } + + #[repr(C)] + #[cfg(target_word_size = "32")] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } + + #[repr(C)] + #[cfg(target_word_size = "64")] + pub struct sigset_t { + __val: [libc::c_ulong, ..16], + } +} + +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000008; + pub const SIGCHLD: libc::c_int = 18; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_code: libc::c_int, + si_errno: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_flags: libc::c_uint, + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + sa_restorer: *mut libc::c_void, + sa_resv: [libc::c_int, ..1], + } + + #[repr(C)] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } +} + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +mod signal { + use libc; + + pub const SA_ONSTACK: libc::c_int = 0x0001; + pub const SA_RESTART: libc::c_int = 0x0002; + pub const SA_RESETHAND: libc::c_int = 0x0004; + pub const SA_NOCLDSTOP: libc::c_int = 0x0008; + pub const SA_NODEFER: libc::c_int = 0x0010; + pub const SA_NOCLDWAIT: libc::c_int = 0x0020; + pub const SA_SIGINFO: libc::c_int = 0x0040; + pub const SIGCHLD: libc::c_int = 20; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub type sigset_t = u32; + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[repr(C)] + pub struct sigset_t { + bits: [u32, ..4], + } + + // This structure has more fields, but we're not all that interested in + // them. + #[repr(C)] + pub struct siginfo { + pub si_signo: libc::c_int, + pub si_errno: libc::c_int, + pub si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_flags: libc::c_int, + pub sa_mask: sigset_t, + } +} diff --git a/src/libst2/sys/unix/fs.rs b/src/libst2/sys/unix/fs.rs new file mode 100644 index 0000000000000..08286313cc1e4 --- /dev/null +++ b/src/libst2/sys/unix/fs.rs @@ -0,0 +1,95 @@ +// Copyright 2013-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. + +//! Blocking posix-based file I/O + +use libc::{mod, c_int, c_void}; +use c_str::CString; +use mem; +use io; + +use prelude::*; + +use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; +use io::{IoResult, FileStat, SeekStyle, Reader}; +use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; +use result::{Ok, Err}; +use sys::retry; +use sys_common::{keep_going, eof, mkerr_libc}; + +pub use path::PosixPath as Path; + +pub type fd_t = libc::c_int; + +pub struct FileDesc { + /// The underlying C file descriptor. + fd: fd_t, + + /// Whether to close the file descriptor on drop. + close_on_drop: bool, +} + +impl FileDesc { + pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { unimplemented!() } + + pub fn read(&self, buf: &mut [u8]) -> IoResult { unimplemented!() } + pub fn write(&self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + pub fn fd(&self) -> fd_t { unimplemented!() } + + pub fn seek(&self, pos: i64, whence: SeekStyle) -> IoResult { unimplemented!() } + + pub fn tell(&self) -> IoResult { unimplemented!() } + + pub fn fsync(&self) -> IoResult<()> { unimplemented!() } + + pub fn datasync(&self) -> IoResult<()> { unimplemented!() } + + pub fn truncate(&self, offset: i64) -> IoResult<()> { unimplemented!() } + + pub fn fstat(&self) -> IoResult { unimplemented!() } + + /// Extract the actual filedescriptor without closing it. + pub fn unwrap(self) -> fd_t { unimplemented!() } +} + +impl Drop for FileDesc { + fn drop(&mut self) { unimplemented!() } +} + +pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { unimplemented!() } + +pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { unimplemented!() } + +pub fn readdir(p: &Path) -> IoResult> { unimplemented!() } + +pub fn unlink(p: &Path) -> IoResult<()> { unimplemented!() } + +pub fn rename(old: &Path, new: &Path) -> IoResult<()> { unimplemented!() } + +pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { unimplemented!() } + +pub fn rmdir(p: &Path) -> IoResult<()> { unimplemented!() } + +pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { unimplemented!() } + +pub fn readlink(p: &Path) -> IoResult { unimplemented!() } + +pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } + +pub fn link(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } + +fn mkstat(stat: &libc::stat) -> FileStat { unimplemented!() } + +pub fn stat(p: &Path) -> IoResult { unimplemented!() } + +pub fn lstat(p: &Path) -> IoResult { unimplemented!() } + +pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { unimplemented!() } diff --git a/src/libst2/sys/unix/helper_signal.rs b/src/libst2/sys/unix/helper_signal.rs new file mode 100644 index 0000000000000..e677012cb018f --- /dev/null +++ b/src/libst2/sys/unix/helper_signal.rs @@ -0,0 +1,22 @@ +// 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. + +use libc; +use os; + +use sys::fs::FileDesc; + +pub type signal = libc::c_int; + +pub fn new() -> (signal, signal) { unimplemented!() } + +pub fn signal(fd: libc::c_int) { unimplemented!() } + +pub fn close(fd: libc::c_int) { unimplemented!() } diff --git a/src/libst2/sys/unix/mod.rs b/src/libst2/sys/unix/mod.rs new file mode 100644 index 0000000000000..140f3b84142c7 --- /dev/null +++ b/src/libst2/sys/unix/mod.rs @@ -0,0 +1,82 @@ +// 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. + +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(unused_imports)] +#![allow(dead_code)] +#![allow(unused_unsafe)] +#![allow(unused_mut)] + +extern crate libc; + +use num; +use num::{Int, SignedInt}; +use prelude::*; +use io::{mod, IoResult, IoError}; +use sys_common::mkerr_libc; + +macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( + static $name: Helper<$m> = Helper { + lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + }; +) ) + +pub mod c; +pub mod fs; +pub mod helper_signal; +pub mod os; +pub mod pipe; +pub mod process; +pub mod tcp; +pub mod timer; +pub mod thread_local; +pub mod tty; +pub mod udp; + +pub mod addrinfo { + pub use sys_common::net::get_host_addresses; +} + +// FIXME: move these to c module +pub type sock_t = self::fs::fd_t; +pub type wrlen = libc::size_t; +pub type msglen_t = libc::size_t; +pub unsafe fn close_sock(sock: sock_t) { unimplemented!() } + +pub fn last_error() -> IoError { unimplemented!() } + +pub fn last_net_error() -> IoError { unimplemented!() } + +extern "system" { + fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; +} + +pub fn last_gai_error(s: libc::c_int) -> IoError { unimplemented!() } + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { unimplemented!() } + +pub fn decode_error_detailed(errno: i32) -> IoError { unimplemented!() } + +#[inline] +pub fn retry (f: || -> T) -> T { unimplemented!() } + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { unimplemented!() } + +pub fn wouldblock() -> bool { unimplemented!() } + +pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { unimplemented!() } + +// nothing needed on unix platforms +pub fn init_net() { unimplemented!() } diff --git a/src/libst2/sys/unix/os.rs b/src/libst2/sys/unix/os.rs new file mode 100644 index 0000000000000..1fc855ceea0be --- /dev/null +++ b/src/libst2/sys/unix/os.rs @@ -0,0 +1,25 @@ +// 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. + +use libc; +use libc::{c_int, c_char}; +use prelude::*; +use io::IoResult; +use sys::fs::FileDesc; + +use os::TMPBUF_SZ; + +/// Returns the platform-specific value of errno +pub fn errno() -> int { unimplemented!() } + +/// Get a detailed string description for the given error number +pub fn error_string(errno: i32) -> String { unimplemented!() } + +pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { unimplemented!() } diff --git a/src/libst2/sys/unix/pipe.rs b/src/libst2/sys/unix/pipe.rs new file mode 100644 index 0000000000000..7f09e8bbc0505 --- /dev/null +++ b/src/libst2/sys/unix/pipe.rs @@ -0,0 +1,140 @@ +// 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. + +use alloc::arc::Arc; +use libc; +use c_str::CString; +use mem; +use rustrt::mutex; +use sync::atomic; +use io::{mod, IoResult, IoError}; +use prelude::*; + +use sys::{mod, timer, retry, c, set_nonblocking, wouldblock}; +use sys::fs::{fd_t, FileDesc}; +use sys_common::net::*; +use sys_common::{eof, mkerr_libc}; + +fn unix_socket(ty: libc::c_int) -> IoResult { unimplemented!() } + +fn addr_to_sockaddr_un(addr: &CString, + storage: &mut libc::sockaddr_storage) + -> IoResult { unimplemented!() } + +struct Inner { + fd: fd_t, + + // Unused on Linux, where this lock is not necessary. + #[allow(dead_code)] + lock: mutex::NativeMutex +} + +impl Inner { + fn new(fd: fd_t) -> Inner { unimplemented!() } +} + +impl Drop for Inner { + fn drop(&mut self) { unimplemented!() } +} + +fn connect(addr: &CString, ty: libc::c_int, + timeout: Option) -> IoResult { unimplemented!() } + +fn bind(addr: &CString, ty: libc::c_int) -> IoResult { unimplemented!() } + +//////////////////////////////////////////////////////////////////////////////// +// Unix Streams +//////////////////////////////////////////////////////////////////////////////// + +pub struct UnixStream { + inner: Arc, + read_deadline: u64, + write_deadline: u64, +} + +impl UnixStream { + pub fn connect(addr: &CString, + timeout: Option) -> IoResult { unimplemented!() } + + fn new(inner: Arc) -> UnixStream { unimplemented!() } + + fn fd(&self) -> fd_t { unimplemented!() } + + #[cfg(target_os = "linux")] + fn lock_nonblocking(&self) { unimplemented!() } + + #[cfg(not(target_os = "linux"))] + fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } + + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + + pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } + + pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } + + pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } + + pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } + + pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } +} + +impl Clone for UnixStream { + fn clone(&self) -> UnixStream { unimplemented!() } +} + +//////////////////////////////////////////////////////////////////////////////// +// Unix Listener +//////////////////////////////////////////////////////////////////////////////// + +pub struct UnixListener { + inner: Inner, + path: CString, +} + +impl UnixListener { + pub fn bind(addr: &CString) -> IoResult { unimplemented!() } + + fn fd(&self) -> fd_t { unimplemented!() } + + pub fn listen(self) -> IoResult { unimplemented!() } +} + +pub struct UnixAcceptor { + inner: Arc, + deadline: u64, +} + +struct AcceptorInner { + listener: UnixListener, + reader: FileDesc, + writer: FileDesc, + closed: atomic::AtomicBool, +} + +impl UnixAcceptor { + fn fd(&self) -> fd_t { unimplemented!() } + + pub fn accept(&mut self) -> IoResult { unimplemented!() } + + pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } + + pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Clone for UnixAcceptor { + fn clone(&self) -> UnixAcceptor { unimplemented!() } +} + +impl Drop for UnixListener { + fn drop(&mut self) { unimplemented!() } +} diff --git a/src/libst2/sys/unix/process.rs b/src/libst2/sys/unix/process.rs new file mode 100644 index 0000000000000..7734b3a9fdf9b --- /dev/null +++ b/src/libst2/sys/unix/process.rs @@ -0,0 +1,69 @@ +// 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. +use self::Req::*; + +use libc::{mod, pid_t, c_void, c_int}; +use c_str::CString; +use io::{mod, IoResult, IoError}; +use mem; +use os; +use ptr; +use prelude::*; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use collections; +use path::BytesContainer; +use hash::Hash; + +use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval}; +use sys::fs::FileDesc; +use sys_common::helper_thread::Helper; +use sys_common::{AsFileDesc, mkerr_libc, timeout}; + +pub use sys_common::ProcessConfig; + +helper_init!(static HELPER: Helper) + +/// The unique id of the process (this should never be negative). +pub struct Process { + pub pid: pid_t +} + +enum Req { + NewChild(libc::pid_t, Sender, u64), +} + +impl Process { + pub fn id(&self) -> pid_t { unimplemented!() } + + pub unsafe fn kill(&self, signal: int) -> IoResult<()> { unimplemented!() } + + pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { unimplemented!() } + + pub fn spawn(cfg: &C, in_fd: Option

, + out_fd: Option

, err_fd: Option

) + -> IoResult + where C: ProcessConfig, P: AsFileDesc, + K: BytesContainer + Eq + Hash, V: BytesContainer + { unimplemented!() } + + pub fn wait(&self, deadline: u64) -> IoResult { unimplemented!() } + + pub fn try_wait(&self) -> Option { unimplemented!() } +} + +fn with_argv(prog: &CString, args: &[CString], + cb: proc(*const *const libc::c_char) -> T) -> T { unimplemented!() } + +fn with_envp(env: Option<&collections::HashMap>, + cb: proc(*const c_void) -> T) -> T + where K: BytesContainer + Eq + Hash, V: BytesContainer +{ unimplemented!() } + +fn translate_status(status: c_int) -> ProcessExit { unimplemented!() } diff --git a/src/libst2/sys/unix/tcp.rs b/src/libst2/sys/unix/tcp.rs new file mode 100644 index 0000000000000..7f6236dcad975 --- /dev/null +++ b/src/libst2/sys/unix/tcp.rs @@ -0,0 +1,71 @@ +// 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. + +use io::net::ip; +use io::IoResult; +use libc; +use mem; +use ptr; +use prelude::*; +use super::{last_error, last_net_error, retry, sock_t}; +use sync::{Arc, atomic}; +use sys::fs::FileDesc; +use sys::{set_nonblocking, wouldblock}; +use sys; +use sys_common; +use sys_common::net::*; + +pub use sys_common::net::TcpStream; + +//////////////////////////////////////////////////////////////////////////////// +// TCP listeners +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpListener { + pub inner: FileDesc, +} + +impl TcpListener { + pub fn bind(addr: ip::SocketAddr) -> IoResult { unimplemented!() } + + pub fn fd(&self) -> sock_t { unimplemented!() } + + pub fn listen(self, backlog: int) -> IoResult { unimplemented!() } + + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } +} + +pub struct TcpAcceptor { + inner: Arc, + deadline: u64, +} + +struct AcceptorInner { + listener: TcpListener, + reader: FileDesc, + writer: FileDesc, + closed: atomic::AtomicBool, +} + +impl TcpAcceptor { + pub fn fd(&self) -> sock_t { unimplemented!() } + + pub fn accept(&mut self) -> IoResult { unimplemented!() } + + pub fn socket_name(&mut self) -> IoResult { unimplemented!() } + + pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } + + pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } +} + +impl Clone for TcpAcceptor { + fn clone(&self) -> TcpAcceptor { unimplemented!() } +} diff --git a/src/libst2/sys/unix/thread_local.rs b/src/libst2/sys/unix/thread_local.rs new file mode 100644 index 0000000000000..d507efbdebf5a --- /dev/null +++ b/src/libst2/sys/unix/thread_local.rs @@ -0,0 +1,40 @@ +// 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. + +use prelude::*; +use libc::c_int; + +pub type Key = pthread_key_t; + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { unimplemented!() } + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { unimplemented!() } + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { unimplemented!() } + +#[inline] +pub unsafe fn destroy(key: Key) { unimplemented!() } + +#[cfg(target_os = "macos")] +type pthread_key_t = ::libc::c_ulong; + +#[cfg(not(target_os = "macos"))] +type pthread_key_t = ::libc::c_uint; + +extern { + fn pthread_key_create(key: *mut pthread_key_t, + dtor: Option) -> c_int; + fn pthread_key_delete(key: pthread_key_t) -> c_int; + fn pthread_getspecific(key: pthread_key_t) -> *mut u8; + fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int; +} diff --git a/src/libst2/sys/unix/timer.rs b/src/libst2/sys/unix/timer.rs new file mode 100644 index 0000000000000..11b46793d9d1b --- /dev/null +++ b/src/libst2/sys/unix/timer.rs @@ -0,0 +1,110 @@ +// Copyright 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. + +//! Timers for non-Linux/non-Windows OSes +//! +//! This module implements timers with a worker thread, select(), and a lot of +//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate +//! part is that I'm at a loss of what else to do one these OSes. This is also +//! why Linux has a specialized timerfd implementation and windows has its own +//! implementation (they're more accurate than this one). +//! +//! The basic idea is that there is a worker thread that's communicated to via a +//! channel and a pipe, the pipe is used by the worker thread in a select() +//! syscall with a timeout. The timeout is the "next timer timeout" while the +//! channel is used to send data over to the worker thread. +//! +//! Whenever the call to select() times out, then a channel receives a message. +//! Whenever the call returns that the file descriptor has information, then the +//! channel from timers is drained, enqueuing all incoming requests. +//! +//! The actual implementation of the helper thread is a sorted array of +//! timers in terms of target firing date. The target is the absolute time at +//! which the timer should fire. Timers are then re-enqueued after a firing if +//! the repeat boolean is set. +//! +//! Naturally, all this logic of adding times and keeping track of +//! relative/absolute time is a little lossy and not quite exact. I've done the +//! best I could to reduce the amount of calls to 'now()', but there's likely +//! still inaccuracies trickling in here and there. +//! +//! One of the tricky parts of this implementation is that whenever a timer is +//! acted upon, it must cancel whatever the previous action was (if one is +//! active) in order to act like the other implementations of this timer. In +//! order to do this, the timer's inner pointer is transferred to the worker +//! thread. Whenever the timer is modified, it first takes ownership back from +//! the worker thread in order to modify the same data structure. This has the +//! side effect of "cancelling" the previous requests while allowing a +//! re-enqueuing later on. +//! +//! Note that all time units in this file are in *milliseconds*. + +pub use self::Req::*; + +use libc; +use mem; +use os; +use ptr; +use sync::atomic; +use comm; +use sys::c; +use sys::fs::FileDesc; +use sys_common::helper_thread::Helper; +use prelude::*; +use io::IoResult; + +helper_init!(static HELPER: Helper) + +pub trait Callback { + fn call(&mut self); +} + +pub struct Timer { + id: uint, + inner: Option>, +} + +pub struct Inner { + cb: Option>, + interval: u64, + repeat: bool, + target: u64, + id: uint, +} + +pub enum Req { + // Add a new timer to the helper thread. + NewTimer(Box), + + // Remove a timer based on its id and then send it back on the channel + // provided + RemoveTimer(uint, Sender>), +} + +// returns the current time (in milliseconds) +pub fn now() -> u64 { unimplemented!() } + +fn helper(input: libc::c_int, messages: Receiver, _: ()) { unimplemented!() } + +impl Timer { + pub fn new() -> IoResult { unimplemented!() } + + pub fn sleep(&mut self, ms: u64) { unimplemented!() } + + pub fn oneshot(&mut self, msecs: u64, cb: Box) { unimplemented!() } + + pub fn period(&mut self, msecs: u64, cb: Box) { unimplemented!() } + + fn inner(&mut self) -> Box { unimplemented!() } +} + +impl Drop for Timer { + fn drop(&mut self) { unimplemented!() } +} diff --git a/src/libst2/sys/unix/tty.rs b/src/libst2/sys/unix/tty.rs new file mode 100644 index 0000000000000..917b947586ba2 --- /dev/null +++ b/src/libst2/sys/unix/tty.rs @@ -0,0 +1,29 @@ +// 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. + +use sys::fs::FileDesc; +use prelude::*; +use libc::{mod, c_int}; +use io::{mod, IoResult, IoError}; +use sys_common; + +pub struct TTY { + pub fd: FileDesc, +} + +impl TTY { + pub fn new(fd: c_int) -> IoResult { unimplemented!() } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } + pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> { unimplemented!() } + pub fn get_winsize(&mut self) -> IoResult<(int, int)> { unimplemented!() } + pub fn isatty(&self) -> bool { unimplemented!() } +} diff --git a/src/libst2/sys/unix/udp.rs b/src/libst2/sys/unix/udp.rs new file mode 100644 index 0000000000000..50f8fb828ad32 --- /dev/null +++ b/src/libst2/sys/unix/udp.rs @@ -0,0 +1,11 @@ +// 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. + +pub use sys_common::net::UdpSocket; diff --git a/src/libst2/sys/windows/c.rs b/src/libst2/sys/windows/c.rs new file mode 100644 index 0000000000000..b8e9b1dca3abc --- /dev/null +++ b/src/libst2/sys/windows/c.rs @@ -0,0 +1,250 @@ +// 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. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(overflowing_literals)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use libc; +use prelude::*; + +pub const WSADESCRIPTION_LEN: uint = 256; +pub const WSASYS_STATUS_LEN: uint = 128; +pub const FIONBIO: libc::c_long = 0x8004667e; +pub const FD_SETSIZE: uint = 64; +pub const MSG_DONTWAIT: libc::c_int = 0; +pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582; +pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4; +pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80; +pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20; +pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2; +pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1; +pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40; +pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; + +pub const FD_ACCEPT: libc::c_long = 0x08; +pub const FD_MAX_EVENTS: uint = 10; +pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; +pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; +pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; +pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; + +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, +} +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], +} + +pub type LPWSADATA = *mut WSADATA; + +#[repr(C)] +pub struct WSANETWORKEVENTS { + pub lNetworkEvents: libc::c_long, + pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS], +} + +pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; + +pub type WSAEVENT = libc::HANDLE; + +#[repr(C)] +pub struct fd_set { + fd_count: libc::c_uint, + fd_array: [libc::SOCKET, ..FD_SETSIZE], +} + +pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) { + set.fd_array[set.fd_count as uint] = s; + set.fd_count += 1; +} + +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: libc::WORD, + lpWSAData: LPWSADATA) -> libc::c_int; + pub fn WSAGetLastError() -> libc::c_int; + pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSACreateEvent() -> WSAEVENT; + pub fn WSAEventSelect(s: libc::SOCKET, + hEventObject: WSAEVENT, + lNetworkEvents: libc::c_long) -> libc::c_int; + pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD, + lphEvents: *const WSAEVENT, + fWaitAll: libc::BOOL, + dwTimeout: libc::DWORD, + fAltertable: libc::BOOL) -> libc::DWORD; + pub fn WSAEnumNetworkEvents(s: libc::SOCKET, + hEventObject: WSAEVENT, + lpNetworkEvents: LPWSANETWORKEVENTS) + -> libc::c_int; + + pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, + argp: *mut libc::c_ulong) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::SOCKET, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_char, + optlen: *mut libc::c_int) -> libc::c_int; + + pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL; + pub fn WaitForMultipleObjects(nCount: libc::DWORD, + lpHandles: *const libc::HANDLE, + bWaitAll: libc::BOOL, + dwMilliseconds: libc::DWORD) -> libc::DWORD; + + pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; + pub fn CancelIoEx(hFile: libc::HANDLE, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; +} + +pub mod compat { + use intrinsics::{atomic_store_relaxed, transmute}; + use iter::Iterator; + use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; + use prelude::*; + + extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; + } + + // store_func() is idempotent, so using relaxed ordering for the atomics + // should be enough. This way, calling a function in this compatibility + // layer (after it's loaded) shouldn't be any slower than a regular DLL + // call. + unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { + let mut module: Vec = module.utf16_units().collect(); + module.push(0); + symbol.with_c_str(|symbol| { + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol)); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func + }) + }) + } + + /// Macro for creating a compatibility fallback for a Windows function + /// + /// # Example + /// ``` + /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { + /// // Fallback implementation + /// }) + /// ``` + /// + /// Note that arguments unused by the fallback implementation should not be called `_` as + /// they are used to be passed to the real function if available. + macro_rules! compat_fn( + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty $fallback:block) => ( + #[inline(always)] + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; + + extern "system" fn thunk($($argname: $argtype),*) -> $rettype { + unsafe { + ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint, + stringify!($module), + stringify!($symbol), + fallback as uint); + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + } + + extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback + + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + ); + + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( + compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) + ) + ) + + /// Compatibility layer for functions in `kernel32.dll` + /// + /// Latest versions of Windows this is needed for: + /// + /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 + /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 + pub mod kernel32 { + use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; + use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; + + extern "system" { + fn SetLastError(dwErrCode: DWORD); + } + + compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + + compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + } +} + +extern "system" { + // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL + pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, + lpBuffer: libc::LPVOID, + nNumberOfCharsToRead: libc::DWORD, + lpNumberOfCharsRead: libc::LPDWORD, + pInputControl: libc::LPVOID) -> libc::BOOL; + + pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE, + lpBuffer: libc::types::os::arch::extra::LPCVOID, + nNumberOfCharsToWrite: libc::DWORD, + lpNumberOfCharsWritten: libc::LPDWORD, + lpReserved: libc::LPVOID) -> libc::BOOL; + + pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::LPDWORD) -> libc::BOOL; + + pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::DWORD) -> libc::BOOL; +} diff --git a/src/libst2/sys/windows/fs.rs b/src/libst2/sys/windows/fs.rs new file mode 100644 index 0000000000000..b881eb2d4955c --- /dev/null +++ b/src/libst2/sys/windows/fs.rs @@ -0,0 +1,460 @@ +// 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. + +//! Blocking Windows-based file I/O + +use alloc::arc::Arc; +use libc::{mod, c_int}; + +use c_str::CString; +use mem; +use os::windows::fill_utf16_buf_and_decode; +use path; +use ptr; +use str; +use io; + +use prelude::*; +use sys; +use sys_common::{keep_going, eof, mkerr_libc}; + +use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; +use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; +use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; + +pub use path::WindowsPath as Path; +pub type fd_t = libc::c_int; + +pub struct FileDesc { + /// The underlying C file descriptor. + pub fd: fd_t, + + /// Whether to close the file descriptor on drop. + close_on_drop: bool, +} + +impl FileDesc { + pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { + FileDesc { fd: fd, close_on_drop: close_on_drop } + } + + pub fn read(&self, buf: &mut [u8]) -> IoResult { + let mut read = 0; + let ret = unsafe { + libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, + buf.len() as libc::DWORD, &mut read, + ptr::null_mut()) + }; + if ret != 0 { + Ok(read as uint) + } else { + Err(super::last_error()) + } + } + + pub fn write(&self, buf: &[u8]) -> IoResult<()> { + let mut cur = buf.as_ptr(); + let mut remaining = buf.len(); + while remaining > 0 { + let mut amt = 0; + let ret = unsafe { + libc::WriteFile(self.handle(), cur as libc::LPVOID, + remaining as libc::DWORD, &mut amt, + ptr::null_mut()) + }; + if ret != 0 { + remaining -= amt as uint; + cur = unsafe { cur.offset(amt as int) }; + } else { + return Err(super::last_error()) + } + } + Ok(()) + } + + pub fn fd(&self) -> fd_t { self.fd } + + pub fn handle(&self) -> libc::HANDLE { + unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE } + } + + // A version of seek that takes &self so that tell can call it + // - the private seek should of course take &mut self. + fn seek_common(&self, pos: i64, style: SeekStyle) -> IoResult { + let whence = match style { + SeekSet => libc::FILE_BEGIN, + SeekEnd => libc::FILE_END, + SeekCur => libc::FILE_CURRENT, + }; + unsafe { + let mut newpos = 0; + match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) { + 0 => Err(super::last_error()), + _ => Ok(newpos as u64), + } + } + } + + pub fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult { + self.seek_common(pos, style) + } + + pub fn tell(&self) -> IoResult { + self.seek_common(0, SeekCur) + } + + pub fn fsync(&mut self) -> IoResult<()> { + super::mkerr_winbool(unsafe { + libc::FlushFileBuffers(self.handle()) + }) + } + + pub fn datasync(&mut self) -> IoResult<()> { return self.fsync(); } + + pub fn truncate(&mut self, offset: i64) -> IoResult<()> { + let orig_pos = try!(self.tell()); + let _ = try!(self.seek(offset, SeekSet)); + let ret = unsafe { + match libc::SetEndOfFile(self.handle()) { + 0 => Err(super::last_error()), + _ => Ok(()) + } + }; + let _ = self.seek(orig_pos as i64, SeekSet); + return ret; + } + + pub fn fstat(&mut self) -> IoResult { + let mut stat: libc::stat = unsafe { mem::zeroed() }; + match unsafe { libc::fstat(self.fd(), &mut stat) } { + 0 => Ok(mkstat(&stat)), + _ => Err(super::last_error()), + } + } + + /// Extract the actual filedescriptor without closing it. + pub fn unwrap(self) -> fd_t { + let fd = self.fd; + unsafe { mem::forget(self) }; + fd + } +} + +impl Drop for FileDesc { + 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 + // for this is that if an error occurs we don't actually know if the + // file descriptor was closed or not, and if we retried (for something + // like EINTR), we might close another valid file descriptor (opened + // after we closed ours. + if self.close_on_drop && self.fd > libc::STDERR_FILENO { + let n = unsafe { libc::close(self.fd) }; + if n != 0 { + println!("error {} when closing file descriptor {}", n, self.fd); + } + } + } +} + +pub fn to_utf16(s: &Path) -> IoResult> { + sys::to_utf16(s.as_str()) +} + +pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { + // Flags passed to open_osfhandle + let flags = match fm { + Open => 0, + Append => libc::O_APPEND, + Truncate => libc::O_TRUNC, + }; + let flags = match fa { + Read => flags | libc::O_RDONLY, + Write => flags | libc::O_WRONLY | libc::O_CREAT, + ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, + }; + let mut dwDesiredAccess = match fa { + Read => libc::FILE_GENERIC_READ, + Write => libc::FILE_GENERIC_WRITE, + ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE + }; + + // libuv has a good comment about this, but the basic idea is what we try to + // emulate unix semantics by enabling all sharing by allowing things such as + // deleting a file while it's still open. + let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE | + libc::FILE_SHARE_DELETE; + + let dwCreationDisposition = match (fm, fa) { + (Truncate, Read) => libc::TRUNCATE_EXISTING, + (Truncate, _) => libc::CREATE_ALWAYS, + (Open, Read) => libc::OPEN_EXISTING, + (Open, _) => libc::OPEN_ALWAYS, + (Append, Read) => { + dwDesiredAccess |= libc::FILE_APPEND_DATA; + libc::OPEN_EXISTING + } + (Append, _) => { + dwDesiredAccess &= !libc::FILE_WRITE_DATA; + dwDesiredAccess |= libc::FILE_APPEND_DATA; + libc::OPEN_ALWAYS + } + }; + + let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL; + // Compat with unix, this allows opening directories (see libuv) + dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS; + + let path = try!(to_utf16(path)); + let handle = unsafe { + libc::CreateFileW(path.as_ptr(), + dwDesiredAccess, + dwShareMode, + ptr::null_mut(), + dwCreationDisposition, + dwFlagsAndAttributes, + ptr::null_mut()) + }; + if handle == libc::INVALID_HANDLE_VALUE { + Err(super::last_error()) + } else { + let fd = unsafe { + libc::open_osfhandle(handle as libc::intptr_t, flags) + }; + if fd < 0 { + let _ = unsafe { libc::CloseHandle(handle) }; + Err(super::last_error()) + } else { + Ok(FileDesc::new(fd, true)) + } + } +} + +pub fn mkdir(p: &Path, _mode: uint) -> IoResult<()> { + let p = try!(to_utf16(p)); + super::mkerr_winbool(unsafe { + // FIXME: turn mode into something useful? #2623 + libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) + }) +} + +pub fn readdir(p: &Path) -> IoResult> { + fn prune(root: &Path, dirs: Vec) -> Vec { + dirs.into_iter().filter(|path| { + path.as_vec() != b"." && path.as_vec() != b".." + }).map(|path| root.join(path)).collect() + } + + let star = p.join("*"); + let path = try!(to_utf16(&star)); + + unsafe { + let mut wfd = mem::zeroed(); + let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd); + if find_handle != libc::INVALID_HANDLE_VALUE { + let mut paths = vec![]; + let mut more_files = 1 as libc::BOOL; + while more_files != 0 { + { + let filename = str::truncate_utf16_at_nul(&wfd.cFileName); + match String::from_utf16(filename) { + Some(filename) => paths.push(Path::new(filename)), + None => { + assert!(libc::FindClose(find_handle) != 0); + return Err(IoError { + kind: io::InvalidInput, + desc: "path was not valid UTF-16", + detail: Some(format!("path was not valid UTF-16: {}", filename)), + }) + }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring + } + } + more_files = libc::FindNextFileW(find_handle, &mut wfd); + } + assert!(libc::FindClose(find_handle) != 0); + Ok(prune(p, paths)) + } else { + Err(super::last_error()) + } + } +} + +pub fn unlink(p: &Path) -> IoResult<()> { + fn do_unlink(p_utf16: &Vec) -> IoResult<()> { + super::mkerr_winbool(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) }) + } + + let p_utf16 = try!(to_utf16(p)); + let res = do_unlink(&p_utf16); + match res { + Ok(()) => Ok(()), + Err(e) => { + // FIXME: change the code below to use more direct calls + // than `stat` and `chmod`, to avoid re-conversion to + // utf16 etc. + + // On unix, a readonly file can be successfully removed. On windows, + // however, it cannot. To keep the two platforms in line with + // respect to their behavior, catch this case on windows, attempt to + // change it to read-write, and then remove the file. + if e.kind == io::PermissionDenied { + let stat = match stat(p) { + Ok(stat) => stat, + Err(..) => return Err(e), + }; + if stat.perm.intersects(io::USER_WRITE) { return Err(e) } + + match chmod(p, (stat.perm | io::USER_WRITE).bits() as uint) { + Ok(()) => do_unlink(&p_utf16), + Err(..) => { + // Try to put it back as we found it + let _ = chmod(p, stat.perm.bits() as uint); + Err(e) + } + } + } else { + Err(e) + } + } + } +} + +pub fn rename(old: &Path, new: &Path) -> IoResult<()> { + let old = try!(to_utf16(old)); + let new = try!(to_utf16(new)); + super::mkerr_winbool(unsafe { + libc::MoveFileExW(old.as_ptr(), new.as_ptr(), libc::MOVEFILE_REPLACE_EXISTING) + }) +} + +pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { + let p = try!(to_utf16(p)); + mkerr_libc(unsafe { + libc::wchmod(p.as_ptr(), mode as libc::c_int) + }) +} + +pub fn rmdir(p: &Path) -> IoResult<()> { + let p = try!(to_utf16(p)); + mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) }) +} + +pub fn chown(_p: &Path, _uid: int, _gid: int) -> IoResult<()> { + // libuv has this as a no-op, so seems like this should as well? + Ok(()) +} + +pub fn readlink(p: &Path) -> IoResult { + // FIXME: I have a feeling that this reads intermediate symlinks as well. + use sys::c::compat::kernel32::GetFinalPathNameByHandleW; + let p = try!(to_utf16(p)); + let handle = unsafe { + libc::CreateFileW(p.as_ptr(), + libc::GENERIC_READ, + libc::FILE_SHARE_READ, + ptr::null_mut(), + libc::OPEN_EXISTING, + libc::FILE_ATTRIBUTE_NORMAL, + ptr::null_mut()) + }; + if handle == libc::INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + // Specify (sz - 1) because the documentation states that it's the size + // without the null pointer + let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe { + GetFinalPathNameByHandleW(handle, + buf as *const u16, + sz - 1, + libc::VOLUME_NAME_DOS) + }); + let ret = match ret { + Some(ref s) if s.as_slice().starts_with(r"\\?\") => { // " + Ok(Path::new(s.as_slice().slice_from(4))) + } + Some(s) => Ok(Path::new(s)), + None => Err(super::last_error()), + }; + assert!(unsafe { libc::CloseHandle(handle) } != 0); + return ret; +} + +pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { + use sys::c::compat::kernel32::CreateSymbolicLinkW; + let src = try!(to_utf16(src)); + let dst = try!(to_utf16(dst)); + super::mkerr_winbool(unsafe { + CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL + }) +} + +pub fn link(src: &Path, dst: &Path) -> IoResult<()> { + let src = try!(to_utf16(src)); + let dst = try!(to_utf16(dst)); + super::mkerr_winbool(unsafe { + libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) + }) +} + +fn mkstat(stat: &libc::stat) -> FileStat { + FileStat { + size: stat.st_size as u64, + kind: match (stat.st_mode as libc::c_int) & libc::S_IFMT { + libc::S_IFREG => io::TypeFile, + libc::S_IFDIR => io::TypeDirectory, + libc::S_IFIFO => io::TypeNamedPipe, + libc::S_IFBLK => io::TypeBlockSpecial, + libc::S_IFLNK => io::TypeSymlink, + _ => io::TypeUnknown, + }, + perm: FilePermission::from_bits_truncate(stat.st_mode as u32), + created: stat.st_ctime as u64, + modified: stat.st_mtime as u64, + accessed: stat.st_atime as u64, + unstable: UnstableFileStat { + device: stat.st_dev as u64, + inode: stat.st_ino as u64, + rdev: stat.st_rdev as u64, + nlink: stat.st_nlink as u64, + uid: stat.st_uid as u64, + gid: stat.st_gid as u64, + blksize:0, + blocks: 0, + flags: 0, + gen: 0, + }, + } +} + +pub fn stat(p: &Path) -> IoResult { + let mut stat: libc::stat = unsafe { mem::zeroed() }; + let p = try!(to_utf16(p)); + match unsafe { libc::wstat(p.as_ptr(), &mut stat) } { + 0 => Ok(mkstat(&stat)), + _ => Err(super::last_error()), + } +} + +// FIXME: move this to platform-specific modules (for now)? +pub fn lstat(_p: &Path) -> IoResult { + // FIXME: implementation is missing + Err(super::unimpl()) +} + +pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { + let mut buf = libc::utimbuf { + actime: atime as libc::time64_t, + modtime: mtime as libc::time64_t, + }; + let p = try!(to_utf16(p)); + mkerr_libc(unsafe { + libc::wutime(p.as_ptr(), &mut buf) + }) +} diff --git a/src/libst2/sys/windows/helper_signal.rs b/src/libst2/sys/windows/helper_signal.rs new file mode 100644 index 0000000000000..c547c79e83a13 --- /dev/null +++ b/src/libst2/sys/windows/helper_signal.rs @@ -0,0 +1,38 @@ +// 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. + +use libc::{mod, BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle}; +use ptr; + +pub type signal = HANDLE; + +pub fn new() -> (HANDLE, HANDLE) { + unsafe { + let handle = CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE, + ptr::null()); + (handle, handle) + } +} + +pub fn signal(handle: HANDLE) { + assert!(unsafe { SetEvent(handle) != 0 }); +} + +pub fn close(handle: HANDLE) { + assert!(unsafe { CloseHandle(handle) != 0 }); +} + +extern "system" { + fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + bInitialState: BOOL, + lpName: LPCSTR) -> HANDLE; + fn SetEvent(hEvent: HANDLE) -> BOOL; +} diff --git a/src/libst2/sys/windows/mod.rs b/src/libst2/sys/windows/mod.rs new file mode 100644 index 0000000000000..b627ab0f7c747 --- /dev/null +++ b/src/libst2/sys/windows/mod.rs @@ -0,0 +1,85 @@ +// 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. + +#![allow(missing_docs)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused_imports)] +#![allow(dead_code)] +#![allow(unused_unsafe)] +#![allow(unused_mut)] + +extern crate libc; + +use num; +use mem; +use prelude::*; +use io::{mod, IoResult, IoError}; +use sync::{Once, ONCE_INIT}; + +macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( + static $name: Helper<$m> = Helper { + lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + }; +) ) + +pub mod c; +pub mod fs; +pub mod helper_signal; +pub mod os; +pub mod pipe; +pub mod process; +pub mod tcp; +pub mod thread_local; +pub mod timer; +pub mod tty; +pub mod udp; + +pub mod addrinfo { + pub use sys_common::net::get_host_addresses; +} + +// FIXME: move these to c module +pub type sock_t = libc::SOCKET; +pub type wrlen = libc::c_int; +pub type msglen_t = libc::c_int; +pub unsafe fn close_sock(sock: sock_t) { unimplemented!() } + +// windows has zero values as errors +fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { unimplemented!() } + +pub fn last_error() -> IoError { unimplemented!() } + +pub fn last_net_error() -> IoError { unimplemented!() } + +pub fn last_gai_error(_errno: i32) -> IoError { unimplemented!() } + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { unimplemented!() } + +pub fn decode_error_detailed(errno: i32) -> IoError { unimplemented!() } + +#[inline] +pub fn retry (f: || -> I) -> I { unimplemented!() } // PR rust-lang/rust/#17020 + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { unimplemented!() } + +pub fn wouldblock() -> bool { unimplemented!() } + +pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { unimplemented!() } + +pub fn init_net() { unimplemented!() } + +pub fn unimpl() -> IoError { unimplemented!() } + +pub fn to_utf16(s: Option<&str>) -> IoResult> { unimplemented!() } diff --git a/src/libst2/sys/windows/os.rs b/src/libst2/sys/windows/os.rs new file mode 100644 index 0000000000000..aa43b42e74643 --- /dev/null +++ b/src/libst2/sys/windows/os.rs @@ -0,0 +1,103 @@ +// 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. + +// FIXME: move various extern bindings from here into liblibc or +// something similar + +use libc; +use libc::{c_int, c_char, c_void}; +use prelude::*; +use io::{IoResult, IoError}; +use sys::fs::FileDesc; +use ptr; + +use os::TMPBUF_SZ; + +pub fn errno() -> uint { + use libc::types::os::arch::extra::DWORD; + + #[link_name = "kernel32"] + extern "system" { + fn GetLastError() -> DWORD; + } + + unsafe { + GetLastError() as uint + } +} + +/// Get a detailed string description for the given error number +pub fn error_string(errnum: i32) -> String { + use libc::types::os::arch::extra::DWORD; + use libc::types::os::arch::extra::LPWSTR; + use libc::types::os::arch::extra::LPVOID; + use libc::types::os::arch::extra::WCHAR; + + #[link_name = "kernel32"] + extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void) + -> DWORD; + } + + static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; + static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + + // This value is calculated from the macro + // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) + let langId = 0x0800 as DWORD; + + let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; + + unsafe { + let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::null_mut(), + errnum as DWORD, + langId, + buf.as_mut_ptr(), + buf.len() as DWORD, + ptr::null()); + if res == 0 { + // Sometimes FormatMessageW can fail e.g. system doesn't like langId, + let fm_err = errno(); + return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); + } + + let msg = String::from_utf16(::str::truncate_utf16_at_nul(&buf)); + match msg { + Some(msg) => format!("OS Error {}: {}", errnum, msg), + None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), + } + } +} + +pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { + // Windows pipes work subtly differently than unix pipes, and their + // inheritance has to be handled in a different way that I do not + // fully understand. Here we explicitly make the pipe non-inheritable, + // which means to pass it to a subprocess they need to be duplicated + // first, as in std::run. + let mut fds = [0, ..2]; + match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, + (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { + 0 => { + assert!(fds[0] != -1 && fds[0] != 0); + assert!(fds[1] != -1 && fds[1] != 0); + Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) + } + _ => Err(IoError::last_error()), + } +} diff --git a/src/libst2/sys/windows/pipe.rs b/src/libst2/sys/windows/pipe.rs new file mode 100644 index 0000000000000..a623c2cd8e297 --- /dev/null +++ b/src/libst2/sys/windows/pipe.rs @@ -0,0 +1,751 @@ +// 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. + +//! Named pipes implementation for windows +//! +//! If are unfortunate enough to be reading this code, I would like to first +//! apologize. This was my first encounter with windows named pipes, and it +//! didn't exactly turn out very cleanly. If you, too, are new to named pipes, +//! read on as I'll try to explain some fun things that I ran into. +//! +//! # Unix pipes vs Named pipes +//! +//! As with everything else, named pipes on windows are pretty different from +//! unix pipes on unix. On unix, you use one "server pipe" to accept new client +//! pipes. So long as this server pipe is active, new children pipes can +//! connect. On windows, you instead have a number of "server pipes", and each +//! of these server pipes can throughout their lifetime be attached to a client +//! or not. Once attached to a client, a server pipe may then disconnect at a +//! later date. +//! +//! # Accepting clients +//! +//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces +//! are built around the unix flavors. This means that we have one "server +//! pipe" to which many clients can connect. In order to make this compatible +//! with the windows model, each connected client consumes ownership of a server +//! pipe, and then a new server pipe is created for the next client. +//! +//! Note that the server pipes attached to clients are never given back to the +//! listener for recycling. This could possibly be implemented with a channel so +//! the listener half can re-use server pipes, but for now I err'd on the simple +//! side of things. Each stream accepted by a listener will destroy the server +//! pipe after the stream is dropped. +//! +//! This model ends up having a small race or two, and you can find more details +//! on the `native_accept` method. +//! +//! # Simultaneous reads and writes +//! +//! In testing, I found that two simultaneous writes and two simultaneous reads +//! on a pipe ended up working out just fine, but problems were encountered when +//! a read was executed simultaneously with a write. After some googling around, +//! it sounded like named pipes just weren't built for this kind of interaction, +//! and the suggested solution was to use overlapped I/O. +//! +//! I don't really know what overlapped I/O is, but my basic understanding after +//! reading about it is that you have an external Event which is used to signal +//! I/O completion, passed around in some OVERLAPPED structures. As to what this +//! is, I'm not exactly sure. +//! +//! This problem implies that all named pipes are created with the +//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is +//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and +//! inside of this structure is a HANDLE from CreateEvent. After the I/O is +//! determined to be pending (may complete in the future), the +//! GetOverlappedResult function is used to block on the event, waiting for the +//! I/O to finish. +//! +//! This scheme ended up working well enough. There were two snags that I ran +//! into, however: +//! +//! * Each UnixStream instance needs its own read/write events to wait on. These +//! can't be shared among clones of the same stream because the documentation +//! states that it unsets the event when the I/O is started (would possibly +//! corrupt other events simultaneously waiting). For convenience's sake, +//! these events are lazily initialized. +//! +//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition +//! to all pipes created through `connect`. Notably this means that the +//! ConnectNamedPipe function is nonblocking, implying that the Listener needs +//! to have yet another event to do the actual blocking. +//! +//! # Conclusion +//! +//! The conclusion here is that I probably don't know the best way to work with +//! windows named pipes, but the solution here seems to work well enough to get +//! the test suite passing (the suite is in libstd), and that's good enough for +//! me! + +use alloc::arc::Arc; +use libc; +use c_str::CString; +use mem; +use ptr; +use sync::atomic; +use rustrt::mutex; +use io::{mod, IoError, IoResult}; +use prelude::*; + +use sys_common::{mod, eof}; + +use super::{c, os, timer, to_utf16, decode_error_detailed}; + +struct Event(libc::HANDLE); + +impl Event { + fn new(manual_reset: bool, initial_state: bool) -> IoResult { + let event = unsafe { + libc::CreateEventW(ptr::null_mut(), + manual_reset as libc::BOOL, + initial_state as libc::BOOL, + ptr::null()) + }; + if event as uint == 0 { + Err(super::last_error()) + } else { + Ok(Event(event)) + } + } + + fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle } +} + +impl Drop for Event { + fn drop(&mut self) { + unsafe { let _ = libc::CloseHandle(self.handle()); } + } +} + +struct Inner { + handle: libc::HANDLE, + lock: mutex::NativeMutex, + read_closed: atomic::AtomicBool, + write_closed: atomic::AtomicBool, +} + +impl Inner { + fn new(handle: libc::HANDLE) -> Inner { + Inner { + handle: handle, + lock: unsafe { mutex::NativeMutex::new() }, + read_closed: atomic::AtomicBool::new(false), + write_closed: atomic::AtomicBool::new(false), + } + } +} + +impl Drop for Inner { + fn drop(&mut self) { + unsafe { + let _ = libc::FlushFileBuffers(self.handle); + let _ = libc::CloseHandle(self.handle); + } + } +} + +unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE { + libc::CreateNamedPipeW( + name, + libc::PIPE_ACCESS_DUPLEX | + if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} | + libc::FILE_FLAG_OVERLAPPED, + libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE | + libc::PIPE_WAIT, + libc::PIPE_UNLIMITED_INSTANCES, + 65536, + 65536, + 0, + ptr::null_mut() + ) +} + +pub fn await(handle: libc::HANDLE, deadline: u64, + events: &[libc::HANDLE]) -> IoResult { + use libc::consts::os::extra::{WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0}; + + // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo + // to figure out if we should indeed get the result. + let ms = if deadline == 0 { + libc::INFINITE as u64 + } else { + let now = timer::now(); + if deadline < now {0} else {deadline - now} + }; + let ret = unsafe { + c::WaitForMultipleObjects(events.len() as libc::DWORD, + events.as_ptr(), + libc::FALSE, + ms as libc::DWORD) + }; + match ret { + WAIT_FAILED => Err(super::last_error()), + WAIT_TIMEOUT => unsafe { + let _ = c::CancelIo(handle); + Err(sys_common::timeout("operation timed out")) + }, + n => Ok((n - WAIT_OBJECT_0) as uint) + } +} + +fn epipe() -> IoError { + IoError { + kind: io::EndOfFile, + desc: "the pipe has ended", + detail: None, + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Unix Streams +//////////////////////////////////////////////////////////////////////////////// + +pub struct UnixStream { + inner: Arc, + write: Option, + read: Option, + read_deadline: u64, + write_deadline: u64, +} + +impl UnixStream { + fn try_connect(p: *const u16) -> Option { + // Note that most of this is lifted from the libuv implementation. + // The idea is that if we fail to open a pipe in read/write mode + // that we try afterwards in just read or just write + let mut result = unsafe { + libc::CreateFileW(p, + libc::GENERIC_READ | libc::GENERIC_WRITE, + 0, + ptr::null_mut(), + libc::OPEN_EXISTING, + libc::FILE_FLAG_OVERLAPPED, + ptr::null_mut()) + }; + if result != libc::INVALID_HANDLE_VALUE { + return Some(result) + } + + let err = unsafe { libc::GetLastError() }; + if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { + result = unsafe { + libc::CreateFileW(p, + libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES, + 0, + ptr::null_mut(), + libc::OPEN_EXISTING, + libc::FILE_FLAG_OVERLAPPED, + ptr::null_mut()) + }; + if result != libc::INVALID_HANDLE_VALUE { + return Some(result) + } + } + let err = unsafe { libc::GetLastError() }; + if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { + result = unsafe { + libc::CreateFileW(p, + libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES, + 0, + ptr::null_mut(), + libc::OPEN_EXISTING, + libc::FILE_FLAG_OVERLAPPED, + ptr::null_mut()) + }; + if result != libc::INVALID_HANDLE_VALUE { + return Some(result) + } + } + None + } + + pub fn connect(addr: &CString, timeout: Option) -> IoResult { + let addr = try!(to_utf16(addr.as_str())); + let start = timer::now(); + loop { + match UnixStream::try_connect(addr.as_ptr()) { + Some(handle) => { + let inner = Inner::new(handle); + let mut mode = libc::PIPE_TYPE_BYTE | + libc::PIPE_READMODE_BYTE | + libc::PIPE_WAIT; + let ret = unsafe { + libc::SetNamedPipeHandleState(inner.handle, + &mut mode, + ptr::null_mut(), + ptr::null_mut()) + }; + return if ret == 0 { + Err(super::last_error()) + } else { + Ok(UnixStream { + inner: Arc::new(inner), + read: None, + write: None, + read_deadline: 0, + write_deadline: 0, + }) + } + } + None => {} + } + + // On windows, if you fail to connect, you may need to call the + // `WaitNamedPipe` function, and this is indicated with an error + // code of ERROR_PIPE_BUSY. + let code = unsafe { libc::GetLastError() }; + if code as int != libc::ERROR_PIPE_BUSY as int { + return Err(super::last_error()) + } + + match timeout { + Some(timeout) => { + let now = timer::now(); + let timed_out = (now - start) >= timeout || unsafe { + let ms = (timeout - (now - start)) as libc::DWORD; + libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0 + }; + if timed_out { + return Err(sys_common::timeout("connect timed out")) + } + } + + // An example I found on Microsoft's website used 20 + // seconds, libuv uses 30 seconds, hence we make the + // obvious choice of waiting for 25 seconds. + None => { + if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 { + return Err(super::last_error()) + } + } + } + } + } + + fn handle(&self) -> libc::HANDLE { self.inner.handle } + + fn read_closed(&self) -> bool { + self.inner.read_closed.load(atomic::SeqCst) + } + + fn write_closed(&self) -> bool { + self.inner.write_closed.load(atomic::SeqCst) + } + + fn cancel_io(&self) -> IoResult<()> { + match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } { + 0 if os::errno() == libc::ERROR_NOT_FOUND as uint => { + Ok(()) + } + 0 => Err(super::last_error()), + _ => Ok(()) + } + } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { + if self.read.is_none() { + self.read = Some(try!(Event::new(true, false))); + } + + let mut bytes_read = 0; + let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; + overlapped.hEvent = self.read.as_ref().unwrap().handle(); + + // Pre-flight check to see if the reading half has been closed. This + // must be done before issuing the ReadFile request, but after we + // acquire the lock. + // + // See comments in close_read() about why this lock is necessary. + let guard = unsafe { self.inner.lock.lock() }; + if self.read_closed() { + return Err(eof()) + } + + // Issue a nonblocking requests, succeeding quickly if it happened to + // succeed. + let ret = unsafe { + libc::ReadFile(self.handle(), + buf.as_ptr() as libc::LPVOID, + buf.len() as libc::DWORD, + &mut bytes_read, + &mut overlapped) + }; + if ret != 0 { return Ok(bytes_read as uint) } + + // If our errno doesn't say that the I/O is pending, then we hit some + // legitimate error and return immediately. + if os::errno() != libc::ERROR_IO_PENDING as uint { + return Err(super::last_error()) + } + + // Now that we've issued a successful nonblocking request, we need to + // wait for it to finish. This can all be done outside the lock because + // we'll see any invocation of CancelIoEx. We also call this in a loop + // because we're woken up if the writing half is closed, we just need to + // realize that the reading half wasn't closed and we go right back to + // sleep. + drop(guard); + loop { + // Process a timeout if one is pending + let wait_succeeded = await(self.handle(), self.read_deadline, + &[overlapped.hEvent]); + + let ret = unsafe { + libc::GetOverlappedResult(self.handle(), + &mut overlapped, + &mut bytes_read, + libc::TRUE) + }; + // If we succeeded, or we failed for some reason other than + // CancelIoEx, return immediately + if ret != 0 { return Ok(bytes_read as uint) } + if os::errno() != libc::ERROR_OPERATION_ABORTED as uint { + return Err(super::last_error()) + } + + // If the reading half is now closed, then we're done. If we woke up + // because the writing half was closed, keep trying. + if wait_succeeded.is_err() { + return Err(sys_common::timeout("read timed out")) + } + if self.read_closed() { + return Err(eof()) + } + } + } + + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { + if self.write.is_none() { + self.write = Some(try!(Event::new(true, false))); + } + + let mut offset = 0; + let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; + overlapped.hEvent = self.write.as_ref().unwrap().handle(); + + while offset < buf.len() { + let mut bytes_written = 0; + + // This sequence below is quite similar to the one found in read(). + // Some careful looping is done to ensure that if close_write() is + // invoked we bail out early, and if close_read() is invoked we keep + // going after we woke up. + // + // See comments in close_read() about why this lock is necessary. + let guard = unsafe { self.inner.lock.lock() }; + if self.write_closed() { + return Err(epipe()) + } + let ret = unsafe { + libc::WriteFile(self.handle(), + buf[offset..].as_ptr() as libc::LPVOID, + (buf.len() - offset) as libc::DWORD, + &mut bytes_written, + &mut overlapped) + }; + let err = os::errno(); + drop(guard); + + if ret == 0 { + if err != libc::ERROR_IO_PENDING as uint { + return Err(decode_error_detailed(err as i32)) + } + // Process a timeout if one is pending + let wait_succeeded = await(self.handle(), self.write_deadline, + &[overlapped.hEvent]); + let ret = unsafe { + libc::GetOverlappedResult(self.handle(), + &mut overlapped, + &mut bytes_written, + libc::TRUE) + }; + // If we weren't aborted, this was a legit error, if we were + // aborted, then check to see if the write half was actually + // closed or whether we woke up from the read half closing. + if ret == 0 { + if os::errno() != libc::ERROR_OPERATION_ABORTED as uint { + return Err(super::last_error()) + } + if !wait_succeeded.is_ok() { + let amt = offset + bytes_written as uint; + return if amt > 0 { + Err(IoError { + kind: io::ShortWrite(amt), + desc: "short write during write", + detail: None, + }) + } else { + Err(sys_common::timeout("write timed out")) + } + } + if self.write_closed() { + return Err(epipe()) + } + continue // retry + } + } + offset += bytes_written as uint; + } + Ok(()) + } + + pub fn close_read(&mut self) -> IoResult<()> { + // On windows, there's no actual shutdown() method for pipes, so we're + // forced to emulate the behavior manually at the application level. To + // do this, we need to both cancel any pending requests, as well as + // prevent all future requests from succeeding. These two operations are + // not atomic with respect to one another, so we must use a lock to do + // so. + // + // The read() code looks like: + // + // 1. Make sure the pipe is still open + // 2. Submit a read request + // 3. Wait for the read request to finish + // + // The race this lock is preventing is if another thread invokes + // close_read() between steps 1 and 2. By atomically executing steps 1 + // and 2 with a lock with respect to close_read(), we're guaranteed that + // no thread will erroneously sit in a read forever. + let _guard = unsafe { self.inner.lock.lock() }; + self.inner.read_closed.store(true, atomic::SeqCst); + self.cancel_io() + } + + pub fn close_write(&mut self) -> IoResult<()> { + // see comments in close_read() for why this lock is necessary + let _guard = unsafe { self.inner.lock.lock() }; + self.inner.write_closed.store(true, atomic::SeqCst); + self.cancel_io() + } + + pub fn set_timeout(&mut self, timeout: Option) { + let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); + self.read_deadline = deadline; + self.write_deadline = deadline; + } + pub fn set_read_timeout(&mut self, timeout: Option) { + self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); + } + pub fn set_write_timeout(&mut self, timeout: Option) { + self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); + } +} + +impl Clone for UnixStream { + fn clone(&self) -> UnixStream { + UnixStream { + inner: self.inner.clone(), + read: None, + write: None, + read_deadline: 0, + write_deadline: 0, + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Unix Listener +//////////////////////////////////////////////////////////////////////////////// + +pub struct UnixListener { + handle: libc::HANDLE, + name: CString, +} + +impl UnixListener { + pub fn bind(addr: &CString) -> IoResult { + // Although we technically don't need the pipe until much later, we + // create the initial handle up front to test the validity of the name + // and such. + let addr_v = try!(to_utf16(addr.as_str())); + let ret = unsafe { pipe(addr_v.as_ptr(), true) }; + if ret == libc::INVALID_HANDLE_VALUE { + Err(super::last_error()) + } else { + Ok(UnixListener { handle: ret, name: addr.clone() }) + } + } + + pub fn listen(self) -> IoResult { + Ok(UnixAcceptor { + listener: self, + event: try!(Event::new(true, false)), + deadline: 0, + inner: Arc::new(AcceptorState { + abort: try!(Event::new(true, false)), + closed: atomic::AtomicBool::new(false), + }), + }) + } +} + +impl Drop for UnixListener { + fn drop(&mut self) { + unsafe { let _ = libc::CloseHandle(self.handle); } + } +} + +pub struct UnixAcceptor { + inner: Arc, + listener: UnixListener, + event: Event, + deadline: u64, +} + +struct AcceptorState { + abort: Event, + closed: atomic::AtomicBool, +} + +impl UnixAcceptor { + pub fn accept(&mut self) -> IoResult { + // This function has some funky implementation details when working with + // unix pipes. On windows, each server named pipe handle can be + // connected to a one or zero clients. To the best of my knowledge, a + // named server is considered active and present if there exists at + // least one server named pipe for it. + // + // The model of this function is to take the current known server + // handle, connect a client to it, and then transfer ownership to the + // UnixStream instance. The next time accept() is invoked, it'll need a + // different server handle to connect a client to. + // + // Note that there is a possible race here. Once our server pipe is + // handed off to a `UnixStream` object, the stream could be closed, + // meaning that there would be no active server pipes, hence even though + // we have a valid `UnixAcceptor`, no one can connect to it. For this + // reason, we generate the next accept call's server pipe at the end of + // this function call. + // + // This provides us an invariant that we always have at least one server + // connection open at a time, meaning that all connects to this acceptor + // should succeed while this is active. + // + // The actual implementation of doing this is a little tricky. Once a + // server pipe is created, a client can connect to it at any time. I + // assume that which server a client connects to is nondeterministic, so + // we also need to guarantee that the only server able to be connected + // to is the one that we're calling ConnectNamedPipe on. This means that + // we have to create the second server pipe *after* we've already + // accepted a connection. In order to at least somewhat gracefully + // handle errors, this means that if the second server pipe creation + // fails that we disconnect the connected client and then just keep + // using the original server pipe. + let handle = self.listener.handle; + + // If we've had an artificial call to close_accept, be sure to never + // proceed in accepting new clients in the future + if self.inner.closed.load(atomic::SeqCst) { return Err(eof()) } + + let name = try!(to_utf16(self.listener.name.as_str())); + + // Once we've got a "server handle", we need to wait for a client to + // connect. The ConnectNamedPipe function will block this thread until + // someone on the other end connects. This function can "fail" if a + // client connects after we created the pipe but before we got down + // here. Thanks windows. + let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; + overlapped.hEvent = self.event.handle(); + if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } { + let mut err = unsafe { libc::GetLastError() }; + + if err == libc::ERROR_IO_PENDING as libc::DWORD { + // Process a timeout if one is pending + let wait_succeeded = await(handle, self.deadline, + &[self.inner.abort.handle(), + overlapped.hEvent]); + + // This will block until the overlapped I/O is completed. The + // timeout was previously handled, so this will either block in + // the normal case or succeed very quickly in the timeout case. + let ret = unsafe { + let mut transfer = 0; + libc::GetOverlappedResult(handle, + &mut overlapped, + &mut transfer, + libc::TRUE) + }; + if ret == 0 { + if wait_succeeded.is_ok() { + err = unsafe { libc::GetLastError() }; + } else { + return Err(sys_common::timeout("accept timed out")) + } + } else { + // we succeeded, bypass the check below + err = libc::ERROR_PIPE_CONNECTED as libc::DWORD; + } + } + if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD { + return Err(super::last_error()) + } + } + + // Now that we've got a connected client to our handle, we need to + // create a second server pipe. If this fails, we disconnect the + // connected client and return an error (see comments above). + let new_handle = unsafe { pipe(name.as_ptr(), false) }; + if new_handle == libc::INVALID_HANDLE_VALUE { + let ret = Err(super::last_error()); + // If our disconnection fails, then there's not really a whole lot + // that we can do, so panic + let err = unsafe { libc::DisconnectNamedPipe(handle) }; + assert!(err != 0); + return ret; + } else { + self.listener.handle = new_handle; + } + + // Transfer ownership of our handle into this stream + Ok(UnixStream { + inner: Arc::new(Inner::new(handle)), + read: None, + write: None, + read_deadline: 0, + write_deadline: 0, + }) + } + + pub fn set_timeout(&mut self, timeout: Option) { + self.deadline = timeout.map(|i| i + timer::now()).unwrap_or(0); + } + + pub fn close_accept(&mut self) -> IoResult<()> { + self.inner.closed.store(true, atomic::SeqCst); + let ret = unsafe { + c::SetEvent(self.inner.abort.handle()) + }; + if ret == 0 { + Err(super::last_error()) + } else { + Ok(()) + } + } +} + +impl Clone for UnixAcceptor { + fn clone(&self) -> UnixAcceptor { + let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); + UnixAcceptor { + inner: self.inner.clone(), + event: Event::new(true, false).ok().unwrap(), + deadline: 0, + listener: UnixListener { + name: self.listener.name.clone(), + handle: unsafe { + let p = pipe(name.as_ptr(), false) ; + assert!(p != libc::INVALID_HANDLE_VALUE as libc::HANDLE); + p + }, + }, + } + } +} diff --git a/src/libst2/sys/windows/process.rs b/src/libst2/sys/windows/process.rs new file mode 100644 index 0000000000000..3fb5ee34356fe --- /dev/null +++ b/src/libst2/sys/windows/process.rs @@ -0,0 +1,511 @@ +// 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. + +use libc::{pid_t, c_void, c_int}; +use libc; +use c_str::CString; +use io; +use mem; +use os; +use ptr; +use prelude::*; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use collections; +use path::BytesContainer; +use hash::Hash; +use io::{IoResult, IoError}; + +use sys::fs; +use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; +use sys::fs::FileDesc; +use sys_common::helper_thread::Helper; +use sys_common::{AsFileDesc, mkerr_libc, timeout}; + +use io::fs::PathExtensions; +use string::String; + +pub use sys_common::ProcessConfig; + +/** + * A value representing a child process. + * + * The lifetime of this value is linked to the lifetime of the actual + * process - the Process destructor calls self.finish() which waits + * for the process to terminate. + */ +pub struct Process { + /// The unique id of the process (this should never be negative). + pid: pid_t, + + /// A HANDLE to the process, which will prevent the pid being + /// re-used until the handle is closed. + handle: *mut (), +} + +impl Drop for Process { + fn drop(&mut self) { + free_handle(self.handle); + } +} + +impl Process { + pub fn id(&self) -> pid_t { + self.pid + } + + pub unsafe fn kill(&self, signal: int) -> IoResult<()> { + Process::killpid(self.pid, signal) + } + + pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { + let handle = libc::OpenProcess(libc::PROCESS_TERMINATE | + libc::PROCESS_QUERY_INFORMATION, + libc::FALSE, pid as libc::DWORD); + if handle.is_null() { + return Err(super::last_error()) + } + let ret = match signal { + // test for existence on signal 0 + 0 => { + let mut status = 0; + let ret = libc::GetExitCodeProcess(handle, &mut status); + if ret == 0 { + Err(super::last_error()) + } else if status != libc::STILL_ACTIVE { + Err(IoError { + kind: io::InvalidInput, + desc: "no process to kill", + detail: None, + }) + } else { + Ok(()) + } + } + 15 | 9 => { // sigterm or sigkill + let ret = libc::TerminateProcess(handle, 1); + super::mkerr_winbool(ret) + } + _ => Err(IoError { + kind: io::IoUnavailable, + desc: "unsupported signal on windows", + detail: None, + }) + }; + let _ = libc::CloseHandle(handle); + return ret; + } + + pub fn spawn(cfg: &C, in_fd: Option

, + out_fd: Option

, err_fd: Option

) + -> IoResult + where C: ProcessConfig, P: AsFileDesc, + K: BytesContainer + Eq + Hash, V: BytesContainer + { + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessW + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + + use mem; + use iter::Iterator; + use str::StrPrelude; + + if cfg.gid().is_some() || cfg.uid().is_some() { + return Err(IoError { + kind: io::IoUnavailable, + desc: "unsupported gid/uid requested on windows", + detail: None, + }) + } + + // To have the spawning semantics of unix/windows stay the same, we need to + // read the *child's* PATH if one is provided. See #15149 for more details. + let program = cfg.env().and_then(|env| { + for (key, v) in env.iter() { + if b"PATH" != key.container_as_bytes() { continue } + + // Split the value and test each path to see if the + // program exists. + for path in os::split_paths(v.container_as_bytes()).into_iter() { + let path = path.join(cfg.program().as_bytes_no_nul()) + .with_extension(os::consts::EXE_EXTENSION); + if path.exists() { + return Some(path.to_c_str()) + } + } + break + } + None + }); + + unsafe { + let mut si = zeroed_startupinfo(); + si.cb = mem::size_of::() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + // Similarly to unix, we don't actually leave holes for the stdio file + // descriptors, but rather open up /dev/null equivalents. These + // equivalents are drawn from libuv's windows process spawning. + let set_fd = |fd: &Option

, slot: &mut HANDLE, + is_stdin: bool| { + match *fd { + None => { + let access = if is_stdin { + libc::FILE_GENERIC_READ + } else { + libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES + }; + let size = mem::size_of::(); + let mut sa = libc::SECURITY_ATTRIBUTES { + nLength: size as libc::DWORD, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: 1, + }; + let mut filename: Vec = "NUL".utf16_units().collect(); + filename.push(0); + *slot = libc::CreateFileW(filename.as_ptr(), + access, + libc::FILE_SHARE_READ | + libc::FILE_SHARE_WRITE, + &mut sa, + libc::OPEN_EXISTING, + 0, + ptr::null_mut()); + if *slot == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + } + Some(ref fd) => { + let orig = get_osfhandle(fd.as_fd().fd()) as HANDLE; + if orig == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + if DuplicateHandle(cur_proc, orig, cur_proc, slot, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + return Err(super::last_error()) + } + } + } + Ok(()) + }; + + try!(set_fd(&in_fd, &mut si.hStdInput, true)); + try!(set_fd(&out_fd, &mut si.hStdOutput, false)); + try!(set_fd(&err_fd, &mut si.hStdError, false)); + + let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()), + cfg.args()); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + // stolen from the libuv code. + let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; + if cfg.detach() { + flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; + } + + with_envp(cfg.env(), |envp| { + with_dirp(cfg.cwd(), |dirp| { + let mut cmd_str: Vec = cmd_str.as_slice().utf16_units().collect(); + cmd_str.push(0); + let created = CreateProcessW(ptr::null(), + cmd_str.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + TRUE, + flags, envp, dirp, + &mut si, &mut pi); + if created == FALSE { + create_err = Some(super::last_error()); + } + }) + }); + + assert!(CloseHandle(si.hStdInput) != 0); + assert!(CloseHandle(si.hStdOutput) != 0); + assert!(CloseHandle(si.hStdError) != 0); + + match create_err { + Some(err) => return Err(err), + None => {} + } + + // We close the thread handle because we don't care about keeping the + // thread id valid, and we aren't keeping the thread handle around to be + // able to close it later. We don't close the process handle however + // because std::we want the process id to stay valid at least until the + // calling code closes the process handle. + assert!(CloseHandle(pi.hThread) != 0); + + Ok(Process { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *mut () + }) + } + } + + /** + * Waits for a process to exit and returns the exit code, failing + * if there is no process with the specified id. + * + * Note that this is private to avoid race conditions on unix where if + * a user calls waitpid(some_process.get_id()) then some_process.finish() + * and some_process.destroy() and some_process.finalize() will then either + * operate on a none-existent process or, even worse, on a newer process + * with the same id. + */ + pub fn wait(&self, deadline: u64) -> IoResult { + use libc::types::os::arch::extra::DWORD; + use libc::consts::os::extra::{ + SYNCHRONIZE, + PROCESS_QUERY_INFORMATION, + FALSE, + STILL_ACTIVE, + INFINITE, + WAIT_TIMEOUT, + WAIT_OBJECT_0, + }; + use libc::funcs::extra::kernel32::{ + OpenProcess, + GetExitCodeProcess, + CloseHandle, + WaitForSingleObject, + }; + + unsafe { + let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, + FALSE, + self.pid as DWORD); + if process.is_null() { + return Err(super::last_error()) + } + + loop { + let mut status = 0; + if GetExitCodeProcess(process, &mut status) == FALSE { + let err = Err(super::last_error()); + assert!(CloseHandle(process) != 0); + return err; + } + if status != STILL_ACTIVE { + assert!(CloseHandle(process) != 0); + return Ok(ExitStatus(status as int)); + } + let interval = if deadline == 0 { + INFINITE + } else { + let now = timer::now(); + if deadline < now {0} else {(deadline - now) as u32} + }; + match WaitForSingleObject(process, interval) { + WAIT_OBJECT_0 => {} + WAIT_TIMEOUT => { + assert!(CloseHandle(process) != 0); + return Err(timeout("process wait timed out")) + } + _ => { + let err = Err(super::last_error()); + assert!(CloseHandle(process) != 0); + return err + } + } + } + } + } +} + +fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { + libc::types::os::arch::extra::STARTUPINFO { + cb: 0, + lpReserved: ptr::null_mut(), + lpDesktop: ptr::null_mut(), + lpTitle: ptr::null_mut(), + dwX: 0, + dwY: 0, + dwXSize: 0, + dwYSize: 0, + dwXCountChars: 0, + dwYCountCharts: 0, + dwFillAttribute: 0, + dwFlags: 0, + wShowWindow: 0, + cbReserved2: 0, + lpReserved2: ptr::null_mut(), + hStdInput: libc::INVALID_HANDLE_VALUE, + hStdOutput: libc::INVALID_HANDLE_VALUE, + hStdError: libc::INVALID_HANDLE_VALUE, + } +} + +fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { + libc::types::os::arch::extra::PROCESS_INFORMATION { + hProcess: ptr::null_mut(), + hThread: ptr::null_mut(), + dwProcessId: 0, + dwThreadId: 0 + } +} + +fn make_command_line(prog: &CString, args: &[CString]) -> String { + let mut cmd = String::new(); + append_arg(&mut cmd, prog.as_str() + .expect("expected program name to be utf-8 encoded")); + for arg in args.iter() { + cmd.push(' '); + append_arg(&mut cmd, arg.as_str() + .expect("expected argument to be utf-8 encoded")); + } + return cmd; + + fn append_arg(cmd: &mut String, arg: &str) { + // If an argument has 0 characters then we need to quote it to ensure + // that it actually gets passed through on the command line or otherwise + // it will be dropped entirely when parsed on the other end. + let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0; + if quote { + cmd.push('"'); + } + let argvec: Vec = arg.chars().collect(); + for i in range(0u, argvec.len()) { + append_char_at(cmd, argvec.as_slice(), i); + } + if quote { + cmd.push('"'); + } + } + + fn append_char_at(cmd: &mut String, arg: &[char], i: uint) { + match arg[i] { + '"' => { + // Escape quotes. + cmd.push_str("\\\""); + } + '\\' => { + if backslash_run_ends_in_quote(arg, i) { + // Double all backslashes that are in runs before quotes. + cmd.push_str("\\\\"); + } else { + // Pass other backslashes through unescaped. + cmd.push('\\'); + } + } + c => { + cmd.push(c); + } + } + } + + fn backslash_run_ends_in_quote(s: &[char], mut i: uint) -> bool { + while i < s.len() && s[i] == '\\' { + i += 1; + } + return i < s.len() && s[i] == '"'; + } +} + +fn with_envp(env: Option<&collections::HashMap>, + cb: |*mut c_void| -> T) -> T + where K: BytesContainer + Eq + Hash, V: BytesContainer +{ + // On Windows we pass an "environment block" which is not a char**, but + // rather a concatenation of null-terminated k=v\0 sequences, with a final + // \0 to terminate. + match env { + Some(env) => { + let mut blk = Vec::new(); + + for pair in env.iter() { + let kv = format!("{}={}", + pair.ref0().container_as_str().unwrap(), + pair.ref1().container_as_str().unwrap()); + blk.extend(kv.as_slice().utf16_units()); + blk.push(0); + } + + blk.push(0); + + cb(blk.as_mut_ptr() as *mut c_void) + } + _ => cb(ptr::null_mut()) + } +} + +fn with_dirp(d: Option<&CString>, cb: |*const u16| -> T) -> T { + match d { + Some(dir) => { + let dir_str = dir.as_str() + .expect("expected workingdirectory to be utf-8 encoded"); + let mut dir_str: Vec = dir_str.utf16_units().collect(); + dir_str.push(0); + cb(dir_str.as_ptr()) + }, + None => cb(ptr::null()) + } +} + +fn free_handle(handle: *mut ()) { + assert!(unsafe { + libc::CloseHandle(mem::transmute(handle)) != 0 + }) +} + +#[cfg(test)] +mod tests { + + #[test] + fn test_make_command_line() { + use prelude::*; + use str; + use c_str::CString; + use super::make_command_line; + + fn test_wrapper(prog: &str, args: &[&str]) -> String { + make_command_line(&prog.to_c_str(), + args.iter() + .map(|a| a.to_c_str()) + .collect::>() + .as_slice()) + } + + assert_eq!( + test_wrapper("prog", &["aaa", "bbb", "ccc"]), + "prog aaa bbb ccc".to_string() + ); + + assert_eq!( + test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), + "\"C:\\Program Files\\blah\\blah.exe\" aaa".to_string() + ); + assert_eq!( + test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), + "\"C:\\Program Files\\test\" aa\\\"bb".to_string() + ); + assert_eq!( + test_wrapper("echo", &["a b c"]), + "echo \"a b c\"".to_string() + ); + assert_eq!( + test_wrapper("\u03c0\u042f\u97f3\u00e6\u221e", &[]), + "\u03c0\u042f\u97f3\u00e6\u221e".to_string() + ); + } +} diff --git a/src/libst2/sys/windows/tcp.rs b/src/libst2/sys/windows/tcp.rs new file mode 100644 index 0000000000000..3baf2be08d238 --- /dev/null +++ b/src/libst2/sys/windows/tcp.rs @@ -0,0 +1,219 @@ +// 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. + +use io::net::ip; +use io::IoResult; +use libc; +use mem; +use ptr; +use prelude::*; +use super::{last_error, last_net_error, retry, sock_t}; +use sync::{Arc, atomic}; +use sys::fs::FileDesc; +use sys::{mod, c, set_nonblocking, wouldblock, timer}; +use sys_common::{mod, timeout, eof}; +use sys_common::net::*; + +pub use sys_common::net::TcpStream; + +pub struct Event(c::WSAEVENT); + +impl Event { + pub fn new() -> IoResult { + let event = unsafe { c::WSACreateEvent() }; + if event == c::WSA_INVALID_EVENT { + Err(super::last_error()) + } else { + Ok(Event(event)) + } + } + + pub fn handle(&self) -> c::WSAEVENT { let Event(handle) = *self; handle } +} + +impl Drop for Event { + fn drop(&mut self) { + unsafe { let _ = c::WSACloseEvent(self.handle()); } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// TCP listeners +//////////////////////////////////////////////////////////////////////////////// + +pub struct TcpListener { + inner: FileDesc, +} + +impl TcpListener { + pub fn bind(addr: ip::SocketAddr) -> IoResult { + sys::init_net(); + + let fd = try!(socket(addr, libc::SOCK_STREAM)); + let ret = TcpListener { inner: FileDesc::new(fd as libc::c_int, true) }; + + let mut storage = unsafe { mem::zeroed() }; + let len = addr_to_sockaddr(addr, &mut storage); + let addrp = &storage as *const _ as *const libc::sockaddr; + + match unsafe { libc::bind(fd, addrp, len) } { + -1 => Err(last_net_error()), + _ => Ok(ret), + } + } + + pub fn fd(&self) -> sock_t { self.inner.fd as sock_t } + + pub fn listen(self, backlog: int) -> IoResult { + match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { + -1 => Err(last_net_error()), + + _ => { + let accept = try!(Event::new()); + let ret = unsafe { + c::WSAEventSelect(self.fd(), accept.handle(), c::FD_ACCEPT) + }; + if ret != 0 { + return Err(last_net_error()) + } + Ok(TcpAcceptor { + inner: Arc::new(AcceptorInner { + listener: self, + abort: try!(Event::new()), + accept: accept, + closed: atomic::AtomicBool::new(false), + }), + deadline: 0, + }) + } + } + } + + pub fn socket_name(&mut self) -> IoResult { + sockname(self.fd(), libc::getsockname) + } +} + +pub struct TcpAcceptor { + inner: Arc, + deadline: u64, +} + +struct AcceptorInner { + listener: TcpListener, + abort: Event, + accept: Event, + closed: atomic::AtomicBool, +} + +impl TcpAcceptor { + pub fn fd(&self) -> sock_t { self.inner.listener.fd() } + + pub fn accept(&mut self) -> IoResult { + // Unlink unix, windows cannot invoke `select` on arbitrary file + // descriptors like pipes, only sockets. Consequently, windows cannot + // use the same implementation as unix for accept() when close_accept() + // is considered. + // + // In order to implement close_accept() and timeouts, windows uses + // event handles. An acceptor-specific abort event is created which + // will only get set in close_accept(), and it will never be un-set. + // Additionally, another acceptor-specific event is associated with the + // FD_ACCEPT network event. + // + // These two events are then passed to WaitForMultipleEvents to see + // which one triggers first, and the timeout passed to this function is + // the local timeout for the acceptor. + // + // If the wait times out, then the accept timed out. If the wait + // succeeds with the abort event, then we were closed, and if the wait + // succeeds otherwise, then we do a nonblocking poll via `accept` to + // see if we can accept a connection. The connection is candidate to be + // stolen, so we do all of this in a loop as well. + let events = [self.inner.abort.handle(), self.inner.accept.handle()]; + + while !self.inner.closed.load(atomic::SeqCst) { + let ms = if self.deadline == 0 { + c::WSA_INFINITE as u64 + } else { + let now = timer::now(); + if self.deadline < now {0} else {self.deadline - now} + }; + let ret = unsafe { + c::WSAWaitForMultipleEvents(2, events.as_ptr(), libc::FALSE, + ms as libc::DWORD, libc::FALSE) + }; + match ret { + c::WSA_WAIT_TIMEOUT => { + return Err(timeout("accept timed out")) + } + c::WSA_WAIT_FAILED => return Err(last_net_error()), + c::WSA_WAIT_EVENT_0 => break, + n => assert_eq!(n, c::WSA_WAIT_EVENT_0 + 1), + } + + let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() }; + let ret = unsafe { + c::WSAEnumNetworkEvents(self.fd(), events[1], &mut wsaevents) + }; + if ret != 0 { return Err(last_net_error()) } + + if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue } + match unsafe { + libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut()) + } { + -1 if wouldblock() => {} + -1 => return Err(last_net_error()), + + // Accepted sockets inherit the same properties as the caller, + // so we need to deregister our event and switch the socket back + // to blocking mode + fd => { + let stream = TcpStream::new(fd); + let ret = unsafe { + c::WSAEventSelect(fd, events[1], 0) + }; + if ret != 0 { return Err(last_net_error()) } + try!(set_nonblocking(fd, false)); + return Ok(stream) + } + } + } + + Err(eof()) + } + + pub fn socket_name(&mut self) -> IoResult { + sockname(self.fd(), libc::getsockname) + } + + pub fn set_timeout(&mut self, timeout: Option) { + self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); + } + + pub fn close_accept(&mut self) -> IoResult<()> { + self.inner.closed.store(true, atomic::SeqCst); + let ret = unsafe { c::WSASetEvent(self.inner.abort.handle()) }; + if ret == libc::TRUE { + Ok(()) + } else { + Err(last_net_error()) + } + } +} + +impl Clone for TcpAcceptor { + fn clone(&self) -> TcpAcceptor { + TcpAcceptor { + inner: self.inner.clone(), + deadline: 0, + } + } +} diff --git a/src/libst2/sys/windows/thread_local.rs b/src/libst2/sys/windows/thread_local.rs new file mode 100644 index 0000000000000..b841f6d3a2b2f --- /dev/null +++ b/src/libst2/sys/windows/thread_local.rs @@ -0,0 +1,238 @@ +// 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. + +use prelude::*; + +use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; + +use mem; +use rustrt; +use rustrt::exclusive::Exclusive; +use sync::{ONCE_INIT, Once}; + +pub type Key = DWORD; +pub type Dtor = unsafe extern fn(*mut u8); + +// Turns out, like pretty much everything, Windows is pretty close the +// functionality that Unix provides, but slightly different! In the case of +// TLS, Windows does not provide an API to provide a destructor for a TLS +// variable. This ends up being pretty crucial to this implementation, so we +// need a way around this. +// +// The solution here ended up being a little obscure, but fear not, the +// internet has informed me [1][2] that this solution is not unique (no way +// I could have thought of it as well!). The key idea is to insert some hook +// somewhere to run arbitrary code on thread termination. With this in place +// we'll be able to run anything we like, including all TLS destructors! +// +// To accomplish this feat, we perform a number of tasks, all contained +// within this module: +// +// * All TLS destructors are tracked by *us*, not the windows runtime. This +// means that we have a global list of destructors for each TLS key that +// we know about. +// * When a TLS key is destroyed, we're sure to remove it from the dtor list +// if it's in there. +// * When a thread exits, we run over the entire list and run dtors for all +// non-null keys. This attempts to match Unix semantics in this regard. +// +// This ends up having the overhead of using a global list, having some +// locks here and there, and in general just adding some more code bloat. We +// attempt to optimize runtime by forgetting keys that don't have +// destructors, but this only gets us so far. +// +// For more details and nitty-gritty, see the code sections below! +// +// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way +// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base +// /threading/thread_local_storage_win.cc#L42 + +static INIT_DTORS: Once = ONCE_INIT; +static mut DTORS: *mut Exclusive> = 0 as *mut _; + +// ------------------------------------------------------------------------- +// Native bindings +// +// This section is just raw bindings to the native functions that Windows +// provides, There's a few extra calls to deal with destructors. + +#[inline] +pub unsafe fn create(dtor: Option) -> Key { + const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; + let key = TlsAlloc(); + assert!(key != TLS_OUT_OF_INDEXES); + match dtor { + Some(f) => register_dtor(key, f), + None => {} + } + return key; +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + let r = TlsSetValue(key, value as LPVOID); + debug_assert!(r != 0); +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + TlsGetValue(key) as *mut u8 +} + +#[inline] +pub unsafe fn destroy(key: Key) { + if unregister_dtor(key) { + // FIXME: Currently if a key has a destructor associated with it we + // can't actually ever unregister it. If we were to + // unregister it, then any key destruction would have to be + // serialized with respect to actually running destructors. + // + // We want to avoid a race where right before run_dtors runs + // some destructors TlsFree is called. Allowing the call to + // TlsFree would imply that the caller understands that *all + // known threads* are not exiting, which is quite a difficult + // thing to know! + // + // For now we just leak all keys with dtors to "fix" this. + // Note that source [2] above shows precedent for this sort + // of strategy. + } else { + let r = TlsFree(key); + debug_assert!(r != 0); + } +} + +extern "system" { + fn TlsAlloc() -> DWORD; + fn TlsFree(dwTlsIndex: DWORD) -> BOOL; + fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; + fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; +} + +// ------------------------------------------------------------------------- +// Dtor registration +// +// These functions are associated with registering and unregistering +// destructors. They're pretty simple, they just push onto a vector and scan +// a vector currently. +// +// FIXME: This could probably be at least a little faster with a BTree. + +fn init_dtors() { + let dtors = box Exclusive::new(Vec::<(Key, Dtor)>::new()); + unsafe { + DTORS = mem::transmute(dtors); + } + + rustrt::at_exit(proc() unsafe { + mem::transmute::<_, Box>>>(DTORS); + DTORS = 0 as *mut _; + }); +} + +unsafe fn register_dtor(key: Key, dtor: Dtor) { + INIT_DTORS.doit(init_dtors); + let mut dtors = (*DTORS).lock(); + dtors.push((key, dtor)); +} + +unsafe fn unregister_dtor(key: Key) -> bool { + if DTORS.is_null() { return false } + let mut dtors = (*DTORS).lock(); + let before = dtors.len(); + dtors.retain(|&(k, _)| k != key); + dtors.len() != before +} + +// ------------------------------------------------------------------------- +// Where the Magic (TM) Happens +// +// If you're looking at this code, and wondering "what is this doing?", +// you're not alone! I'll try to break this down step by step: +// +// # What's up with CRT$XLB? +// +// For anything about TLS destructors to work on Windows, we have to be able +// to run *something* when a thread exits. To do so, we place a very special +// static in a very special location. If this is encoded in just the right +// way, the kernel's loader is apparently nice enough to run some function +// of ours whenever a thread exits! How nice of the kernel! +// +// Lots of detailed information can be found in source [1] above, but the +// gist of it is that this is leveraging a feature of Microsoft's PE format +// (executable format) which is not actually used by any compilers today. +// This apparently translates to any callbacks in the ".CRT$XLB" section +// being run on certain events. +// +// So after all that, we use the compiler's #[link_section] feature to place +// a callback pointer into the magic section so it ends up being called. +// +// # What's up with this callback? +// +// The callback specified receives a number of parameters from... someone! +// (the kernel? the runtime? I'm not qute sure!) There are a few events that +// this gets invoked for, but we're currentl only interested on when a +// thread or a process "detaches" (exits). The process part happens for the +// last thread and the thread part happens for any normal thread. +// +// # Ok, what's up with running all these destructors? +// +// This will likely need to be improved over time, but this function +// attempts a "poor man's" destructor callback system. To do this we clone a +// local copy of the dtor list to start out with. This is our fudgy attempt +// to not hold the lock while destructors run and not worry about the list +// changing while we're looking at it. +// +// Once we've got a list of what to run, we iterate over all keys, check +// their values, and then run destructors if the values turn out to be non +// null (setting them to null just beforehand). We do this a few times in a +// loop to basically match Unix semantics. If we don't reach a fixed point +// after a short while then we just inevitably leak something most likely. +// +// # The article mentions crazy stuff about "/INCLUDE"? +// +// It sure does! This seems to work for now, so maybe we'll just run into +// that if we start linking with msvc? + +#[link_section = ".CRT$XLB"] +#[linkage = "external"] +#[allow(warnings)] +pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, + LPVOID) = + on_tls_callback; + +#[allow(warnings)] +unsafe extern "system" fn on_tls_callback(h: LPVOID, + dwReason: DWORD, + pv: LPVOID) { + const DLL_THREAD_DETACH: DWORD = 3; + const DLL_PROCESS_DETACH: DWORD = 0; + if dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH { + run_dtors(); + } +} + +unsafe fn run_dtors() { + if DTORS.is_null() { return } + let mut any_run = true; + for _ in range(0, 5i) { + if !any_run { break } + any_run = false; + let dtors = (*DTORS).lock().iter().map(|p| *p).collect::>(); + for &(key, dtor) in dtors.iter() { + let ptr = TlsGetValue(key); + if !ptr.is_null() { + TlsSetValue(key, 0 as *mut _); + dtor(ptr as *mut _); + any_run = true; + } + } + } +} diff --git a/src/libst2/sys/windows/timer.rs b/src/libst2/sys/windows/timer.rs new file mode 100644 index 0000000000000..9af3a7c8b6e01 --- /dev/null +++ b/src/libst2/sys/windows/timer.rs @@ -0,0 +1,210 @@ +// Copyright 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. + +//! Timers based on Windows WaitableTimers +//! +//! This implementation is meant to be used solely on windows. As with other +//! implementations, there is a worker thread which is doing all the waiting on +//! a large number of timers for all active timers in the system. This worker +//! thread uses the select() equivalent, WaitForMultipleObjects. One of the +//! objects being waited on is a signal into the worker thread to notify that +//! the incoming channel should be looked at. +//! +//! Other than that, the implementation is pretty straightforward in terms of +//! the other two implementations of timers with nothing *that* new showing up. + +pub use self::Req::*; + +use libc; +use ptr; +use comm; + +use sys::c; +use sys::fs::FileDesc; +use sys_common::helper_thread::Helper; +use prelude::*; +use io::IoResult; + +helper_init!(static HELPER: Helper) + +pub trait Callback { + fn call(&mut self); +} + +pub struct Timer { + obj: libc::HANDLE, + on_worker: bool, +} + +pub enum Req { + NewTimer(libc::HANDLE, Box, bool), + RemoveTimer(libc::HANDLE, Sender<()>), +} + +fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { + let mut objs = vec![input]; + let mut chans = vec![]; + + 'outer: loop { + let idx = unsafe { + imp::WaitForMultipleObjects(objs.len() as libc::DWORD, + objs.as_ptr(), + 0 as libc::BOOL, + libc::INFINITE) + }; + + if idx == 0 { + loop { + match messages.try_recv() { + Ok(NewTimer(obj, c, one)) => { + objs.push(obj); + chans.push((c, one)); + } + Ok(RemoveTimer(obj, c)) => { + c.send(()); + match objs.iter().position(|&o| o == obj) { + Some(i) => { + drop(objs.remove(i)); + drop(chans.remove(i - 1)); + } + None => {} + } + } + Err(comm::Disconnected) => { + assert_eq!(objs.len(), 1); + assert_eq!(chans.len(), 0); + break 'outer; + } + Err(..) => break + } + } + } else { + let remove = { + match &mut chans[idx as uint - 1] { + &(ref mut c, oneshot) => { c.call(); oneshot } + } + }; + if remove { + drop(objs.remove(idx as uint)); + drop(chans.remove(idx as uint - 1)); + } + } + } +} + +// returns the current time (in milliseconds) +pub fn now() -> u64 { + let mut ticks_per_s = 0; + assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1); + let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s}; + let mut ticks = 0; + assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1); + + return (ticks as u64 * 1000) / (ticks_per_s as u64); +} + +impl Timer { + pub fn new() -> IoResult { + HELPER.boot(|| {}, helper); + + let obj = unsafe { + imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null()) + }; + if obj.is_null() { + Err(super::last_error()) + } else { + Ok(Timer { obj: obj, on_worker: false, }) + } + } + + fn remove(&mut self) { + if !self.on_worker { return } + + let (tx, rx) = channel(); + HELPER.send(RemoveTimer(self.obj, tx)); + rx.recv(); + + self.on_worker = false; + } + + pub fn sleep(&mut self, msecs: u64) { + self.remove(); + + // there are 10^6 nanoseconds in a millisecond, and the parameter is in + // 100ns intervals, so we multiply by 10^4. + let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), + ptr::null_mut(), 0) + }, 1); + + let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) }; + } + + pub fn oneshot(&mut self, msecs: u64, cb: Box) { + self.remove(); + + // see above for the calculation + let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), + ptr::null_mut(), 0) + }, 1); + + HELPER.send(NewTimer(self.obj, cb, true)); + self.on_worker = true; + } + + pub fn period(&mut self, msecs: u64, cb: Box) { + self.remove(); + + // see above for the calculation + let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; + assert_eq!(unsafe { + imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG, + ptr::null_mut(), ptr::null_mut(), 0) + }, 1); + + HELPER.send(NewTimer(self.obj, cb, false)); + self.on_worker = true; + } +} + +impl Drop for Timer { + fn drop(&mut self) { + self.remove(); + assert!(unsafe { libc::CloseHandle(self.obj) != 0 }); + } +} + +mod imp { + use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER, + LONG, LPVOID, DWORD, c_void}; + + pub type PTIMERAPCROUTINE = *mut c_void; + + extern "system" { + pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES, + bManualReset: BOOL, + lpTimerName: LPCSTR) -> HANDLE; + pub fn SetWaitableTimer(hTimer: HANDLE, + pDueTime: *const LARGE_INTEGER, + lPeriod: LONG, + pfnCompletionRoutine: PTIMERAPCROUTINE, + lpArgToCompletionRoutine: LPVOID, + fResume: BOOL) -> BOOL; + pub fn WaitForMultipleObjects(nCount: DWORD, + lpHandles: *const HANDLE, + bWaitAll: BOOL, + dwMilliseconds: DWORD) -> DWORD; + pub fn WaitForSingleObject(hHandle: HANDLE, + dwMilliseconds: DWORD) -> DWORD; + } +} diff --git a/src/libst2/sys/windows/tty.rs b/src/libst2/sys/windows/tty.rs new file mode 100644 index 0000000000000..0e7b06cbb9478 --- /dev/null +++ b/src/libst2/sys/windows/tty.rs @@ -0,0 +1,166 @@ +// 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. + +// ignore-lexer-test FIXME #15877 + +//! Windows specific console TTY implementation +//! +//! This module contains the implementation of a Windows specific console TTY. +//! Also converts between UTF-16 and UTF-8. Windows has very poor support for +//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole +//! will panic when the codepage is set to UTF-8 and a Unicode character is +//! entered. +//! +//! FIXME +//! This implementation does not account for codepoints that are split across +//! multiple reads and writes. Also, this implementation does not expose a way +//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer +//! wrapper that performs encoding/decoding, this implementation should switch +//! to working in raw UTF-16, with such a wrapper around it. + +use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; +use super::c::{ERROR_ILLEGAL_CHARACTER}; +use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS}; +use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT}; +use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; +use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID}; +use libc::{get_osfhandle, CloseHandle}; +use libc::types::os::arch::extra::LPCVOID; +use io::{mod, IoError, IoResult, MemReader}; +use prelude::*; +use ptr; +use str::from_utf8; + +fn invalid_encoding() -> IoError { + IoError { + kind: io::InvalidInput, + desc: "text was not valid unicode", + detail: None, + } +} + +pub fn is_tty(fd: c_int) -> bool { + let mut out: DWORD = 0; + // If this function doesn't panic then fd is a TTY + match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE, + &mut out as LPDWORD) } { + 0 => false, + _ => true, + } +} + +pub struct TTY { + closeme: bool, + handle: HANDLE, + utf8: MemReader, +} + +impl TTY { + pub fn new(fd: c_int) -> IoResult { + if is_tty(fd) { + // If the file descriptor is one of stdin, stderr, or stdout + // then it should not be closed by us + let closeme = match fd { + 0...2 => false, + _ => true, + }; + let handle = unsafe { get_osfhandle(fd) as HANDLE }; + Ok(TTY { + handle: handle, + utf8: MemReader::new(Vec::new()), + closeme: closeme, + }) + } else { + Err(IoError { + kind: io::MismatchedFileTypeForOperation, + desc: "invalid handle provided to function", + detail: None, + }) + } + } + + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { + // Read more if the buffer is empty + if self.utf8.eof() { + let mut utf16 = Vec::from_elem(0x1000, 0u16); + let mut num: DWORD = 0; + match unsafe { ReadConsoleW(self.handle, + utf16.as_mut_ptr() as LPVOID, + utf16.len() as u32, + &mut num as LPDWORD, + ptr::null_mut()) } { + 0 => return Err(super::last_error()), + _ => (), + }; + utf16.truncate(num as uint); + let utf8 = match String::from_utf16(utf16.as_slice()) { + Some(utf8) => utf8.into_bytes(), + None => return Err(invalid_encoding()), + }; + self.utf8 = MemReader::new(utf8); + } + // MemReader shouldn't error here since we just filled it + Ok(self.utf8.read(buf).unwrap()) + } + + pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { + let utf16 = match from_utf8(buf) { + Some(utf8) => { + utf8.as_slice().utf16_units().collect::>() + } + None => return Err(invalid_encoding()), + }; + let mut num: DWORD = 0; + match unsafe { WriteConsoleW(self.handle, + utf16.as_ptr() as LPCVOID, + utf16.len() as u32, + &mut num as LPDWORD, + ptr::null_mut()) } { + 0 => Err(super::last_error()), + _ => Ok(()), + } + } + + pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { + // FIXME + // Somebody needs to decide on which of these flags we want + match unsafe { SetConsoleMode(self.handle, + match raw { + true => 0, + false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS | + ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | + ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE, + }) } { + 0 => Err(super::last_error()), + _ => Ok(()), + } + } + + pub fn get_winsize(&mut self) -> IoResult<(int, int)> { + // FIXME + // Get console buffer via CreateFile with CONOUT$ + // Make a CONSOLE_SCREEN_BUFFER_INFO + // Call GetConsoleScreenBufferInfo + // Maybe call GetLargestConsoleWindowSize instead? + Err(super::unimpl()) + } + + // Let us magically declare this as a TTY + pub fn isatty(&self) -> bool { true } +} + +impl Drop for TTY { + fn drop(&mut self) { + if self.closeme { + // Nobody cares about the return value + let _ = unsafe { CloseHandle(self.handle) }; + } + } +} diff --git a/src/libst2/sys/windows/udp.rs b/src/libst2/sys/windows/udp.rs new file mode 100644 index 0000000000000..50f8fb828ad32 --- /dev/null +++ b/src/libst2/sys/windows/udp.rs @@ -0,0 +1,11 @@ +// 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. + +pub use sys_common::net::UdpSocket; diff --git a/src/libst2/task.rs b/src/libst2/task.rs new file mode 100644 index 0000000000000..296a9f936413d --- /dev/null +++ b/src/libst2/task.rs @@ -0,0 +1,183 @@ +// 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. + +//! Task creation +//! +//! An executing Rust program consists of a collection of tasks, each +//! with their own stack and local state. +//! +//! Tasks generally have their memory *isolated* from each other by +//! virtue of Rust's owned types (which of course may only be owned by +//! a single task at a time). Communication between tasks is primarily +//! done through [channels](../../std/comm/index.html), Rust's +//! message-passing types, though [other forms of task +//! synchronization](../../std/sync/index.html) are often employed to +//! achieve particular performance goals. In particular, types that +//! are guaranteed to be threadsafe are easily shared between threads +//! using the atomically-reference-counted container, +//! [`Arc`](../../std/sync/struct.Arc.html). +//! +//! Fatal logic errors in Rust cause *task panic*, during which +//! a task will unwind the stack, running destructors and freeing +//! owned resources. Task panic is unrecoverable from within +//! the panicking task (i.e. there is no 'try/catch' in Rust), but +//! panic may optionally be detected from a different task. If +//! the main task panics the application will exit with a non-zero +//! exit code. +//! +//! ## Example +//! +//! ```rust +//! spawn(proc() { +//! println!("Hello, World!"); +//! }) +//! ``` + +#![unstable = "The task spawning model will be changed as part of runtime reform, and the module \ + will likely be renamed from `task` to `thread`."] + +use any::Any; +use comm::channel; +use io::{Writer, stdio}; +use kinds::{Send, marker}; +use option::{None, Some, Option}; +use boxed::Box; +use result::Result; +use rustrt::local::Local; +use rustrt::task; +use rustrt::task::Task; +use str::{Str, SendStr, IntoMaybeOwned}; +use string::{String, ToString}; +use sync::Future; + +/// The task builder type. +/// +/// Provides detailed control over the properties and behavior of new tasks. + +// NB: Builders are designed to be single-use because they do stateful +// things that get weird when reusing - e.g. if you create a result future +// it only applies to a single task, so then you have to maintain Some +// potentially tricky state to ensure that everything behaves correctly +// when you try to reuse the builder to spawn a new task. We'll just +// sidestep that whole issue by making builders uncopyable and making +// the run function move them in. +pub struct TaskBuilder { + // A name for the task-to-be, for identification in panic messages + name: Option, + // The size of the stack for the spawned task + stack_size: Option, + // Task-local stdout + stdout: Option>, + // Task-local stderr + stderr: Option>, + // Optionally wrap the eventual task body + gen_body: Option proc():Send>, + nocopy: marker::NoCopy, +} + +impl TaskBuilder { + /// Generate the base configuration for spawning a task, off of which more + /// configuration methods can be chained. + pub fn new() -> TaskBuilder { unimplemented!() } +} + +impl TaskBuilder { + /// Name the task-to-be. Currently the name is used for identification + /// only in panic messages. + #[unstable = "IntoMaybeOwned will probably change."] + pub fn named>(mut self, name: T) -> TaskBuilder { unimplemented!() } + + /// Set the size of the stack for the new task. + pub fn stack_size(mut self, size: uint) -> TaskBuilder { unimplemented!() } + + /// Redirect task-local stdout. + #[experimental = "May not want to make stdio overridable here."] + pub fn stdout(mut self, stdout: Box) -> TaskBuilder { unimplemented!() } + + /// Redirect task-local stderr. + #[experimental = "May not want to make stdio overridable here."] + pub fn stderr(mut self, stderr: Box) -> TaskBuilder { unimplemented!() } + + // Where spawning actually happens (whether yielding a future or not) + fn spawn_internal(self, f: proc():Send, + on_exit: Option>):Send>) { unimplemented!() } + + /// Creates and executes a new child task. + /// + /// Sets up a new task with its own call stack and schedules it to run + /// the provided proc. The task has the properties and behavior + /// specified by the `TaskBuilder`. + pub fn spawn(self, f: proc():Send) { unimplemented!() } + + /// Execute a proc in a newly-spawned task and return a future representing + /// the task's result. The task has the properties and behavior + /// specified by the `TaskBuilder`. + /// + /// Taking the value of the future will block until the child task + /// terminates. + /// + /// # Return value + /// + /// If the child task executes successfully (without panicking) then the + /// future returns `result::Ok` containing the value returned by the + /// function. If the child task panics then the future returns `result::Err` + /// containing the argument to `panic!(...)` as an `Any` trait object. + #[experimental = "Futures are experimental."] + pub fn try_future(self, f: proc():Send -> T) + -> Future>> { unimplemented!() } + + /// Execute a function in a newly-spawnedtask and block until the task + /// completes or panics. Equivalent to `.try_future(f).unwrap()`. + #[unstable = "Error type may change."] + pub fn try(self, f: proc():Send -> T) -> Result> { unimplemented!() } +} + +/* Convenience functions */ + +/// Creates and executes a new child task +/// +/// Sets up a new task with its own call stack and schedules it to run +/// the provided unique closure. +/// +/// This function is equivalent to `TaskBuilder::new().spawn(f)`. +pub fn spawn(f: proc(): Send) { unimplemented!() } + +/// Execute a function in a newly-spawned task and return either the return +/// value of the function or an error if the task panicked. +/// +/// This is equivalent to `TaskBuilder::new().try`. +#[unstable = "Error type may change."] +pub fn try(f: proc(): Send -> T) -> Result> { unimplemented!() } + +/// Execute a function in another task and return a future representing the +/// task's result. +/// +/// This is equivalent to `TaskBuilder::new().try_future`. +#[experimental = "Futures are experimental."] +pub fn try_future(f: proc():Send -> T) -> Future>> { unimplemented!() } + + +/* Lifecycle functions */ + +/// Read the name of the current task. +#[stable] +pub fn name() -> Option { unimplemented!() } + +/// Yield control to the task scheduler. +#[unstable = "Name will change."] +pub fn deschedule() { unimplemented!() } + +/// True if the running task is currently panicking (e.g. will return `true` inside a +/// destructor that is run while unwinding the stack after a call to `panic!()`). +#[unstable = "May move to a different module."] +pub fn failing() -> bool { unimplemented!() } + +#[test] +fn task_abort_no_kill_runtime() { unimplemented!() } diff --git a/src/libst2/thread_local/mod.rs b/src/libst2/thread_local/mod.rs new file mode 100644 index 0000000000000..1927aaf9da25b --- /dev/null +++ b/src/libst2/thread_local/mod.rs @@ -0,0 +1,313 @@ +// 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. + +//! Thread local storage +//! +//! This module provides an implementation of thread local storage for Rust +//! programs. Thread local storage is a method of storing data into a global +//! variable which each thread in the program will have its own copy of. +//! Threads do not share this data, so accesses do not need to be synchronized. +//! +//! At a high level, this module provides two variants of storage: +//! +//! * Owning thread local storage. This is a type of thread local key which +//! owns the value that it contains, and will destroy the value when the +//! thread exits. This variant is created with the `thread_local!` macro and +//! can contain any value which is `'static` (no borrowed pointers. +//! +//! * Scoped thread local storage. This type of key is used to store a reference +//! to a value into local storage temporarily for the scope of a function +//! call. There are no restrictions on what types of values can be placed +//! into this key. +//! +//! Both forms of thread local storage provide an accessor function, `with`, +//! which will yield a shared reference to the value to the specified +//! closure. Thread local keys only allow shared access to values as there is no +//! way to guarantee uniqueness if a mutable borrow was allowed. Most values +//! will want to make use of some form of **interior mutability** through the +//! `Cell` or `RefCell` types. + +#![macro_escape] +#![experimental] + +use prelude::*; + +use cell::UnsafeCell; + +// Sure wish we had macro hygiene, no? +#[doc(hidden)] pub use self::imp::Key as KeyInner; +#[doc(hidden)] pub use self::imp::destroy_value; +#[doc(hidden)] pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER; +#[doc(hidden)] pub use sys_common::thread_local::StaticKey as OsStaticKey; + +pub mod scoped; + +/// A thread local storage key which owns its contents. +/// +/// This key uses the fastest possible implementation available to it for the +/// target platform. It is instantiated with the `thread_local!` macro and the +/// primary method is the `with` method. +/// +/// The `with` method yields a reference to the contained value which cannot be +/// sent across tasks or escape the given closure. +/// +/// # Initialization and Destruction +/// +/// Initialization is dynamically performed on the first call to `with()` +/// within a thread, and values support destructors which will be run when a +/// thread exits. +/// +/// # Example +/// +/// ``` +/// use std::cell::RefCell; +/// +/// thread_local!(static FOO: RefCell = RefCell::new(1)); +/// +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 1); +/// *f.borrow_mut() = 2; +/// }); +/// +/// // each thread starts out with the initial value of 1 +/// spawn(proc() { +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 1); +/// *f.borrow_mut() = 3; +/// }); +/// }); +/// +/// // we retain our original value of 2 despite the child thread +/// FOO.with(|f| { +/// assert_eq!(*f.borrow(), 2); +/// }); +/// ``` +pub struct Key { + // The key itself may be tagged with #[thread_local], and this `Key` is + // stored as a `static`, and it's not valid for a static to reference the + // address of another thread_local static. For this reason we kinda wonkily + // work around this by generating a shim function which will give us the + // address of the inner TLS key at runtime. + // + // This is trivially devirtualizable by LLVM because we never store anything + // to this field and rustc can declare the `static` as constant as well. + #[doc(hidden)] + pub inner: fn() -> &'static KeyInner>>, + + // initialization routine to invoke to create a value + #[doc(hidden)] + pub init: fn() -> T, +} + +/// Declare a new thread local storage key of type `std::thread_local::Key`. +#[macro_export] +#[doc(hidden)] +macro_rules! thread_local( + (static $name:ident: $t:ty = $init:expr) => ( + static $name: ::std::thread_local::Key<$t> = { + use std::cell::UnsafeCell as __UnsafeCell; + use std::thread_local::KeyInner as __KeyInner; + use std::option::Option as __Option; + use std::option::None as __None; + + __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { + __UnsafeCell { value: __None } + }) + fn __init() -> $t { unimplemented!() } + fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { unimplemented!() } + ::std::thread_local::Key { inner: __getit, init: __init } + }; + ); + (pub static $name:ident: $t:ty = $init:expr) => ( + pub static $name: ::std::thread_local::Key<$t> = { + use std::cell::UnsafeCell as __UnsafeCell; + use std::thread_local::KeyInner as __KeyInner; + use std::option::Option as __Option; + use std::option::None as __None; + + __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { + __UnsafeCell { value: __None } + }) + fn __init() -> $t { unimplemented!() } + fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { unimplemented!() } + ::std::thread_local::Key { inner: __getit, init: __init } + }; + ); +) + +// Macro pain #4586: +// +// When cross compiling, rustc will load plugins and macros from the *host* +// platform before search for macros from the target platform. This is primarily +// done to detect, for example, plugins. Ideally the macro below would be +// defined once per module below, but unfortunately this means we have the +// following situation: +// +// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro +// will inject #[thread_local] statics. +// 2. We then try to compile a program for arm-linux-androideabi +// 3. The compiler has a host of linux and a target of android, so it loads +// macros from the *linux* libstd. +// 4. The macro generates a #[thread_local] field, but the android libstd does +// not use #[thread_local] +// 5. Compile error about structs with wrong fields. +// +// To get around this, we're forced to inject the #[cfg] logic into the macro +// itself. Woohoo. + +#[macro_export] +macro_rules! __thread_local_inner( + (static $name:ident: $t:ty = $init:expr) => ( + #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)] + static $name: ::std::thread_local::KeyInner<$t> = + __thread_local_inner!($init, $t); + ); + (pub static $name:ident: $t:ty = $init:expr) => ( + #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)] + pub static $name: ::std::thread_local::KeyInner<$t> = + __thread_local_inner!($init, $t); + ); + ($init:expr, $t:ty) => ({ + #[cfg(any(target_os = "macos", target_os = "linux"))] + const INIT: ::std::thread_local::KeyInner<$t> = { + ::std::thread_local::KeyInner { + inner: ::std::cell::UnsafeCell { value: $init }, + dtor_registered: ::std::cell::UnsafeCell { value: false }, + dtor_running: ::std::cell::UnsafeCell { value: false }, + marker: ::std::kinds::marker::NoCopy, + } + }; + + #[cfg(not(any(target_os = "macos", target_os = "linux")))] + const INIT: ::std::thread_local::KeyInner<$t> = { + unsafe extern fn __destroy(ptr: *mut u8) { unimplemented!() } + ::std::thread_local::KeyInner { + inner: ::std::cell::UnsafeCell { value: $init }, + os: ::std::thread_local::OsStaticKey { + inner: ::std::thread_local::OS_INIT_INNER, + dtor: ::std::option::Some(__destroy), + }, + } + }; + + INIT + }); +) + +impl Key { + /// Acquire a reference to the value in this TLS key. + /// + /// This will lazily initialize the value if this thread has not referenced + /// this key yet. + /// + /// # Panics + /// + /// This function will `panic!()` if the key currently has its + /// destructor running, and it **may** panic if the destructor has + /// previously been run for this thread. + pub fn with(&'static self, f: |&T| -> R) -> R { unimplemented!() } + + /// Test this TLS key to determine whether its value has been destroyed for + /// the current thread or not. + /// + /// This will not initialize the key if it is not already initialized. + pub fn destroyed(&'static self) -> bool { unimplemented!() } +} + +#[cfg(any(target_os = "macos", target_os = "linux"))] +mod imp { + use prelude::*; + + use cell::UnsafeCell; + use intrinsics; + use kinds::marker; + use ptr; + + #[doc(hidden)] + pub struct Key { + // Place the inner bits in an `UnsafeCell` to currently get around the + // "only Sync statics" restriction. This allows any type to be placed in + // the cell. + // + // Note that all access requires `T: 'static` so it can't be a type with + // any borrowed pointers still. + pub inner: UnsafeCell, + + // Metadata to keep track of the state of the destructor. Remember that + // these variables are thread-local, not global. + pub dtor_registered: UnsafeCell, // should be Cell + pub dtor_running: UnsafeCell, // should be Cell + + // These shouldn't be copied around. + pub marker: marker::NoCopy, + } + + #[doc(hidden)] + impl Key { + pub unsafe fn get(&'static self) -> Option<&'static T> { unimplemented!() } + + unsafe fn register_dtor(&self) { unimplemented!() } + } + + // Since what appears to be glibc 2.18 this symbol has been shipped which + // GCC and clang both use to invoke destructors in thread_local globals, so + // let's do the same! + // + // Note, however, that we run on lots older linuxes, as well as cross + // compiling from a newer linux to an older linux, so we also have a + // fallback implementation to use as well. + // + // Due to rust-lang/rust#18804, make sure this is not generic! + #[cfg(target_os = "linux")] + unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { unimplemented!() } + + // OSX's analog of the above linux function is this _tlv_atexit function. + // The disassembly of thread_local globals in C++ (at least produced by + // clang) will have this show up in the output. + #[cfg(target_os = "macos")] + unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { unimplemented!() } + + #[doc(hidden)] + pub unsafe extern fn destroy_value(ptr: *mut u8) { unimplemented!() } +} + +#[cfg(not(any(target_os = "macos", target_os = "linux")))] +mod imp { + use prelude::*; + + use cell::UnsafeCell; + use mem; + use sys_common::thread_local::StaticKey as OsStaticKey; + + #[doc(hidden)] + pub struct Key { + // Statically allocated initialization expression, using an `UnsafeCell` + // for the same reasons as above. + pub inner: UnsafeCell, + + // OS-TLS key that we'll use to key off. + pub os: OsStaticKey, + } + + struct Value { + key: &'static Key, + value: T, + } + + #[doc(hidden)] + impl Key { + pub unsafe fn get(&'static self) -> Option<&'static T> { unimplemented!() } + + unsafe fn ptr(&'static self) -> Option<*mut T> { unimplemented!() } + } + + #[doc(hidden)] + pub unsafe extern fn destroy_value(ptr: *mut u8) { unimplemented!() } +} diff --git a/src/libst2/thread_local/scoped.rs b/src/libst2/thread_local/scoped.rs new file mode 100644 index 0000000000000..1368adf65609d --- /dev/null +++ b/src/libst2/thread_local/scoped.rs @@ -0,0 +1,199 @@ +// 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. + +//! Scoped thread-local storage +//! +//! This module provides the ability to generate *scoped* thread-local +//! variables. In this sense, scoped indicates that thread local storage +//! actually stores a reference to a value, and this reference is only placed +//! in storage for a scoped amount of time. +//! +//! There are no restrictions on what types can be placed into a scoped +//! variable, but all scoped variables are initialized to the equivalent of +//! null. Scoped thread local stor is useful when a value is present for a known +//! period of time and it is not required to relinquish ownership of the +//! contents. +//! +//! # Example +//! +//! ``` +//! scoped_thread_local!(static FOO: uint) +//! +//! // Initially each scoped slot is empty. +//! assert!(!FOO.is_set()); +//! +//! // When inserting a value, the value is only in place for the duration +//! // of the closure specified. +//! FOO.set(&1, || { +//! FOO.with(|slot| { +//! assert_eq!(*slot, 1); +//! }); +//! }); +//! ``` + +#![macro_escape] + +use prelude::*; + +// macro hygiene sure would be nice, wouldn't it? +#[doc(hidden)] pub use self::imp::KeyInner; +#[doc(hidden)] pub use sys_common::thread_local::INIT as OS_INIT; + +/// Type representing a thread local storage key corresponding to a reference +/// to the type parameter `T`. +/// +/// Keys are statically allocated and can contain a reference to an instance of +/// type `T` scoped to a particular lifetime. Keys provides two methods, `set` +/// and `with`, both of which currently use closures to control the scope of +/// their contents. +pub struct Key { #[doc(hidden)] pub inner: KeyInner } + +/// Declare a new scoped thread local storage key. +/// +/// This macro declares a `static` item on which methods are used to get and +/// set the value stored within. +#[macro_export] +macro_rules! scoped_thread_local( + (static $name:ident: $t:ty) => ( + __scoped_thread_local_inner!(static $name: $t) + ); + (pub static $name:ident: $t:ty) => ( + __scoped_thread_local_inner!(pub static $name: $t) + ); +) + +#[macro_export] +#[doc(hidden)] +macro_rules! __scoped_thread_local_inner( + (static $name:ident: $t:ty) => ( + #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios")), + thread_local)] + static $name: ::std::thread_local::scoped::Key<$t> = + __scoped_thread_local_inner!($t); + ); + (pub static $name:ident: $t:ty) => ( + #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios")), + thread_local)] + pub static $name: ::std::thread_local::scoped::Key<$t> = + __scoped_thread_local_inner!($t); + ); + ($t:ty) => ({ + use std::thread_local::scoped::Key as __Key; + + #[cfg(not(any(windows, target_os = "android", target_os = "ios")))] + const INIT: __Key<$t> = __Key { + inner: ::std::thread_local::scoped::KeyInner { + inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, + } + }; + + #[cfg(any(windows, target_os = "android", target_os = "ios"))] + const INIT: __Key<$t> = __Key { + inner: ::std::thread_local::scoped::KeyInner { + inner: ::std::thread_local::scoped::OS_INIT, + marker: ::std::kinds::marker::InvariantType, + } + }; + + INIT + }) +) + +impl Key { + /// Insert a value into this scoped thread local storage slot for a + /// duration of a closure. + /// + /// While `cb` is running, the value `t` will be returned by `get` unless + /// this function is called recursively inside of `cb`. + /// + /// Upon return, this function will restore the previous value, if any + /// was available. + /// + /// # Example + /// + /// ``` + /// scoped_thread_local!(static FOO: uint) + /// + /// FOO.set(&100, || { + /// let val = FOO.with(|v| *v); + /// assert_eq!(val, 100); + /// + /// // set can be called recursively + /// FOO.set(&101, || { + /// // ... + /// }); + /// + /// // Recursive calls restore the previous value. + /// let val = FOO.with(|v| *v); + /// assert_eq!(val, 100); + /// }); + /// ``` + pub fn set(&'static self, t: &T, cb: || -> R) -> R { unimplemented!() } + + /// Get a value out of this scoped variable. + /// + /// This function takes a closure which receives the value of this + /// variable. + /// + /// # Panics + /// + /// This function will panic if `set` has not previously been called. + /// + /// # Example + /// + /// ```no_run + /// scoped_thread_local!(static FOO: uint) + /// + /// FOO.with(|slot| { + /// // work with `slot` + /// }); + /// ``` + pub fn with(&'static self, cb: |&T| -> R) -> R { unimplemented!() } + + /// Test whether this TLS key has been `set` for the current thread. + pub fn is_set(&'static self) -> bool { unimplemented!() } +} + +#[cfg(not(any(windows, target_os = "android", target_os = "ios")))] +mod imp { + use std::cell::UnsafeCell; + + // FIXME: Should be a `Cell`, but that's not `Sync` + #[doc(hidden)] + pub struct KeyInner { pub inner: UnsafeCell<*mut T> } + + #[doc(hidden)] + impl KeyInner { + #[doc(hidden)] + pub unsafe fn set(&self, ptr: *mut T) { unimplemented!() } + #[doc(hidden)] + pub unsafe fn get(&self) -> *mut T { unimplemented!() } + } +} + +#[cfg(any(windows, target_os = "android", target_os = "ios"))] +mod imp { + use kinds::marker; + use sys_common::thread_local::StaticKey as OsStaticKey; + + #[doc(hidden)] + pub struct KeyInner { + pub inner: OsStaticKey, + pub marker: marker::InvariantType, + } + + #[doc(hidden)] + impl KeyInner { + #[doc(hidden)] + pub unsafe fn set(&self, ptr: *mut T) { unimplemented!() } + #[doc(hidden)] + pub unsafe fn get(&self) -> *mut T { unimplemented!() } + } +} diff --git a/src/libst2/time/duration.rs b/src/libst2/time/duration.rs new file mode 100644 index 0000000000000..ec2d62ff85cb1 --- /dev/null +++ b/src/libst2/time/duration.rs @@ -0,0 +1,557 @@ +// 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. + +//! Temporal quantification + +#![experimental] + +use {fmt, i64}; +use ops::{Add, Sub, Mul, Div, Neg}; +use option::{Option, Some, None}; +use num::Int; +use result::{Result, Ok, Err}; + +/// The number of nanoseconds in a microsecond. +const NANOS_PER_MICRO: i32 = 1000; +/// The number of nanoseconds in a millisecond. +const NANOS_PER_MILLI: i32 = 1000_000; +/// The number of nanoseconds in seconds. +const NANOS_PER_SEC: i32 = 1_000_000_000; +/// The number of microseconds per second. +const MICROS_PER_SEC: i64 = 1000_000; +/// The number of milliseconds per second. +const MILLIS_PER_SEC: i64 = 1000; +/// The number of seconds in a minute. +const SECS_PER_MINUTE: i64 = 60; +/// The number of seconds in an hour. +const SECS_PER_HOUR: i64 = 3600; +/// The number of (non-leap) seconds in days. +const SECS_PER_DAY: i64 = 86400; +/// The number of (non-leap) seconds in a week. +const SECS_PER_WEEK: i64 = 604800; + +macro_rules! try_opt( + ($e:expr) => (match $e { Some(v) => v, None => return None }) +) + + +/// ISO 8601 time duration with nanosecond precision. +/// This also allows for the negative duration; see individual methods for details. +#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Duration { + secs: i64, + nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC +} + +/// The minimum possible `Duration`: `i64::MIN` milliseconds. +pub const MIN: Duration = Duration { + secs: i64::MIN / MILLIS_PER_SEC - 1, + nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +/// The maximum possible `Duration`: `i64::MAX` milliseconds. +pub const MAX: Duration = Duration { + secs: i64::MAX / MILLIS_PER_SEC, + nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI +}; + +impl Duration { + /// Makes a new `Duration` with given number of weeks. + /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn weeks(weeks: i64) -> Duration { + let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of days. + /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn days(days: i64) -> Duration { + let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of hours. + /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn hours(hours: i64) -> Duration { + let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of minutes. + /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. + /// Panics when the duration is out of bounds. + #[inline] + pub fn minutes(minutes: i64) -> Duration { + let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); + Duration::seconds(secs) + } + + /// Makes a new `Duration` with given number of seconds. + /// Panics when the duration is more than `i64::MAX` milliseconds + /// or less than `i64::MIN` milliseconds. + #[inline] + pub fn seconds(seconds: i64) -> Duration { + let d = Duration { secs: seconds, nanos: 0 }; + if d < MIN || d > MAX { + panic!("Duration::seconds out of bounds"); + } + d + } + + /// Makes a new `Duration` with given number of milliseconds. + #[inline] + pub fn milliseconds(milliseconds: i64) -> Duration { + let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); + let nanos = millis as i32 * NANOS_PER_MILLI; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of microseconds. + #[inline] + pub fn microseconds(microseconds: i64) -> Duration { + let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); + let nanos = micros as i32 * NANOS_PER_MICRO; + Duration { secs: secs, nanos: nanos } + } + + /// Makes a new `Duration` with given number of nanoseconds. + #[inline] + pub fn nanoseconds(nanos: i64) -> Duration { + let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); + Duration { secs: secs, nanos: nanos as i32 } + } + + /// Runs a closure, returning the duration of time it took to run the + /// closure. + pub fn span(f: ||) -> Duration { + let before = super::precise_time_ns(); + f(); + Duration::nanoseconds((super::precise_time_ns() - before) as i64) + } + + /// Returns the total number of whole weeks in the duration. + #[inline] + pub fn num_weeks(&self) -> i64 { + self.num_days() / 7 + } + + /// Returns the total number of whole days in the duration. + pub fn num_days(&self) -> i64 { + self.num_seconds() / SECS_PER_DAY + } + + /// Returns the total number of whole hours in the duration. + #[inline] + pub fn num_hours(&self) -> i64 { + self.num_seconds() / SECS_PER_HOUR + } + + /// Returns the total number of whole minutes in the duration. + #[inline] + pub fn num_minutes(&self) -> i64 { + self.num_seconds() / SECS_PER_MINUTE + } + + /// Returns the total number of whole seconds in the duration. + pub fn num_seconds(&self) -> i64 { + // If secs is negative, nanos should be subtracted from the duration. + if self.secs < 0 && self.nanos > 0 { + self.secs + 1 + } else { + self.secs + } + } + + /// Returns the number of nanoseconds such that + /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of + /// nanoseconds in the duration. + fn nanos_mod_sec(&self) -> i32 { + if self.secs < 0 && self.nanos > 0 { + self.nanos - NANOS_PER_SEC + } else { + self.nanos + } + } + + /// Returns the total number of whole milliseconds in the duration, + pub fn num_milliseconds(&self) -> i64 { + // A proper Duration will not overflow, because MIN and MAX are defined + // such that the range is exactly i64 milliseconds. + let secs_part = self.num_seconds() * MILLIS_PER_SEC; + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI; + secs_part + nanos_part as i64 + } + + /// Returns the total number of whole microseconds in the duration, + /// or `None` on overflow (exceeding 2^63 microseconds in either direction). + pub fn num_microseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); + let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; + secs_part.checked_add(nanos_part as i64) + } + + /// Returns the total number of whole nanoseconds in the duration, + /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). + pub fn num_nanoseconds(&self) -> Option { + let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); + let nanos_part = self.nanos_mod_sec(); + secs_part.checked_add(nanos_part as i64) + } + + /// Add two durations, returning `None` if overflow occured. + pub fn checked_add(&self, rhs: &Duration) -> Option { + let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs = try_opt!(secs.checked_add(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// Subtract two durations, returning `None` if overflow occured. + pub fn checked_sub(&self, rhs: &Duration) -> Option { + let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs = try_opt!(secs.checked_sub(1)); + } + let d = Duration { secs: secs, nanos: nanos }; + // Even if d is within the bounds of i64 seconds, + // it might still overflow i64 milliseconds. + if d < MIN || d > MAX { None } else { Some(d) } + } + + /// The minimum possible `Duration`: `i64::MIN` milliseconds. + #[inline] + pub fn min_value() -> Duration { MIN } + + /// The maximum possible `Duration`: `i64::MAX` milliseconds. + #[inline] + pub fn max_value() -> Duration { MAX } + + /// A duration where the stored seconds and nanoseconds are equal to zero. + #[inline] + pub fn zero() -> Duration { + Duration { secs: 0, nanos: 0 } + } + + /// Returns `true` if the duration equals `Duration::zero()`. + #[inline] + pub fn is_zero(&self) -> bool { + self.secs == 0 && self.nanos == 0 + } +} + +impl Neg for Duration { + #[inline] + fn neg(&self) -> Duration { + if self.nanos == 0 { + Duration { secs: -self.secs, nanos: 0 } + } else { + Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } + } + } +} + +impl Add for Duration { + fn add(&self, rhs: &Duration) -> Duration { + let mut secs = self.secs + rhs.secs; + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Sub for Duration { + fn sub(&self, rhs: &Duration) -> Duration { + let mut secs = self.secs - rhs.secs; + let mut nanos = self.nanos - rhs.nanos; + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl Mul for Duration { + fn mul(&self, rhs: &i32) -> Duration { + // Multiply nanoseconds as i64, because it cannot overflow that way. + let total_nanos = self.nanos as i64 * *rhs as i64; + let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); + let secs = self.secs * *rhs as i64 + extra_secs; + Duration { secs: secs, nanos: nanos as i32 } + } +} + +impl Div for Duration { + fn div(&self, rhs: &i32) -> Duration { + let mut secs = self.secs / *rhs as i64; + let carry = self.secs - secs * *rhs as i64; + let extra_nanos = carry * NANOS_PER_SEC as i64 / *rhs as i64; + let mut nanos = self.nanos / *rhs + extra_nanos as i32; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + secs += 1; + } + if nanos < 0 { + nanos += NANOS_PER_SEC; + secs -= 1; + } + Duration { secs: secs, nanos: nanos } + } +} + +impl fmt::Show for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // technically speaking, negative duration is not valid ISO 8601, + // but we need to print it anyway. + let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; + + let days = abs.secs / SECS_PER_DAY; + let secs = abs.secs - days * SECS_PER_DAY; + let hasdate = days != 0; + let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; + + try!(write!(f, "{}P", sign)); + + if hasdate { + try!(write!(f, "{}D", days)); + } + if hastime { + if abs.nanos == 0 { + try!(write!(f, "T{}S", secs)); + } else if abs.nanos % NANOS_PER_MILLI == 0 { + try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)); + } else if abs.nanos % NANOS_PER_MICRO == 0 { + try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)); + } else { + try!(write!(f, "T{}.{:09}S", secs, abs.nanos)); + } + } + Ok(()) + } +} + +// Copied from libnum +#[inline] +fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { + (div_floor_64(this, other), mod_floor_64(this, other)) +} + +#[inline] +fn div_floor_64(this: i64, other: i64) -> i64 { + match div_rem_64(this, other) { + (d, r) if (r > 0 && other < 0) + || (r < 0 && other > 0) => d - 1, + (d, _) => d, + } +} + +#[inline] +fn mod_floor_64(this: i64, other: i64) -> i64 { + match this % other { + r if (r > 0 && other < 0) + || (r < 0 && other > 0) => r + other, + r => r, + } +} + +#[inline] +fn div_rem_64(this: i64, other: i64) -> (i64, i64) { + (this / other, this % other) +} + +#[cfg(test)] +mod tests { + use super::{Duration, MIN, MAX}; + use {i32, i64}; + use option::{Some, None}; + use string::ToString; + + #[test] + fn test_duration() { + assert!(Duration::seconds(1) != Duration::zero()); + assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); + assert_eq!(Duration::seconds(86399) + Duration::seconds(4), + Duration::days(1) + Duration::seconds(3)); + assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); + assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); + assert_eq!(Duration::days(2) + Duration::seconds(86399) + + Duration::nanoseconds(1234567890), + Duration::days(3) + Duration::nanoseconds(234567890)); + assert_eq!(-Duration::days(3), Duration::days(-3)); + assert_eq!(-(Duration::days(3) + Duration::seconds(70)), + Duration::days(-4) + Duration::seconds(86400-70)); + } + + #[test] + fn test_duration_num_days() { + assert_eq!(Duration::zero().num_days(), 0); + assert_eq!(Duration::days(1).num_days(), 1); + assert_eq!(Duration::days(-1).num_days(), -1); + assert_eq!(Duration::seconds(86399).num_days(), 0); + assert_eq!(Duration::seconds(86401).num_days(), 1); + assert_eq!(Duration::seconds(-86399).num_days(), 0); + assert_eq!(Duration::seconds(-86401).num_days(), -1); + assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); + assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); + } + + #[test] + fn test_duration_num_seconds() { + assert_eq!(Duration::zero().num_seconds(), 0); + assert_eq!(Duration::seconds(1).num_seconds(), 1); + assert_eq!(Duration::seconds(-1).num_seconds(), -1); + assert_eq!(Duration::milliseconds(999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); + assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); + assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); + } + + #[test] + fn test_duration_num_milliseconds() { + assert_eq!(Duration::zero().num_milliseconds(), 0); + assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); + assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); + assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); + assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); + assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); + assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); + assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); + assert_eq!(MAX.num_milliseconds(), i64::MAX); + assert_eq!(MIN.num_milliseconds(), i64::MIN); + } + + #[test] + fn test_duration_num_microseconds() { + assert_eq!(Duration::zero().num_microseconds(), Some(0)); + assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); + assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); + assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); + assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_microseconds(), None); + assert_eq!(MIN.num_microseconds(), None); + + // overflow checks + const MICROS_PER_DAY: i64 = 86400_000_000; + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), + Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(), + Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); + assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None); + } + + #[test] + fn test_duration_num_nanoseconds() { + assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); + assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); + assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); + assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); + assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); + assert_eq!(MAX.num_nanoseconds(), None); + assert_eq!(MIN.num_nanoseconds(), None); + + // overflow checks + const NANOS_PER_DAY: i64 = 86400_000_000_000; + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(), + Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); + assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); + assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); + } + + #[test] + fn test_duration_checked_ops() { + assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), + Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999))); + assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000)) + .is_none()); + + assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), + Some(Duration::milliseconds(i64::MIN))); + assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)) + .is_none()); + } + + #[test] + fn test_duration_mul() { + assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); + assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); + assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); + assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); + assert_eq!(Duration::nanoseconds(30) * 333_333_333, + Duration::seconds(10) - Duration::nanoseconds(10)); + assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, + Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3)); + assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); + assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); + } + + #[test] + fn test_duration_div() { + assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); + assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); + assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); + assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); + assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); + assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); + assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); + assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); + assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); + assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); + } + + #[test] + fn test_duration_fmt() { + assert_eq!(Duration::zero().to_string(), "PT0S".to_string()); + assert_eq!(Duration::days(42).to_string(), "P42D".to_string()); + assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string()); + assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string()); + assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string()); + assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string()); + assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string()); + assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), + "P7DT6.543S".to_string()); + assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S".to_string()); + assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S".to_string()); + + // the format specifier should have no effect on `Duration` + assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), + "P1DT2.345S".to_string()); + } +} diff --git a/src/libst2/time/mod.rs b/src/libst2/time/mod.rs new file mode 100644 index 0000000000000..c920dbdc56623 --- /dev/null +++ b/src/libst2/time/mod.rs @@ -0,0 +1,46 @@ +// 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. + +//! Temporal quantification. + +use libc; + +pub use self::duration::Duration; + +pub mod duration; + +/// Returns the current value of a high-resolution performance counter +/// in nanoseconds since an unspecified epoch. +// NB: this is intentionally not public, this is not ready to stabilize its api. +fn precise_time_ns() -> u64 { unimplemented!() } + +#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios")))] +mod imp { + use libc::{c_int, timespec}; + + // Apparently android provides this in some other library? + #[cfg(not(target_os = "android"))] + #[link(name = "rt")] + extern {} + + extern { + pub fn clock_gettime(clk_id: c_int, tp: *mut timespec) -> c_int; + } + +} +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod imp { + use libc::{c_int, mach_timebase_info}; + + extern { + pub fn mach_absolute_time() -> u64; + pub fn mach_timebase_info(info: *mut mach_timebase_info) -> c_int; + } +} From 1c42d2dbcd82f45cdf2d19a34ea2e0a0be7f9d44 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:36:20 +0100 Subject: [PATCH 24/65] re-add pipe::read impl to libst2. --- src/libst2/sys/unix/pipe.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libst2/sys/unix/pipe.rs b/src/libst2/sys/unix/pipe.rs index 7f09e8bbc0505..f328e409b510b 100644 --- a/src/libst2/sys/unix/pipe.rs +++ b/src/libst2/sys/unix/pipe.rs @@ -73,7 +73,18 @@ impl UnixStream { #[cfg(not(target_os = "linux"))] fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } + pub fn read(&mut self, buf: &mut [u8]) -> IoResult { + let fd = self.fd(); + let dolock = || self.lock_nonblocking(); + let doread = |nb| unsafe { + let flags = if nb {c::MSG_DONTWAIT} else {0}; + libc::recv(fd, + buf.as_mut_ptr() as *mut libc::c_void, + buf.len() as libc::size_t, + flags) as libc::c_int + }; + read(fd, self.read_deadline, dolock, doread) + } pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } From c110f29e85f5a22991ffe50eca882464c4d3639e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:37:23 +0100 Subject: [PATCH 25/65] rustc::middle::borrowck::gather_loans::lifetime: revise debug instrumentation. --- src/librustc/middle/borrowck/gather_loans/lifetime.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 619ffc1ae1438..130ad4d42532f 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -96,9 +96,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { fn check_scope(&self, max_scope: ty::Region) -> R { //! Reports an error if `loan_region` is larger than `max_scope` - debug!("check_scope max_scope: {} self.loan_region: {}", - max_scope.repr(self.bccx.tcx), - self.loan_region.repr(self.bccx.tcx)); + debug!("check_scope self.loan_region: {} max_scope: {}", + self.loan_region.repr(self.bccx.tcx), + max_scope.repr(self.bccx.tcx)); if !self.bccx.is_subregion_of(self.loan_region, max_scope) { Err(self.report_error(err_out_of_scope(max_scope, self.loan_region))) } else { From 968be6f5242804051446d6ce13027ce6c79b42ef Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:37:50 +0100 Subject: [PATCH 26/65] rustc::middle::typeck::infer::region_inference add more debug instrumentation. --- .../typeck/infer/region_inference/mod.rs | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index d1179a8db91cf..8ad3b5ab248e2 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -714,7 +714,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { } fn lub_concrete_regions(&self, a: Region, b: Region) -> Region { - match (a, b) { + debug!("lub_concrete_regions(a: {}, b: {})", a, b); + let ret = match (a, b) { (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReEarlyBound(..), _) | @@ -780,7 +781,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { (_, ReInfer(ReSkolemized(..))) => { if a == b {a} else {ReStatic} } - } + }; + debug!("lub_concrete_regions(a: {}, b: {}) returns {}", a, b, ret); + ret } fn lub_free_regions(&self, @@ -793,11 +796,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { * in any order, a consistent result is returned. */ - return match a.cmp(b) { + debug!("lub_free_regions(a: {}, b: {})", a, b); + let ret = match a.cmp(b) { Less => helper(self, a, b), Greater => helper(self, b, a), Equal => ty::ReFree(*a) }; + debug!("lub_free_regions(a: {}, b: {}) returns {}", a, b, ret); + return ret; fn helper(this: &RegionVarBindings, a: &FreeRegion, @@ -818,7 +824,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { b: Region) -> cres<'tcx, Region> { debug!("glb_concrete_regions({}, {})", a, b); - match (a, b) { + let ret = match (a, b) { (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReEarlyBound(..), _) | @@ -881,7 +887,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { Err(ty::terr_regions_no_overlap(b, a)) } } - } + }; + debug!("glb_concrete_regions(a: {}, b: {}) returns {}", a, b, ret); + ret } fn glb_free_regions(&self, @@ -894,11 +902,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { * in any order, a consistent result is returned. */ - return match a.cmp(b) { + debug!("glb_free_regions(a: {}, b: {})", a, b); + let ret = match a.cmp(b) { Less => helper(self, a, b), Greater => helper(self, b, a), Equal => Ok(ty::ReFree(*a)) }; + debug!("glb_free_regions(a: {}, b: {}) returns {}", a, b, ret); + return ret; fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, a: &FreeRegion, @@ -927,11 +938,14 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // it. Otherwise fail. debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={})", scope_a, scope_b, region_a, region_b); - match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) { + let ret = match self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b) { Some(r_id) if scope_a == r_id => Ok(ReScope(scope_b)), Some(r_id) if scope_b == r_id => Ok(ReScope(scope_a)), _ => Err(ty::terr_regions_no_overlap(region_a, region_b)) - } + }; + debug!("intersect_scopes(scope_a={}, scope_b={}, region_a={}, region_b={}) returns {}", + scope_a, scope_b, region_a, region_b, ret); + return ret; } } From 6e5fff063dfa05fac7f60e1fe1bf5098828cf243 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:39:13 +0100 Subject: [PATCH 27/65] rustc::middle::typeck::check::dropck remove source of ReFunction. includes debug output noting that we could have produced ReFunction here. --- src/librustc/middle/typeck/check/dropck.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index 8056a5dba3d5f..292c4dad285c1 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -37,12 +37,23 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, } // Get the parent scope. + let mut could_have_been_re_function = false; let parent_inner_region = match rcx.tcx().region_maps.opt_encl_scope(inner_scope) { - None | Some(region::CodeExtent::Closure(_)) => ty::ReFunction, + None => ty::ReFunction, + // FIXME (onkfelix): if closures need not be handled specially, + // then perhaps I can/should do away with ReFunction entirely. + Some(parent_inner_scope @ region::CodeExtent::Closure(_)) => { + could_have_been_re_function = true; + // ty::ReFunction + ty::ReScope(parent_inner_scope) + } Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), }; + debug!("constrain_region_for_destructor_safety region: {} :> parent_inner_region: {} (from inner_scope: {}){}", + region, parent_inner_region, inner_scope, + if could_have_been_re_function { " could_have_been_re_function" } else { "" }); rcx.tcx().sess.span_note( span, format!("constrain_region_for_destructor_safety \ From b9ebb3e704a5911a97d9be597bfe07ad0209f788 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:40:51 +0100 Subject: [PATCH 28/65] rustc::middle::region local check for trivial cyclic encl region scope. --- src/librustc/middle/region.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 8d10829e4bb9a..554571beeb3b8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -192,6 +192,8 @@ impl RegionMaps { fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { debug!("record_encl_scope(sub={}, sup={})", sub, sup); assert!(sub != sup); + assert!(self.scope_map.borrow().get(&sup) != Some(&sub), + "cyclic encl scope sub: {} sup: {}", sub, sup); self.scope_map.borrow_mut().insert(sub, sup); } From b5229637192ca7eb4c21a2255433dae0d2e34644 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:42:27 +0100 Subject: [PATCH 29/65] rustc::middle::region added debug instrumentation to `fn ancestors_of`. --- src/librustc/middle/region.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 554571beeb3b8..fca2bdf39eafc 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -426,7 +426,7 @@ impl RegionMaps { fn ancestors_of(this: &RegionMaps, scope: CodeExtent) -> Vec { - // debug!("ancestors_of(scope={})", scope); + debug!("ancestors_of(scope={})", scope); let mut result = vec!(scope); let mut scope = scope; loop { @@ -437,7 +437,7 @@ impl RegionMaps { scope = superscope; } } - // debug!("ancestors_of_loop(scope={})", scope); + debug!("ancestors_of_loop(scope={})", scope); } } } @@ -475,6 +475,7 @@ fn record_superlifetime(visitor: &mut RegionResolutionVisitor, fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, var_id: ast::NodeId, _sp: Span) { + debug!("record_var_lifetime var_id: {}", var_id); match visitor.cx.var_parent { InnermostDeclaringBlock::Some(parent_id) => { let parent_scope = CodeExtent::from_node_id(parent_id); From 0e77b13d7f0e20ae2bdb4f9f1b48f4a4c2805279 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Dec 2014 11:43:31 +0100 Subject: [PATCH 30/65] rustc::middle::region attempt to introduce CodeExtent::Closure and CodeExtent::Misc differentiation. --- src/librustc/middle/region.rs | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index fca2bdf39eafc..ce4f204d4184c 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -445,7 +445,7 @@ impl RegionMaps { /// Records the current parent (if any) as the parent of `child_id`. fn record_superlifetime(visitor: &mut RegionResolutionVisitor, - child_id: ast::NodeId, + child_scope: CodeExtent, _sp: Span) { // FIXME (pnkfelix): currently this is redundantly adding entries // for both a specific variant (Closure in this case) as well as @@ -455,16 +455,10 @@ fn record_superlifetime(visitor: &mut RegionResolutionVisitor, match visitor.cx.parent { InnermostEnclosingExpr::Some(parent_id) => { let parent_scope = CodeExtent::from_node_id(parent_id); - let child_scope = CodeExtent::Misc(child_id); - visitor.region_maps.record_encl_scope(child_scope, parent_scope); - let child_scope = CodeExtent::Closure(child_id); visitor.region_maps.record_encl_scope(child_scope, parent_scope); } InnermostEnclosingExpr::Closure(closure_id) => { let parent_scope = CodeExtent::Closure(closure_id); - let child_scope = CodeExtent::Misc(child_id); - visitor.region_maps.record_encl_scope(child_scope, parent_scope); - let child_scope = CodeExtent::Closure(child_id); visitor.region_maps.record_encl_scope(child_scope, parent_scope); } InnermostEnclosingExpr::None => {} @@ -493,7 +487,7 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { debug!("resolve_block(blk.id={})", blk.id); // Record the parent of this block. - record_superlifetime(visitor, blk.id, blk.span); + record_superlifetime(visitor, CodeExtent::Misc(blk.id), blk.span); // We treat the tail expression in the block (if any) somewhat // differently from the statements. The issue has to do with @@ -529,7 +523,9 @@ fn resolve_arm(visitor: &mut RegionResolutionVisitor, arm: &ast::Arm) { } fn resolve_pat(visitor: &mut RegionResolutionVisitor, pat: &ast::Pat) { - record_superlifetime(visitor, pat.id, pat.span); + debug!("resolve_pat(pat.id={})", pat.id); + + record_superlifetime(visitor, CodeExtent::Misc(pat.id), pat.span); // If this is a binding (or maybe a binding, I'm too lazy to check // the def map) then record the lifetime of that binding. @@ -549,7 +545,7 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { let stmt_scope = CodeExtent::from_node_id(stmt_id); visitor.region_maps.mark_as_terminating_scope(stmt_scope); - record_superlifetime(visitor, stmt_id, stmt.span); + record_superlifetime(visitor, CodeExtent::Misc(stmt_id), stmt.span); let prev_parent = visitor.cx.parent; visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id); @@ -560,7 +556,7 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { debug!("resolve_expr(expr.id={})", expr.id); - record_superlifetime(visitor, expr.id, expr.span); + record_superlifetime(visitor, CodeExtent::Misc(expr.id), expr.span); let prev_cx = visitor.cx; visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id); @@ -918,11 +914,24 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, body.id, visitor.cx.parent); + let outer_cx = visitor.cx; + + match fk { + visit::FkFnBlock(..) => { + // A closure's body is enclosed by the closure's original + // expression. (and the block that forms that body is + // itself enclosed by the closure body.) + // + // FiXME (pnkfelix): clean all this up, there must be a + // cleaner construction and/or presentation. + record_superlifetime(visitor, CodeExtent::Closure(id), sp); + } + _ => {} + } + let body_scope = CodeExtent::from_node_id(body.id); visitor.region_maps.mark_as_terminating_scope(body_scope); - let outer_cx = visitor.cx; - // The arguments and `self` are parented to the body of the fn. visitor.cx = Context { parent: InnermostEnclosingExpr::Some(body.id), From b1d0a791c34a5be7be795994ea967cd3c0ac6bb0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:27:44 +0100 Subject: [PATCH 31/65] fixes for new rules for lifetimes and destructors. note that some of these cases may actually be fixes to latent bugs, in some sense (depending on what our guarantees are about e.g. what a hashmap should be allowed to access in its own destructor). --- src/libregex/vm.rs | 6 ++++-- src/test/auxiliary/issue-2631-a.rs | 3 ++- src/test/run-pass/issue-3026.rs | 2 +- .../multidispatch-conditional-impl-not-considered.rs | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libregex/vm.rs b/src/libregex/vm.rs index 79019d213b8ba..aae1b9830a03e 100644 --- a/src/libregex/vm.rs +++ b/src/libregex/vm.rs @@ -116,8 +116,10 @@ impl<'r, 't> Nfa<'r, 't> { }; let mut matched = false; let ninsts = self.prog.insts.len(); - let mut clist = &mut Threads::new(self.which, ninsts, ncaps); - let mut nlist = &mut Threads::new(self.which, ninsts, ncaps); + let mut cthread = Threads::new(self.which, ninsts, ncaps); + let mut nthread = Threads::new(self.which, ninsts, ncaps); + let mut clist = &mut cthread; + let mut nlist = &mut nthread; let mut groups = Vec::from_elem(ncaps * 2, None); diff --git a/src/test/auxiliary/issue-2631-a.rs b/src/test/auxiliary/issue-2631-a.rs index e340331dbfd11..dd1ad413a3d27 100644 --- a/src/test/auxiliary/issue-2631-a.rs +++ b/src/test/auxiliary/issue-2631-a.rs @@ -19,5 +19,6 @@ pub type header_map = HashMap>>>>; // the unused ty param is necessary so this gets monomorphized pub fn request(req: &header_map) { - let _x = req["METHOD".to_string()].clone().borrow().clone()[0].clone(); + let data = req["METHOD".to_string()].clone(); + let _x = data.borrow().clone()[0].clone(); } diff --git a/src/test/run-pass/issue-3026.rs b/src/test/run-pass/issue-3026.rs index b30c0a117a805..377507dcc77f3 100644 --- a/src/test/run-pass/issue-3026.rs +++ b/src/test/run-pass/issue-3026.rs @@ -14,7 +14,7 @@ extern crate collections; use std::collections::HashMap; pub fn main() { - let mut buggy_map: HashMap = HashMap::new(); let x = box 1; + let mut buggy_map: HashMap = HashMap::new(); buggy_map.insert(42, &*x); } diff --git a/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs b/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs index 5db5a6267bf2b..49ecef9c7359a 100644 --- a/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs +++ b/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs @@ -29,5 +29,5 @@ impl Bar { fn main() { let b = RefCell::new(Bar); - b.borrow().foo() + b.borrow().foo(); } From b0b8caca9e6fe91e8b2f81d0da4623ec64c5b301 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:33:24 +0100 Subject: [PATCH 32/65] Added DestructionScope variant to CodeExtent, representing the area immediately surrounding a node that is a terminating_scope (e.g. statements, looping forms) during which the destructors run (the destructors for temporaries from the execution of that node, that is). --- src/librustc/metadata/tydecode.rs | 4 ++++ src/librustc/metadata/tyencode.rs | 3 ++- src/librustc/middle/region.rs | 24 ++++++++++++++++++++++-- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 806b7d42fbb97..70dd275d2bfa9 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -348,6 +348,10 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent { let node_id = parse_uint(st) as ast::NodeId; region::CodeExtent::Closure(node_id) } + 'D' => { + let node_id = parse_uint(st) as ast::NodeId; + region::CodeExtent::DestructionScope(node_id) + } 'B' => { let node_id = parse_uint(st) as ast::NodeId; let first_stmt_index = parse_uint(st); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 25bb19286f3f9..5cd575031dca3 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -173,7 +173,8 @@ fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) { region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id), region::CodeExtent::Closure(node_id) => mywrite!(w, "C{}", node_id), region::CodeExtent::Remainder(region::BlockRemainder { - block: block, first_statement_index: i }) => mywrite!(w, "B{}{}", block, i), + block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i), + region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id), } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index ce4f204d4184c..4596cdd6c8ba5 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -44,12 +44,28 @@ use syntax::visit::{Visitor, FnKind}; #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub enum CodeExtent { Misc(ast::NodeId), + DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id Closure(ast::NodeId), Remainder(BlockRemainder), } -/// Represents a subscope of `block` that starts at -/// `block.stmts[first_statement_index]` (inclusive). +/// Represents a subscope of `block` for a binding that is introduced +/// by `block.stmts[first_statement_index]`. Such subscopes represent +/// a suffix of the block. Note that each subscope does not include +/// the initializer expression, if any, for the statement indexed by +/// `first_statement_index`. +/// +/// For example, given `{ let (a, b) = EXPR_1; let c = EXPR_2; ... }`: +/// +/// * the subscope with `first_statement_index == 0` is scope of both +/// `a` and `b`; it does not include EXPR_1, but does include +/// everything after that first `let`. (If you want a scope that +/// includes EXPR_1 as well, then do not use `CodeExtent::Remainder`, +/// but instead another `CodeExtent` that encompasses the whole block, +/// e.g. `CodeExtent::Misc`. +/// +/// * the subscope with `first_statement_index == 1` is scope of `c`, +/// and thus does not include EXPR_2, but covers the `...`. #[deriving(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, Encodable, Decodable, Show)] pub struct BlockRemainder { pub block: ast::NodeId, @@ -72,6 +88,8 @@ impl CodeExtent { CodeExtent::Misc(node_id) => node_id, CodeExtent::Closure(node_id) => node_id, CodeExtent::Remainder(br) => br.block, + // FIXME (pnkfelix): very sketchy here. + CodeExtent::DestructionScope(node_id) => node_id, } } @@ -83,6 +101,8 @@ impl CodeExtent { CodeExtent::Closure(node_id) => CodeExtent::Closure(f_id(node_id)), CodeExtent::Remainder(br) => CodeExtent::Remainder(BlockRemainder { block: f_id(br.block), ..br }), + CodeExtent::DestructionScope(node_id) => + CodeExtent::DestructionScope(f_id(node_id)), } } } From ec5a3214b2483fe575eef4ddaa16478f225aeb71 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:34:38 +0100 Subject: [PATCH 33/65] improved descriptions and `.repr(tcx)` output for DestructionScope and Remainder. --- src/librustc/util/ppaux.rs | 80 ++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 761a1f66501ca..c7ba82bb3918a 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -12,6 +12,7 @@ use middle::def; use middle::subst::{VecPerParamSpace,Subst}; use middle::subst; +use middle::region::{mod, CodeExtent}; use middle::ty::{BoundRegion, BrAnon, BrNamed}; use middle::ty::{ReEarlyBound, BrFresh, ctxt}; use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; @@ -84,31 +85,56 @@ fn item_scope_tag(item: &ast::Item) -> &'static str { pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) -> (String, Option) { return match region { - ReScope(scope) => { - match cx.map.find(scope.node_id()) { + ReScope(scope @ CodeExtent::Misc(_)) | + ReScope(scope @ CodeExtent::Closure(_)) | + ReScope(scope @ CodeExtent::DestructionScope(_)) => { + let node_id = scope.node_id(); + let prefix = if let CodeExtent::DestructionScope(dtor_id) = scope { + "destruction scope surrounding" + } else { + "" + }; + match cx.map.find(node_id) { Some(ast_map::NodeBlock(ref blk)) => { - explain_span(cx, "block", blk.span) + let place = format!("{}{}", prefix, "block"); + explain_span(cx, place.as_slice(), blk.span) } Some(ast_map::NodeExpr(expr)) => { match expr.node { - ast::ExprCall(..) => explain_span(cx, "call", expr.span), + ast::ExprCall(..) => { + let place = format!("{}{}", prefix, "call"); + explain_span(cx, place.as_slice(), expr.span) + }, ast::ExprMethodCall(..) => { - explain_span(cx, "method call", expr.span) + let place = format!("{}{}", prefix, "method call"); + explain_span(cx, place.as_slice(), expr.span) + }, + ast::ExprMatch(_, _, ast::MatchIfLetDesugar) => { + let place = format!("{}{}", prefix, "if let"); + explain_span(cx, place.as_slice(), expr.span) }, - ast::ExprMatch(_, _, ast::MatchIfLetDesugar) => explain_span(cx, "if let", expr.span), ast::ExprMatch(_, _, ast::MatchWhileLetDesugar) => { - explain_span(cx, "while let", expr.span) + let place = format!("{}{}", prefix, "while let"); + explain_span(cx, place.as_slice(), expr.span) + }, + ast::ExprMatch(..) => { + let place = format!("{}{}", prefix, "match"); + explain_span(cx, place.as_slice(), expr.span) }, - ast::ExprMatch(..) => explain_span(cx, "match", expr.span), - _ => explain_span(cx, "expression", expr.span) + _ => { + let place = format!("{}{}", prefix, "expression"); + explain_span(cx, place.as_slice(), expr.span) + } } } Some(ast_map::NodeStmt(stmt)) => { - explain_span(cx, "statement", stmt.span) + let place = format!("{}{}", prefix, "statement"); + explain_span(cx, place.as_slice(), stmt.span) } Some(ast_map::NodeItem(it)) => { let tag = item_scope_tag(&*it); - explain_span(cx, tag, it.span) + let place = format!("{}{}", prefix, tag); + explain_span(cx, place.as_slice(), it.span) } Some(_) | None => { // this really should not happen @@ -117,6 +143,20 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) } } + ReScope(CodeExtent::Remainder( + region::BlockRemainder { block: block_id, first_statement_index })) => { + match cx.map.find(block_id) { + Some(ast_map::NodeBlock(ref blk)) => { + let stmt_span = blk.stmts[first_statement_index].span; + let place = "block suffix"; + explain_span(cx, place, Span { lo: stmt_span.hi, ..blk.span }) + } + _ => { + cx.sess.bug("failed to find block for BlockRemainder") + } + } + } + ReFree(ref fr) => { let prefix = match fr.bound_region { BrAnon(idx) => { @@ -879,11 +919,27 @@ impl<'tcx> UserString<'tcx> for ty::Region { impl<'tcx> Repr<'tcx> for ty::FreeRegion { fn repr(&self, tcx: &ctxt) -> String { format!("ReFree({}, {})", - self.scope.node_id(), + self.scope.repr(tcx), self.bound_region.repr(tcx)) } } +impl<'tcx> Repr<'tcx> for region::CodeExtent { + fn repr(&self, tcx: &ctxt) -> String { + match *self { + region::CodeExtent::Misc(node_id) => + format!("Misc({})", node_id), + region::CodeExtent::DestructionScope(node_id) => + format!("DestructionScope({})", node_id), + region::CodeExtent::Closure(node_id) => + format!("Closure({})", node_id), + region::CodeExtent::Remainder(region::BlockRemainder { + block: node_id, first_statement_index, }) => + format!("Remainder({}, {})", node_id, first_statement_index), + } + } +} + impl<'tcx> Repr<'tcx> for ast::DefId { fn repr(&self, tcx: &ctxt) -> String { // Unfortunately, there seems to be no way to attempt to print From b9b36cb87d4ea5bc3538d0d264e022068ca5c6b3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:35:14 +0100 Subject: [PATCH 34/65] fix typo in comment in region_inference/mod.rs. --- src/librustc/middle/typeck/infer/region_inference/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/typeck/infer/region_inference/mod.rs b/src/librustc/middle/typeck/infer/region_inference/mod.rs index 8ad3b5ab248e2..8f5679fe2b012 100644 --- a/src/librustc/middle/typeck/infer/region_inference/mod.rs +++ b/src/librustc/middle/typeck/infer/region_inference/mod.rs @@ -750,7 +750,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: match self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) { - // if the free region's scope `fr.scope_id` is bigger than + // if the free region's scope `fr.scope` is bigger than // the scope region `s_id`, then the LUB is the free // region itself: Some(r_id) if r_id == fr.scope => f, From 7540ac99af84faeb40672ee0111d3621bdd2a2fd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:39:14 +0100 Subject: [PATCH 35/65] Switch to constructing DestructionScope rather than Misc in a number of places, mostly related to `ty::ReFree` creation. --- src/librustc/middle/mem_categorization.rs | 5 ++- src/librustc/middle/resolve_lifetime.rs | 10 ++++-- src/librustc/middle/ty.rs | 38 ++++++++++++++--------- src/librustc/middle/typeck/check/mod.rs | 10 +++--- src/librustc/middle/typeck/collect.rs | 2 +- 5 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5556b1132695a..6602c8cc95bf3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -711,7 +711,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { // Region of environment pointer let env_region = ty::ReFree(ty::FreeRegion { - scope: region::CodeExtent::from_node_id(fn_body_id), + // The environment of a closure is guaranteed to + // outlive any bindings introduced in the body of the + // closure itself. + scope: region::CodeExtent::DestructionScope(fn_body_id), bound_region: ty::BrEnv }); diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index fae64ff924274..84f44541efa1b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -22,7 +22,7 @@ use self::ScopeChain::*; use session::Session; use middle::def; -use middle::region; +use middle::region::{mod, CodeExtent}; use middle::resolve::DefMap; use middle::subst; use middle::ty; @@ -310,7 +310,13 @@ impl<'a> LifetimeContext<'a> { loop { match *scope { BlockScope(blk_scope, s) => { - return self.resolve_free_lifetime_ref(blk_scope, lifetime_ref, s); + if let CodeExtent::Misc(node_id) = blk_scope { + let d = CodeExtent::DestructionScope(node_id); + return self.resolve_free_lifetime_ref(d, lifetime_ref, s); + } else { + self.sess.bug( + "found unexpected CodeExtent associated with blk_scope") + } } RootScope => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 8be9ed37ca757..a7c55865e036e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3561,12 +3561,15 @@ pub fn ty_region(tcx: &ctxt, } } -pub fn free_region_from_def(free_id: ast::NodeId, def: &RegionParameterDef) +pub fn free_region_from_def(outlives_extent: region::CodeExtent, def: &RegionParameterDef) -> ty::Region { - ty::ReFree(ty::FreeRegion { scope: region::CodeExtent::from_node_id(free_id), - bound_region: ty::BrNamed(def.def_id, - def.name) }) + let ret = + ty::ReFree(ty::FreeRegion { scope: outlives_extent, + bound_region: ty::BrNamed(def.def_id, + def.name) }); + debug!("free_region_from_def returns {}", ret); + ret } // Returns the type of a pattern as a monotype. Like @expr_ty, this function @@ -5616,10 +5619,12 @@ pub fn construct_parameter_environment<'tcx>( generics.types.get_slice(space)); } + let free_id_outlive = region::CodeExtent::DestructionScope(free_id); + // map bound 'a => free 'a let mut regions = VecPerParamSpace::empty(); for &space in subst::ParamSpace::all().iter() { - push_region_params(&mut regions, space, free_id, + push_region_params(&mut regions, space, free_id_outlive, generics.regions.get_slice(space)); } @@ -5628,14 +5633,12 @@ pub fn construct_parameter_environment<'tcx>( regions: subst::NonerasedRegions(regions) }; - let free_id_scope = region::CodeExtent::from_node_id(free_id); - // // Compute the bounds on Self and the type parameters. // let bounds = generics.to_bounds(tcx, &free_substs); - let bounds = liberate_late_bound_regions(tcx, free_id_scope, &bind(bounds)).value; + let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &bind(bounds)).value; let obligations = traits::obligations_for_generics(tcx, traits::ObligationCause::misc(span), &bounds, @@ -5663,18 +5666,18 @@ pub fn construct_parameter_environment<'tcx>( return ty::ParameterEnvironment { free_substs: free_substs, bounds: bounds.types, - implicit_region_bound: ty::ReScope(free_id_scope), + implicit_region_bound: ty::ReScope(free_id_outlive), caller_obligations: obligations, selection_cache: traits::SelectionCache::new(), }; fn push_region_params(regions: &mut VecPerParamSpace, space: subst::ParamSpace, - free_id: ast::NodeId, + all_outlive_extent: region::CodeExtent, region_params: &[RegionParameterDef]) { for r in region_params.iter() { - regions.push(space, ty::free_region_from_def(free_id, r)); + regions.push(space, ty::free_region_from_def(all_outlive_extent, r)); } } @@ -5907,19 +5910,26 @@ impl<'tcx> AutoDerefRef<'tcx> { pub fn liberate_late_bound_regions<'tcx, HR>( tcx: &ty::ctxt<'tcx>, - scope: region::CodeExtent, + all_outlive_scope: region::CodeExtent, value: &HR) -> HR where HR : HigherRankedFoldable<'tcx> { /*! * Replace any late-bound regions bound in `value` with free variants - * attached to scope-id `scope_id`. + * guaranteed to outlive `all_outlive_scope`. */ replace_late_bound_regions( tcx, value, - |br, _| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0 + |br, _| { + let ret = + ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, + bound_region: br}); + debug!("liberate_late_bound_regions replace_late_bound_regions \ + callback returns {}", ret); + ret + }).0 } pub fn erase_late_bound_regions<'tcx, HR>( diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index cb6ed5b9d08ce..baadceb98089e 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -87,7 +87,7 @@ use middle::{const_eval, def, traits}; use middle::lang_items::IteratorItem; use middle::mem_categorization::{mod, McResult}; use middle::pat_util::{mod, pat_id_map}; -use middle::region::CodeExtent; +use middle::region::{mod, CodeExtent}; use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::ty::{FnSig, VariantInfo, Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; @@ -511,7 +511,7 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, // First, we have to replace any bound regions in the fn type with free ones. // The free region references will be bound the node_id of the body block. - let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::from_node_id(body.id), fn_sig); + let fn_sig = liberate_late_bound_regions(tcx, CodeExtent::DestructionScope(body.id), fn_sig); let arg_tys = fn_sig.inputs.as_slice(); let ret_ty = fn_sig.output; @@ -725,7 +725,7 @@ fn check_method_body<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let body_id = method.pe_body().id; let fty = liberate_late_bound_regions( - ccx.tcx, CodeExtent::from_node_id(body_id), &ty::bind(fty)).value; + ccx.tcx, CodeExtent::DestructionScope(body_id), &ty::bind(fty)).value; debug!("fty (liberated): {}", fty.repr(ccx.tcx)); check_bare_fn(ccx, @@ -920,7 +920,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method(impl_trait_ref={})", impl_trait_ref.repr(tcx)); - let impl_m_body_scope = CodeExtent::from_node_id(impl_m_body_id); + let impl_m_body_scope = CodeExtent::DestructionScope(impl_m_body_id); // The impl's trait ref may bind late-bound regions from the impl. // Liberate them and assign them the scope of the method body. @@ -1067,7 +1067,7 @@ fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, |d| ty::mk_param_from_def(tcx, d)); let skol_regions = impl_m.generics.regions.map( - |l| ty::free_region_from_def(impl_m_body_id, l)); + |l| ty::free_region_from_def(impl_m_body_scope, l)); let impl_to_skol_substs = subst::Substs::new(skol_tps.clone(), skol_regions.clone()); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 13a0bf0bdcb52..1b2803862f0d9 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -2162,7 +2162,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( _ => typ, }; - let body_scope = region::CodeExtent::from_node_id(body_id); + let body_scope = region::CodeExtent::DestructionScope(body_id); // "Required type" comes from the trait definition. It may // contain late-bound regions from the method, but not the From 33334102dcaa541ee58351f5436a9ea73fc24daa Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:39:39 +0100 Subject: [PATCH 36/65] `debug!` instrumentation in rustc::middle::borrowck::check_loans. --- src/librustc/middle/borrowck/check_loans.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 238a4ca7bd69e..52a322cd7484a 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -239,6 +239,10 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let tcx = self.tcx(); self.each_issued_loan(scope, |loan| { + debug!("each_in_scope_loan scope: {} loan: {} loan.kill_scope: {}", + scope.repr(self.tcx()), + loan.repr(self.tcx()), + loan.kill_scope.repr(self.tcx())); if tcx.region_maps.is_subscope_of(scope, loan.kill_scope) { op(loan) } else { @@ -265,6 +269,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { let loan_path = owned_ptr_base_path(loan_path); let cont = self.each_in_scope_loan(scope, |loan| { let mut ret = true; + debug!("each_in_scope_loan_affecting_path \ + scope: {} loan_path: {} restricted_paths: {}", + scope.repr(self.tcx()), + loan_path.repr(self.tcx()), + loan.restricted_paths.repr(self.tcx())); for restr_path in loan.restricted_paths.iter() { if **restr_path == *loan_path { if !op(loan) { @@ -304,6 +313,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } let cont = self.each_in_scope_loan(scope, |loan| { + debug!("each_in_scope_loan_affecting_path \ + scope: {} loan_path: {} loan: {}", + scope.repr(self.tcx()), + loan_path.repr(self.tcx()), + loan.repr(self.tcx())); + if *loan.loan_path == *loan_path { op(loan) } else { From 9a8c11b7e2af0ba0ca156589ed54c91f1da573ff Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:40:03 +0100 Subject: [PATCH 37/65] `debug!` instrumentation in rustc::middle::resolve_lifetime. --- src/librustc/middle/resolve_lifetime.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 84f44541efa1b..b68bc9fea5866 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -392,6 +392,9 @@ impl<'a> LifetimeContext<'a> { match search_result { Some((_depth, decl_id)) => { let def = DefFreeRegion(scope_data, decl_id); + debug!("resolve_free_lifetime_ref: \ + insert_lifetime(lifetime_ref: {} def: {})", + lifetime_ref, def); self.insert_lifetime(lifetime_ref, def); } From c453c3b68f0c53d9c2ac3becbc0fd930459c0828 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:40:38 +0100 Subject: [PATCH 38/65] Removed `ty::ReFunction` from rustc::middle::typeck::check::dropck. --- src/librustc/middle/typeck/check/dropck.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index 292c4dad285c1..67e15ac03dec4 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -32,7 +32,7 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, // Ignore bound regions. match region { ty::ReEarlyBound(..) | ty::ReLateBound(..) => return, - ty::ReFunction | ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | + ty::ReFree(_) | ty::ReScope(_) | ty::ReStatic | ty::ReInfer(_) | ty::ReEmpty => {} } @@ -40,7 +40,9 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, let mut could_have_been_re_function = false; let parent_inner_region = match rcx.tcx().region_maps.opt_encl_scope(inner_scope) { - None => ty::ReFunction, + None => rcx.tcx().sess.span_bug( + span, format!("no enclosing scope found for inner_scope: {}", + inner_scope).as_slice()), // FIXME (onkfelix): if closures need not be handled specially, // then perhaps I can/should do away with ReFunction entirely. Some(parent_inner_scope @ region::CodeExtent::Closure(_)) => { From c0fe43f856656e62c1ecb77ab9db8486f16e9a94 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:42:33 +0100 Subject: [PATCH 39/65] insert DestructionScope and block Remainder into enclosing CodeExtents hierarchy. --- src/librustc/middle/region.rs | 267 +++++++++++++++++++++++++++------- 1 file changed, 213 insertions(+), 54 deletions(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4596cdd6c8ba5..cd780e5cc131e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -32,6 +32,7 @@ use syntax::codemap::Span; use syntax::{ast, visit}; use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local}; use syntax::ast_util::{stmt_id}; +use syntax::ptr::P; use syntax::visit::{Visitor, FnKind}; /// CodeExtent represents a statically-describable extent that can be @@ -163,19 +164,75 @@ pub struct RegionMaps { #[deriving(PartialEq, Eq, Show)] enum InnermostDeclaringBlock { None, - Some(ast::NodeId), + Block(ast::NodeId), + Statement(DeclaringStatementContext), + Match(ast::NodeId), +} + +impl InnermostDeclaringBlock { + fn to_code_extent(&self) -> Option { + let extent = match *self { + InnermostDeclaringBlock::None => { + return Option::None; + } + InnermostDeclaringBlock::Block(id) | + InnermostDeclaringBlock::Match(id) => CodeExtent::from_node_id(id), + InnermostDeclaringBlock::Statement(s) => s.to_code_extent(), + }; + Option::Some(extent) + } +} + +/// Contextual information for declarations introduced by a statement +/// (i.e. `let`). It carries node-id's for statement and enclosing +/// block both, as well as the statement's index within the block. +#[deriving(PartialEq, Eq, Show)] +struct DeclaringStatementContext { + stmt_id: ast::NodeId, + block_id: ast::NodeId, + stmt_index: uint, +} + +impl DeclaringStatementContext { + fn to_code_extent(&self) -> CodeExtent { + CodeExtent::Remainder(BlockRemainder { + block: self.block_id, + first_statement_index: self.stmt_index, + }) + } } #[deriving(PartialEq, Eq, Show)] enum InnermostEnclosingExpr { None, Some(ast::NodeId), + DestructionScope(ast::NodeId), + Statement(DeclaringStatementContext), /// A closure is treated as a separate case, because a closure and /// its enclosed block do not have the same relationship with /// respect to control-flow that most other expressions do. Closure(ast::NodeId), } +impl InnermostEnclosingExpr { + fn to_code_extent(&self) -> Option { + let extent = match *self { + InnermostEnclosingExpr::None => { + return Option::None; + } + InnermostEnclosingExpr::Statement(s) => + s.to_code_extent(), + InnermostEnclosingExpr::Some(parent_id) => + CodeExtent::from_node_id(parent_id), + InnermostEnclosingExpr::Closure(closure_id) => + CodeExtent::Closure(closure_id), + InnermostEnclosingExpr::DestructionScope(parent_id) => + CodeExtent::DestructionScope(parent_id), + }; + Some(extent) + } +} + #[deriving(PartialEq, Eq, Show)] pub struct Context { var_parent: InnermostDeclaringBlock, @@ -343,7 +400,8 @@ impl RegionMaps { return true; } - pub fn sub_free_region(&self, sub: FreeRegion, sup: FreeRegion) -> bool { + pub fn sub_free_region(&self, sub: + FreeRegion, sup: FreeRegion) -> bool { /*! * Determines whether two free regions have a subregion relationship * by walking the graph encoded in `free_region_map`. Note that @@ -467,21 +525,19 @@ impl RegionMaps { fn record_superlifetime(visitor: &mut RegionResolutionVisitor, child_scope: CodeExtent, _sp: Span) { - // FIXME (pnkfelix): currently this is redundantly adding entries - // for both a specific variant (Closure in this case) as well as - // the catch-all `CodeExtent::Misc`. This bloats the hashtable and - // is ugly to boot; we should instead consistently select the - // specific variant in all necessary contexts. - match visitor.cx.parent { - InnermostEnclosingExpr::Some(parent_id) => { - let parent_scope = CodeExtent::from_node_id(parent_id); + // FIXME (pnkfelix): this may need to redundantly add entries for + // both a specific variant (Closure in this case) as well as the + // catch-all `CodeExtent::Misc`. (At least, it needed that on one + // path of development that I followed). But doing this would + // bloat the hashtable and is ugly to boot; we should instead + // consistently select the specific variant in all necessary + // contexts. + + match visitor.cx.parent.to_code_extent() { + Option::None => {} + Option::Some(parent_scope) => { visitor.region_maps.record_encl_scope(child_scope, parent_scope); } - InnermostEnclosingExpr::Closure(closure_id) => { - let parent_scope = CodeExtent::Closure(closure_id); - visitor.region_maps.record_encl_scope(child_scope, parent_scope); - } - InnermostEnclosingExpr::None => {} } } @@ -490,12 +546,12 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, var_id: ast::NodeId, _sp: Span) { debug!("record_var_lifetime var_id: {}", var_id); - match visitor.cx.var_parent { - InnermostDeclaringBlock::Some(parent_id) => { - let parent_scope = CodeExtent::from_node_id(parent_id); + + match visitor.cx.var_parent.to_code_extent() { + Some(parent_scope) => { visitor.region_maps.record_var_scope(var_id, parent_scope); } - InnermostDeclaringBlock::None => { + None => { // this can happen in extern fn declarations like // // extern fn isalnum(c: c_int) -> c_int @@ -506,24 +562,106 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) { debug!("resolve_block(blk.id={})", blk.id); - // Record the parent of this block. - record_superlifetime(visitor, CodeExtent::Misc(blk.id), blk.span); + let prev_cx = visitor.cx; + + // FIXME (pnkfelix): Hack: introduce a separate destruction scope + // around each block, to ensure that a (tightly enclosing) + // immediate parent always exists to represent the extent where + // user code of the block is done but destructors of the block are + // still running. + // + // FIXME (pnkfelix): I now think this is unnecessary since I am + // handling DestructionScopes by making a 1:1 mapping between + // entries in terminating_scopes and DestructionScope instances. + if false { + record_superlifetime(visitor, CodeExtent::DestructionScope(blk.id), blk.span); + + visitor.cx = Context { + parent: InnermostEnclosingExpr::DestructionScope(blk.id), + ..visitor.cx + }; + } + + // If block was previously marked as a terminating scope during + // the recursive visit of its parent node in the AST, then we need + // to account for the destruction scope representing the extent of + // the destructors that run immediately after the the block itself + // completes. + let blk_scope = CodeExtent::Misc(blk.id); + if visitor.region_maps.terminating_scopes.borrow().contains(&blk_scope) { + let dtor_scope = CodeExtent::DestructionScope(blk.id); + record_superlifetime(visitor, dtor_scope, blk.span); + visitor.region_maps.record_encl_scope(blk_scope, dtor_scope); + } else { + record_superlifetime(visitor, blk_scope, blk.span); + } // We treat the tail expression in the block (if any) somewhat // differently from the statements. The issue has to do with - // temporary lifetimes. If the user writes: + // temporary lifetimes. Consider the following: + // + // quux({ + // let inner = ... (&bar()) ...; + // ... (&foo()) ... + // }, other_argument()); + // + // Here, the tail expression evaluates to a value that will be + // assigned to `outer`. // - // { - // ... (&foo()) ... - // } + // Each of the statements within the block is a terminating + // scope, and thus a temporaries like the result of calling + // `bar()` in the initalizer expression for `let inner = ...;` + // will be cleaned up immediately after `let inner = ...;` + // executes. // + // On the other hand, temporaries associated with evaluating the + // tail expression for the block are assigned lifetimes so that + // they will be cleaned up as part of the terminating scope + // *surrounding* the block expression. Here, the terminating + // scope for the block expression is the `quux(..)` call; so + // those temporaries will only be cleaned up *after* both + // `other_argument()` has run and also the call to `quux(..)` + // itself has returned. - let prev_cx = visitor.cx; visitor.cx = Context { - var_parent: InnermostDeclaringBlock::Some(blk.id), + var_parent: InnermostDeclaringBlock::Block(blk.id), parent: InnermostEnclosingExpr::Some(blk.id) }; - visit::walk_block(visitor, blk); + + { + // This block should be kept approximately in sync with + // `visit::walk_block`. (We manually walk the block, rather + // than call `walk_block`, in order to maintain precise + // `InnermostDeclaringBlock` information.) + + for view_item in blk.view_items.iter() { + visitor.visit_view_item(view_item) + } + for (i, statement) in blk.stmts.iter().enumerate() { + if let ast::StmtDecl(_, stmt_id) = statement.node { + // Each StmtDecl introduces a subscope for bindings + // introduced by the declaration; this subscope covers + // a suffix of the block . Each subscope in a block + // has the previous subscope in the block as a parent, + // except for the first such subscope, which has the + // block itself as a parent. + let declaring = DeclaringStatementContext { + stmt_id: stmt_id, + block_id: blk.id, + stmt_index: i, + }; + record_superlifetime( + visitor, declaring.to_code_extent(), statement.span); + visitor.cx = Context { + var_parent: InnermostDeclaringBlock::Statement(declaring), + parent: InnermostEnclosingExpr::Statement(declaring), + }; + } + visitor.visit_stmt(&**statement) + } + visit::walk_expr_opt(visitor, &blk.expr) + } + visitor.cx = prev_cx; } @@ -564,8 +702,16 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { debug!("resolve_stmt(stmt.id={})", stmt_id); let stmt_scope = CodeExtent::from_node_id(stmt_id); + + // Every statement will clean up the temporaries created during + // execution of that statement. Therefore each statement has an + // associated destruction scope that represents the extent of the + // statement plus its destructors, and thus the extent for which + // regions referenced by the destructors need to survive. visitor.region_maps.mark_as_terminating_scope(stmt_scope); - record_superlifetime(visitor, CodeExtent::Misc(stmt_id), stmt.span); + let dtor_scope = CodeExtent::DestructionScope(stmt_id); + visitor.region_maps.record_encl_scope(stmt_scope, dtor_scope); + record_superlifetime(visitor, dtor_scope, stmt.span); let prev_parent = visitor.cx.parent; visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id); @@ -576,14 +722,30 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) { fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { debug!("resolve_expr(expr.id={})", expr.id); - record_superlifetime(visitor, CodeExtent::Misc(expr.id), expr.span); + // If expr was previously marked as a terminating scope during the + // recursive visit of its parent node in the AST, then we need to + // account for the destruction scope representing the extent of + // the destructors that run immediately after the the expression + // itself completes. + let expr_scope = CodeExtent::Misc(expr.id); + if visitor.region_maps.terminating_scopes.borrow().contains(&expr_scope) { + let dtor_scope = CodeExtent::DestructionScope(expr.id); + record_superlifetime(visitor, dtor_scope, expr.span); + visitor.region_maps.record_encl_scope(expr_scope, dtor_scope); + } else { + record_superlifetime(visitor, expr_scope, expr.span); + } let prev_cx = visitor.cx; visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id); { let region_maps = &mut visitor.region_maps; - let terminating = |id| { - let scope = CodeExtent::from_node_id(id); + let terminating = |e: &P| { + let scope = CodeExtent::from_node_id(e.id); + region_maps.mark_as_terminating_scope(scope) + }; + let terminating_block = |b: &P| { + let scope = CodeExtent::from_node_id(b.id); region_maps.mark_as_terminating_scope(scope) }; match expr.node { @@ -595,38 +757,38 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) { ast::ExprBinary(ast::BiOr, _, ref r) => { // For shortcircuiting operators, mark the RHS as a terminating // scope since it only executes conditionally. - terminating(r.id); + terminating(r); } ast::ExprIf(_, ref then, Some(ref otherwise)) => { - terminating(then.id); - terminating(otherwise.id); + terminating_block(then); + terminating(otherwise); } ast::ExprIf(ref expr, ref then, None) => { - terminating(expr.id); - terminating(then.id); + terminating(expr); + terminating_block(then); } ast::ExprLoop(ref body, _) => { - terminating(body.id); + terminating_block(body); } ast::ExprWhile(ref expr, ref body, _) => { - terminating(expr.id); - terminating(body.id); + terminating(expr); + terminating_block(body); } ast::ExprForLoop(ref _pat, ref _head, ref body, _) => { - terminating(body.id); + terminating_block(body); // The variable parent of everything inside (most importantly, the // pattern) is the body. - visitor.cx.var_parent = InnermostDeclaringBlock::Some(body.id); + visitor.cx.var_parent = InnermostDeclaringBlock::Block(body.id); } ast::ExprMatch(..) => { - visitor.cx.var_parent = InnermostDeclaringBlock::Some(expr.id); + visitor.cx.var_parent = InnermostDeclaringBlock::Match(expr.id); } ast::ExprAssignOp(..) | ast::ExprIndex(..) | @@ -663,19 +825,13 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &ast::Local) { debug!("resolve_local(local.id={},local.init={})", local.id,local.init.is_some()); - let blk_id = match visitor.cx.var_parent { - InnermostDeclaringBlock::Some(id) => id, - InnermostDeclaringBlock::None => { - visitor.sess.span_bug( - local.span, - "local without enclosing block"); - } - }; - // For convenience in trans, associate with the local-id the var // scope that will be used for any bindings declared in this // pattern. - let blk_scope = CodeExtent::from_node_id(blk_id); + let blk_scope = visitor.cx.var_parent.to_code_extent() + .unwrap_or_else(|| visitor.sess.span_bug( + local.span, "local without enclosing block")); + visitor.region_maps.record_var_scope(local.id, blk_scope); // As an exception to the normal rules governing temporary @@ -951,11 +1107,14 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor, let body_scope = CodeExtent::from_node_id(body.id); visitor.region_maps.mark_as_terminating_scope(body_scope); + let dtor_scope = CodeExtent::DestructionScope(body.id); + visitor.region_maps.record_encl_scope(body_scope, dtor_scope); + record_superlifetime(visitor, dtor_scope, body.span); // The arguments and `self` are parented to the body of the fn. visitor.cx = Context { parent: InnermostEnclosingExpr::Some(body.id), - var_parent: InnermostDeclaringBlock::Some(body.id) + var_parent: InnermostDeclaringBlock::Block(body.id) }; visit::walk_fn_decl(visitor, decl); From c87a0338b2516a6007d81e68c67e6676272d624c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:43:29 +0100 Subject: [PATCH 40/65] FIXME loosened an assertion in `rustc_trans::trans::cleanup` to account for `DestructionScope`. FIXME: Perhaps this should just be switched entirely over to `DestructionScope`, rather than allowing for either `Misc` or `DestructionScope`. --- src/librustc_trans/trans/cleanup.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index b0235be7497ea..21589874f5c44 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -135,12 +135,17 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { // this new AST scope had better be its immediate child. let top_scope = self.top_ast_scope(); if top_scope.is_some() { - assert_eq!(self.ccx - .tcx() - .region_maps - .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id)) - .map(|s|s.node_id()), - top_scope); + assert!((self.ccx + .tcx() + .region_maps + .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id)) + .map(|s|s.node_id()) == top_scope) + || + (self.ccx + .tcx() + .region_maps + .opt_encl_scope(region::CodeExtent::DestructionScope(debug_loc.id)) + .map(|s|s.node_id()) == top_scope)); } self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id), From f5324d24fa92cbea5c5de5c33af59bfc8428db46 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 13 Dec 2014 09:44:18 +0100 Subject: [PATCH 41/65] rustc::middle::typeck::check::wf debug instrumentation and a FIXME comment. The FIXME comment may be immediately relevant to a bug I am having right now when attempting to compile libsyntax. --- src/librustc/middle/typeck/check/wf.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 515c3dd7520b4..4a32c2babbdd4 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -171,6 +171,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { item: &ast::Item) { self.with_fcx(item, |this, fcx| { + // FIXME (pnkfelix): what is the "extent" of an item impl? + // This seems fundamentally different from the dynamic + // extent represented by a block or a function body. + // + // For now, just leaving as the default you get via + // `fn CodeExtent::from_node_id`. let item_scope = region::CodeExtent::from_node_id(item.id); let mut bounds_checker = BoundsChecker::new(fcx, @@ -262,8 +268,11 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> { scope: region::CodeExtent, cache: Option<&'cx mut HashSet>>) -> BoundsChecker<'cx,'tcx> { - BoundsChecker { fcx: fcx, span: span, scope: scope, - cache: cache, binding_count: 0 } + let ret = BoundsChecker { fcx: fcx, span: span, scope: scope, + cache: cache, binding_count: 0 }; + debug!("BoundsChecker::new returns b with: b.scope: {} b.binding_count: {}", + ret.scope, ret.binding_count); + ret } pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) { From 5230f860040b04e64be7f36024a532234a8a4d81 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 15 Dec 2014 17:36:39 +0100 Subject: [PATCH 42/65] middle::resolve_lifetime: Map BlockScope to DestructionScope in `fn resolve_free_lifetime`. --- src/librustc/middle/resolve_lifetime.rs | 30 ++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index b68bc9fea5866..cc8bdff8dc7b4 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -361,17 +361,40 @@ impl<'a> LifetimeContext<'a> { scope_data: region::CodeExtent, lifetime_ref: &ast::Lifetime, scope: Scope) { + debug!("resolve_free_lifetime_ref \ + scope_data: {} lifetime_ref: {} scope: {}", + scope_data, lifetime_ref, scope); + // Walk up the scope chain, tracking the outermost free scope, // until we encounter a scope that contains the named lifetime // or we run out of scopes. let mut scope_data = scope_data; let mut scope = scope; let mut search_result = None; + let mut loop_count = 0u; loop { + debug!("resolve_free_lifetime_ref loop: {} \ + scope_data: {} scope: {} search_result: {}", + loop_count, scope_data, scope, search_result); match *scope { BlockScope(blk_scope_data, s) => { - scope_data = blk_scope_data; - scope = s; + // FIXME (pnkfelix): I still need to work through + // the theoretical justification for this + // transition from the block itself to its + // enclosing destruction scope. (In particular, + // perhaps athis *actually* belongs as part of the + // `RootScope` case, or maybe following the loop + // (either of which I think would resolve my + // problem), but not here, where it has a broad + // effect. + if let CodeExtent::Misc(node_id) = blk_scope_data { + let d = CodeExtent::DestructionScope(node_id); + scope_data = d; + scope = s; + } else { + self.sess.bug( + "found unexpected CodeExtent associated with blk_scope") + } } RootScope => { @@ -393,8 +416,9 @@ impl<'a> LifetimeContext<'a> { Some((_depth, decl_id)) => { let def = DefFreeRegion(scope_data, decl_id); debug!("resolve_free_lifetime_ref: \ + from parent scope {} \ insert_lifetime(lifetime_ref: {} def: {})", - lifetime_ref, def); + lifetime_ref, *scope, def); self.insert_lifetime(lifetime_ref, def); } From 5eae77852a88fde3c6c23cf5a9358ae6486c8768 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 18 Dec 2014 15:16:07 +0100 Subject: [PATCH 43/65] FIXME Fallout from changes to rules for lifetimes and Drop. It would be good revisit all of these changes after I get the whole PR into a good state, to see if some/all of them can be returned to their prior state. Also, a real FIXME: the current spans being generated for the borrow-check errors related to this are terrible; they tend to point one at a sub-expression of the actual expression that needs to be factored out (or, in some cases, an earlier expression entirely? Need to double check that). --- src/librustc/middle/resolve.rs | 23 ++++++++++++------- .../middle/typeck/check/method/probe.rs | 8 ++++--- src/librustc/middle/typeck/coherence/mod.rs | 3 ++- .../middle/typeck/infer/error_reporting.rs | 4 ++-- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 68a31c83ea484..ce929bfbf1fc8 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1403,7 +1403,8 @@ impl<'a> Resolver<'a> { // a trait and the name of an impl of that trait. let mod_name = path.segments.last().unwrap().identifier.name; - let parent_opt = parent.module().children.borrow() + let parent_mod = parent.module(); + let parent_opt = parent_mod.children.borrow() .get(&mod_name).cloned(); let new_parent = match parent_opt { // It already exists @@ -1767,11 +1768,12 @@ impl<'a> Resolver<'a> { true)); debug!("(build reduced graph for item) found extern `{}`", self.module_to_string(&*external_module)); + let parent_mod = parent.module(); self.check_for_conflicts_between_external_crates( - &*parent.module(), + &*parent_mod, name.name, view_item.span); - parent.module().external_module_children.borrow_mut() + parent_mod.external_module_children.borrow_mut() .insert(name.name, external_module.clone()); self.build_reduced_graph_for_external_crate(external_module); } @@ -2301,7 +2303,8 @@ impl<'a> Resolver<'a> { } } - for (_, child_module) in module_.anonymous_children.borrow().iter() { + let children = module_.anonymous_children.borrow(); + for (_, child_module) in children.iter() { self.resolve_imports_for_module_subtree(child_module.clone()); } } @@ -3458,7 +3461,8 @@ impl<'a> Resolver<'a> { // Search for external modules. if namespace == TypeNS { - match module_.external_module_children.borrow().get(&name).cloned() { + let children = module_.external_module_children.borrow().get(&name).cloned(); + match children { None => {} Some(module) => { let name_bindings = @@ -3743,7 +3747,8 @@ impl<'a> Resolver<'a> { // Finally, search through external children. if namespace == TypeNS { - match module_.external_module_children.borrow().get(&name).cloned() { + let children = module_.external_module_children.borrow().get(&name).cloned(); + match children { None => {} Some(module) => { let name_bindings = @@ -3795,7 +3800,8 @@ impl<'a> Resolver<'a> { } } - for (_, module_) in module_.anonymous_children.borrow().iter() { + let children = module_.anonymous_children.borrow(); + for (_, module_) in children.iter() { self.report_unresolved_imports(module_.clone()); } } @@ -3855,7 +3861,8 @@ impl<'a> Resolver<'a> { } } - for (_, child_module) in module_.anonymous_children.borrow().iter() { + let children = module_.anonymous_children.borrow(); + for (_, child_module) in children.iter() { self.record_exports_for_module_subtree(child_module.clone()); } } diff --git a/src/librustc/middle/typeck/check/method/probe.rs b/src/librustc/middle/typeck/check/method/probe.rs index a98b4cf011d97..8bfa7664aef4c 100644 --- a/src/librustc/middle/typeck/check/method/probe.rs +++ b/src/librustc/middle/typeck/check/method/probe.rs @@ -486,12 +486,14 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { trait_def_id); let trait_impls = self.tcx().trait_impls.borrow(); - let impl_def_ids = match trait_impls.get(&trait_def_id) { + let impl_for_def = trait_impls.get(&trait_def_id); + let impl_def_ids = match impl_for_def { None => { return; } Some(impls) => impls, }; - for &impl_def_id in impl_def_ids.borrow().iter() { + let impl_def_ids = impl_def_ids.borrow(); + for &impl_def_id in impl_def_ids.iter() { debug!("assemble_extension_candidates_for_trait_impl: trait_def_id={} impl_def_id={}", trait_def_id.repr(self.tcx()), impl_def_id.repr(self.tcx())); @@ -901,8 +903,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { // if there are any. assert_eq!(substs.types.len(subst::FnSpace), 0); assert_eq!(substs.regions().len(subst::FnSpace), 0); - let mut substs = substs; let placeholder; + let mut substs = substs; if !method.generics.types.is_empty_in(subst::FnSpace) || !method.generics.regions.is_empty_in(subst::FnSpace) diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index 1f32110a09338..9eb42e4aa32a6 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -432,7 +432,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { Some(found_impls) => found_impls }; - for &impl_did in trait_impls.borrow().iter() { + let trait_impls = trait_impls.borrow(); + for &impl_did in trait_impls.iter() { let items = &(*impl_items)[impl_did]; if items.len() < 1 { // We'll error out later. For now, just don't ICE. diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 345fe2533f5be..dd182350f591a 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -867,6 +867,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { let scope_id = same_regions[0].scope_id; let parent = self.tcx.map.get_parent(scope_id); let parent_node = self.tcx.map.find(parent); + let taken = lifetimes_in_scope(self.tcx, scope_id); + let life_giver = LifeGiver::with_taken(taken.as_slice()); let node_inner = match parent_node { Some(ref node) => match *node { ast_map::NodeItem(ref item) => { @@ -909,8 +911,6 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { }; let (fn_decl, generics, fn_style, ident, expl_self, span) = node_inner.expect("expect item fn"); - let taken = lifetimes_in_scope(self.tcx, scope_id); - let life_giver = LifeGiver::with_taken(taken.as_slice()); let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self, generics, same_regions, &life_giver); let (fn_decl, expl_self, generics) = rebuilder.rebuild(); From 700cf12645e3bd1d77ffcf5278ad259f15e59e28 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 18 Dec 2014 15:18:24 +0100 Subject: [PATCH 44/65] Fix to earlier instrumentation: `loop_count` was not getting incremented. --- src/librustc/middle/resolve_lifetime.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index cc8bdff8dc7b4..84807d2679a68 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -373,6 +373,7 @@ impl<'a> LifetimeContext<'a> { let mut search_result = None; let mut loop_count = 0u; loop { + loop_count += 1; debug!("resolve_free_lifetime_ref loop: {} \ scope_data: {} scope: {} search_result: {}", loop_count, scope_data, scope, search_result); From ae0dadf0b2f6dfd7a41e3de6c950ccd3f7227a25 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 18 Dec 2014 15:21:49 +0100 Subject: [PATCH 45/65] rustc stage2 bootstrap cleanup: Remove unused imports and bindings. As a drive-by, fix the prefix used for the emitted message when `explain_region_and_span` encounters a `DestructionScope`. --- src/librustc/middle/typeck/check/mod.rs | 2 +- src/librustc/middle/typeck/check/regionck.rs | 1 - src/librustc/middle/typeck/check/wf.rs | 2 -- src/librustc/util/ppaux.rs | 6 +++--- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index baadceb98089e..d611ff8f2ea1d 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -87,7 +87,7 @@ use middle::{const_eval, def, traits}; use middle::lang_items::IteratorItem; use middle::mem_categorization::{mod, McResult}; use middle::pat_util::{mod, pat_id_map}; -use middle::region::{mod, CodeExtent}; +use middle::region::{CodeExtent}; use middle::subst::{mod, Subst, Substs, VecPerParamSpace, ParamSpace}; use middle::ty::{FnSig, VariantInfo, Polytype}; use middle::ty::{Disr, ParamTy, ParameterEnvironment}; diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 650e61489a604..d5eed8064faf5 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -121,7 +121,6 @@ and report an error, and it just seems like more mess in the end.) use middle::def; use middle::mem_categorization as mc; use middle::region::CodeExtent; -use middle::subst; use middle::traits; use middle::ty::{ReScope}; use middle::ty::{mod, Ty}; diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 4a32c2babbdd4..4ab1084d063ab 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -9,7 +9,6 @@ // except according to those terms. use middle::region; -use middle::subst; use middle::subst::{Subst}; use middle::traits; use middle::ty::{mod, Ty}; @@ -23,7 +22,6 @@ use util::ppaux::Repr; use std::collections::HashSet; use syntax::ast; use syntax::ast_util::{local_def}; -use syntax::attr; use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index c7ba82bb3918a..31e45741f5673 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -89,8 +89,8 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ReScope(scope @ CodeExtent::Closure(_)) | ReScope(scope @ CodeExtent::DestructionScope(_)) => { let node_id = scope.node_id(); - let prefix = if let CodeExtent::DestructionScope(dtor_id) = scope { - "destruction scope surrounding" + let prefix = if let CodeExtent::DestructionScope(_) = scope { + "destruction scope surrounding " } else { "" }; @@ -925,7 +925,7 @@ impl<'tcx> Repr<'tcx> for ty::FreeRegion { } impl<'tcx> Repr<'tcx> for region::CodeExtent { - fn repr(&self, tcx: &ctxt) -> String { + fn repr(&self, _: &ctxt) -> String { match *self { region::CodeExtent::Misc(node_id) => format!("Misc({})", node_id), From 5dd63c1e17a1c3b16b47920c87ced1e48cb3755a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 19 Dec 2014 13:58:57 +0100 Subject: [PATCH 46/65] Checkpoint: Refactored librustc_trans, avoid stack-crossing ref cycle. Namely, `BlockS` used to carry an `fcx: &'blk FunctionContext`, while the `FunctionContext` carries a reference to the arena that holds the blocks, and thus there was a chicken/egg problem where we are attempting to assign the lifetime `'blk` to both the `FunctionContext` and to the arena's blocks, which does not work under the new lifetime rules for `Drop`, since there has to be some order in which the two are torn down. To work around this, I removed the `fcx` from the `BlockS`, and instead turn the `Block` type (which was formerly `&'blk BlockS`) into a tuple carrying both the pointer to the `BlockS` as well as the `fcx`. --- src/librustc_trans/trans/_match.rs | 148 ++++++++--------- src/librustc_trans/trans/adt.rs | 34 ++-- src/librustc_trans/trans/asm.rs | 4 +- src/librustc_trans/trans/base.rs | 154 +++++++++--------- src/librustc_trans/trans/build.rs | 206 ++++++++++++------------ src/librustc_trans/trans/callee.rs | 72 ++++----- src/librustc_trans/trans/cleanup.rs | 116 ++++++------- src/librustc_trans/trans/closure.rs | 48 +++--- src/librustc_trans/trans/common.rs | 122 +++++++------- src/librustc_trans/trans/controlflow.rs | 144 ++++++++--------- src/librustc_trans/trans/datum.rs | 132 +++++++-------- src/librustc_trans/trans/debuginfo.rs | 8 +- src/librustc_trans/trans/expr.rs | 190 +++++++++++----------- src/librustc_trans/trans/foreign.rs | 4 +- src/librustc_trans/trans/glue.rs | 40 ++--- src/librustc_trans/trans/intrinsic.rs | 10 +- src/librustc_trans/trans/meth.rs | 26 +-- src/librustc_trans/trans/tvec.rs | 60 +++---- src/librustc_trans/trans/value.rs | 2 +- 19 files changed, 766 insertions(+), 754 deletions(-) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index d23e53d2e69bf..1c8276a994594 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -274,7 +274,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { } } - fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> { + fn trans<'fcx, 'blk>(&self, mut bcx: Block<'fcx, 'blk, 'tcx>) -> OptResult<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::trans_opt"); let ccx = bcx.ccx(); match *self { @@ -312,10 +312,10 @@ pub enum BranchKind { CompareSliceLength } -pub enum OptResult<'blk, 'tcx: 'blk> { - SingleResult(Result<'blk, 'tcx>), - RangeResult(Result<'blk, 'tcx>, Result<'blk, 'tcx>), - LowerBound(Result<'blk, 'tcx>) +pub enum OptResult<'fcx, 'blk: 'fcx, 'tcx: 'blk> { + SingleResult(Result<'fcx, 'blk, 'tcx>), + RangeResult(Result<'fcx, 'blk, 'tcx>, Result<'fcx, 'blk, 'tcx>), + LowerBound(Result<'fcx, 'blk, 'tcx>) } #[deriving(Clone)] @@ -344,8 +344,8 @@ pub struct BindingInfo<'tcx> { type BindingsMap<'tcx> = FnvHashMap>; -struct ArmData<'p, 'blk, 'tcx: 'blk> { - bodycx: Block<'blk, 'tcx>, +struct ArmData<'p, 'fcx, 'blk: 'fcx, 'tcx: 'blk> { + bodycx: Block<'fcx, 'blk, 'tcx>, arm: &'p ast::Arm, bindings_map: BindingsMap<'tcx> } @@ -356,13 +356,13 @@ struct ArmData<'p, 'blk, 'tcx: 'blk> { * As we proceed `bound_ptrs` are filled with pointers to values to be bound, * these pointers are stored in llmatch variables just before executing `data` arm. */ -struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> { +struct Match<'a, 'p: 'a, 'fcx: 'a, 'blk: 'fcx, 'tcx: 'blk> { pats: Vec<&'p ast::Pat>, - data: &'a ArmData<'p, 'blk, 'tcx>, + data: &'a ArmData<'p, 'fcx, 'blk, 'tcx>, bound_ptrs: Vec<(Ident, ValueRef)>, } -impl<'a, 'p, 'blk, 'tcx> Repr<'tcx> for Match<'a, 'p, 'blk, 'tcx> { +impl<'a, 'p, 'fcx, 'blk, 'tcx> Repr<'tcx> for Match<'a, 'p, 'fcx, 'blk, 'tcx> { fn repr(&self, tcx: &ty::ctxt) -> String { if tcx.sess.verbose() { // for many programs, this just take too long to serialize @@ -383,11 +383,11 @@ fn has_nested_bindings(m: &[Match], col: uint) -> bool { return false; } -fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], +fn expand_nested_bindings<'a, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], col: uint, val: ValueRef) - -> Vec> { + -> Vec> { debug!("expand_nested_bindings(bcx={}, m={}, col={}, val={})", bcx.to_str(), m.repr(bcx.tcx()), @@ -420,13 +420,13 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, type EnterPatterns<'a, 'p> = |&[&'p ast::Pat]|: 'a -> Option>; -fn enter_match<'a, 'b, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn enter_match<'a, 'b, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, dm: &DefMap, - m: &[Match<'a, 'p, 'blk, 'tcx>], + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], col: uint, val: ValueRef, e: EnterPatterns<'b, 'p>) - -> Vec> { + -> Vec> { debug!("enter_match(bcx={}, m={}, col={}, val={})", bcx.to_str(), m.repr(bcx.tcx()), @@ -466,12 +466,12 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }).collect() } -fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn enter_default<'a, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, dm: &DefMap, - m: &[Match<'a, 'p, 'blk, 'tcx>], + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], col: uint, val: ValueRef) - -> Vec> { + -> Vec> { debug!("enter_default(bcx={}, m={}, col={}, val={})", bcx.to_str(), m.repr(bcx.tcx()), @@ -519,16 +519,16 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// takes the complete row of patterns rather than just the first one. /// Also, most of the enter_() family functions have been unified with /// the check_match specialization step. -fn enter_opt<'a, 'p, 'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, +fn enter_opt<'a, 'p, 'fcx, 'blk, 'tcx>( + bcx: Block<'fcx, 'blk, 'tcx>, _: ast::NodeId, dm: &DefMap, - m: &[Match<'a, 'p, 'blk, 'tcx>], + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], opt: &Opt, col: uint, variant_size: uint, val: ValueRef) - -> Vec> { + -> Vec> { debug!("enter_opt(bcx={}, m={}, opt={}, col={}, val={})", bcx.to_str(), m.repr(bcx.tcx()), @@ -562,8 +562,8 @@ fn enter_opt<'a, 'p, 'blk, 'tcx>( // Returns the options in one column of matches. An option is something that // needs to be conditionally matched at runtime; for example, the discriminant // on a set of enum variants or a literal. -fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], col: uint) +fn get_branches<'a, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], col: uint) -> Vec> { let tcx = bcx.tcx(); @@ -602,16 +602,16 @@ fn get_branches<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, found } -struct ExtractedBlock<'blk, 'tcx: 'blk> { +struct ExtractedBlock<'fcx, 'blk: 'fcx, 'tcx: 'blk> { vals: Vec, - bcx: Block<'blk, 'tcx>, + bcx: Block<'fcx, 'blk, 'tcx>, } -fn extract_variant_args<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn extract_variant_args<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, repr: &adt::Repr<'tcx>, disr_val: ty::Disr, val: ValueRef) - -> ExtractedBlock<'blk, 'tcx> { + -> ExtractedBlock<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::extract_variant_args"); let args = Vec::from_fn(adt::num_args(repr, disr_val), |i| { adt::trans_field_ptr(bcx, repr, val, disr_val, i) @@ -654,12 +654,12 @@ fn bind_subslice_pat(bcx: Block, scratch.val } -fn extract_vec_elems<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn extract_vec_elems<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, left_ty: Ty, before: uint, after: uint, val: ValueRef) - -> ExtractedBlock<'blk, 'tcx> { + -> ExtractedBlock<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::extract_vec_elems"); let vec_datum = match_datum(val, left_ty); let (base, len) = vec_datum.get_vec_base_and_len(bcx); @@ -787,16 +787,16 @@ fn pick_column_to_specialize(def_map: &DefMap, m: &[Match]) -> Option { } // Compiles a comparison between two things. -fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, +fn compare_values<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, rhs_t: Ty<'tcx>) - -> Result<'blk, 'tcx> { - fn compare_str<'blk, 'tcx>(cx: Block<'blk, 'tcx>, + -> Result<'fcx, 'blk, 'tcx> { + fn compare_str<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, rhs_t: Ty<'tcx>) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let did = langcall(cx, None, format!("comparison of `{}`", @@ -831,10 +831,10 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } } -fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +fn insert_lllocals<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, bindings_map: &BindingsMap<'tcx>, cs: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * For each binding in `data.bindings_map`, adds an appropriate entry into * the `fcx.lllocals` map @@ -887,14 +887,14 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, bcx } -fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn compile_guard<'a, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, guard_expr: &ast::Expr, - data: &ArmData<'p, 'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], + data: &ArmData<'p, 'fcx, 'blk, 'tcx>, + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], vals: &[ValueRef], chk: &FailureHandler, has_genuine_default: bool) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { debug!("compile_guard(bcx={}, guard_expr={}, m={}, vals={})", bcx.to_str(), bcx.expr_to_string(guard_expr), @@ -935,8 +935,8 @@ fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }) } -fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], +fn compile_submatch<'a, 'p, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], vals: &[ValueRef], chk: &FailureHandler, has_genuine_default: bool) { @@ -991,13 +991,13 @@ fn compile_submatch<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } _ => () } - Br(bcx, data.bodycx.llbb); + Br(bcx, data.bodycx.data.llbb); } } } -fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - m: &[Match<'a, 'p, 'blk, 'tcx>], +fn compile_submatch_continue<'a, 'p, 'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, + m: &[Match<'a, 'p, 'fcx, 'blk, 'tcx>], vals: &[ValueRef], chk: &FailureHandler, col: uint, @@ -1098,7 +1098,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => bcx.fcx.new_temp_block("match_else") }; let sw = if kind == Switch { - build::Switch(bcx, test_val, else_cx.llbb, opts.len()) + build::Switch(bcx, test_val, else_cx.data.llbb, opts.len()) } else { C_int(ccx, 0i) // Placeholder for when not using a switch }; @@ -1118,11 +1118,11 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, if !exhaustive || i + 1 < len { opt_cx = bcx.fcx.new_temp_block("match_case"); match kind { - Single => Br(bcx, opt_cx.llbb), + Single => Br(bcx, opt_cx.data.llbb), Switch => { match opt.trans(bcx) { SingleResult(r) => { - AddCase(sw, r.val, opt_cx.llbb); + AddCase(sw, r.val, opt_cx.data.llbb); bcx = r.bcx; } _ => { @@ -1169,14 +1169,14 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let guarded = m[i].data.arm.guard.is_some(); let multi_pats = m[i].pats.len() > 1; if i + 1 < len && (guarded || multi_pats || kind == CompareSliceLength) { - branch_chk = Some(JumpToBasicBlock(bcx.llbb)); + branch_chk = Some(JumpToBasicBlock(bcx.data.llbb)); } - CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb); + CondBr(after_cx, matches, opt_cx.data.llbb, bcx.data.llbb); } _ => () } } else if kind == Compare || kind == CompareSliceLength { - Br(bcx, else_cx.llbb); + Br(bcx, else_cx.data.llbb); } let mut size = 0u; @@ -1216,7 +1216,7 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, // Compile the fall-through case, if any if !exhaustive && kind != Single { if kind == Compare || kind == CompareSliceLength { - Br(bcx, else_cx.llbb); + Br(bcx, else_cx.data.llbb); } match chk { // If there is only one default arm left, move on to the next @@ -1236,12 +1236,12 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } -pub fn trans_match<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_match<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, match_expr: &ast::Expr, discr_expr: &ast::Expr, arms: &[ast::Arm], dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::trans_match"); trans_match_inner(bcx, match_expr.id, discr_expr, arms, dest) } @@ -1256,7 +1256,7 @@ fn is_discr_reassigned(bcx: Block, discr: &ast::Expr, body: &ast::Expr) -> bool reassigned: false }; { - let mut visitor = euv::ExprUseVisitor::new(&mut rc, bcx); + let mut visitor = euv::ExprUseVisitor::new(&mut rc, &bcx); visitor.walk_expr(body); } rc.reassigned @@ -1288,7 +1288,7 @@ impl<'tcx> euv::Delegate<'tcx> for ReassignmentChecker { } } -fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, +fn create_bindings_map<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, pat: &ast::Pat, discr: &ast::Expr, body: &ast::Expr) -> BindingsMap<'tcx> { // Create the bindings map, which is a mapping from each binding name @@ -1344,11 +1344,11 @@ fn create_bindings_map<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, pat: &ast::Pat, return bindings_map; } -fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, +fn trans_match_inner<'fcx, 'blk, 'tcx>(scope_cx: Block<'fcx, 'blk, 'tcx>, match_id: ast::NodeId, discr_expr: &ast::Expr, arms: &[ast::Arm], - dest: Dest) -> Block<'blk, 'tcx> { + dest: Dest) -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::trans_match_inner"); let fcx = scope_cx.fcx; let mut bcx = scope_cx; @@ -1356,7 +1356,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, let discr_datum = unpack_datum!(bcx, expr::trans_to_lvalue(bcx, discr_expr, "match")); - if bcx.unreachable.get() { + if bcx.data.unreachable.get() { return bcx; } @@ -1415,9 +1415,9 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>, return bcx; } -pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn store_local<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, local: &ast::Local) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Generates code for a local variable declaration like * `let ;` or `let = `. @@ -1427,9 +1427,9 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let tcx = bcx.tcx(); let pat = &*local.pat; - fn create_dummy_locals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, + fn create_dummy_locals<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, pat: &ast::Pat) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { // create dummy memory for the variables if we have no // value to store into them immediately let tcx = bcx.tcx(); @@ -1481,11 +1481,11 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +pub fn store_arg<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, pat: &ast::Pat, arg: Datum<'tcx, Rvalue>, arg_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Generates code for argument patterns like `fn foo(: T)`. * Creates entries in the `lllocals` map for each of the bindings @@ -1534,11 +1534,11 @@ pub fn store_arg<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, /// Generates code for the pattern binding in a `for` loop like /// `for in { ... }`. -pub fn store_for_loop_binding<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn store_for_loop_binding<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, pat: &ast::Pat, llvalue: ValueRef, body_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("match::store_for_loop_binding"); if simple_identifier(&*pat).is_some() { @@ -1556,14 +1556,14 @@ pub fn store_for_loop_binding<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bind_irrefutable_pat(bcx, pat, llvalue, body_scope) } -fn mk_binding_alloca<'blk, 'tcx, A>(bcx: Block<'blk, 'tcx>, +fn mk_binding_alloca<'fcx, 'blk, 'tcx, A>(bcx: Block<'fcx, 'blk, 'tcx>, p_id: ast::NodeId, ident: &ast::Ident, cleanup_scope: cleanup::ScopeId, arg: A, - populate: |A, Block<'blk, 'tcx>, ValueRef, Ty<'tcx>| - -> Block<'blk, 'tcx>) - -> Block<'blk, 'tcx> { + populate: |A, Block<'fcx, 'blk, 'tcx>, ValueRef, Ty<'tcx>| + -> Block<'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let var_ty = node_id_type(bcx, p_id); // Allocate memory on stack for the binding. @@ -1582,11 +1582,11 @@ fn mk_binding_alloca<'blk, 'tcx, A>(bcx: Block<'blk, 'tcx>, bcx } -fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn bind_irrefutable_pat<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, pat: &ast::Pat, val: ValueRef, cleanup_scope: cleanup::ScopeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * A simple version of the pattern matching code that only handles * irrefutable patterns. This is used in let/argument patterns, diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index e7d1b9726a1b1..d3e8bfd820716 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -144,7 +144,7 @@ pub struct Struct<'tcx> { * these, for places in trans where the `Ty` isn't directly * available. */ -pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn represent_node<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, node: ast::NodeId) -> Rc> { represent_type(bcx.ccx(), node_id_type(bcx, node)) } @@ -626,7 +626,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, st: &Struct<'tcx>, * * This should ideally be less tightly tied to `_match`. */ -pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_switch<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, scrutinee: ValueRef) -> (_match::BranchKind, Option) { match *r { @@ -643,7 +643,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Obtain the actual discriminant of a value. -pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, +pub fn trans_get_discr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, scrutinee: ValueRef, cast_to: Option) -> ValueRef { let signed; @@ -719,8 +719,8 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr) * * This should ideally be less tightly tied to `_match`. */ -pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr) - -> _match::OptResult<'blk, 'tcx> { +pub fn trans_case<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr, discr: Disr) + -> _match::OptResult<'fcx, 'blk, 'tcx> { match *r { CEnum(ity, _, _) => { _match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity), @@ -745,7 +745,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr) * Set the discriminant for a new value of the given case of the given * representation. */ -pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, +pub fn trans_set_discr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef, discr: Disr) { match *r { CEnum(ity, min, max) => { @@ -824,7 +824,7 @@ pub fn num_args(r: &Repr, discr: Disr) -> uint { } /// Access a field, at a point when the value's case is known. -pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, +pub fn trans_field_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef, discr: Disr, ix: uint) -> ValueRef { // Note: if this ever needs to generate conditionals (e.g., if we // decide to do some kind of cdr-coding-like non-unique repr @@ -863,7 +863,7 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, } } -pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, val: ValueRef, +pub fn struct_field_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, st: &Struct<'tcx>, val: ValueRef, ix: uint, needs_cast: bool) -> ValueRef { let val = if needs_cast { let ccx = bcx.ccx(); @@ -877,10 +877,10 @@ pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, v GEPi(bcx, val, &[0, ix]) } -pub fn fold_variants<'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, value: ValueRef, - f: |Block<'blk, 'tcx>, &Struct<'tcx>, ValueRef| -> Block<'blk, 'tcx>) - -> Block<'blk, 'tcx> { +pub fn fold_variants<'fcx, 'blk, 'tcx>( + bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, value: ValueRef, + f: |Block<'fcx, 'blk, 'tcx>, &Struct<'tcx>, ValueRef| -> Block<'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let fcx = bcx.fcx; match *r { Univariant(ref st, _) => { @@ -892,7 +892,7 @@ pub fn fold_variants<'blk, 'tcx>( Unreachable(unr_cx); let discr_val = trans_get_discr(bcx, r, value, None); - let llswitch = Switch(bcx, discr_val, unr_cx.llbb, cases.len()); + let llswitch = Switch(bcx, discr_val, unr_cx.data.llbb, cases.len()); let bcx_next = fcx.new_temp_block("enum-variant-iter-next"); for (discr, case) in cases.iter().enumerate() { @@ -900,7 +900,7 @@ pub fn fold_variants<'blk, 'tcx>( format!("enum-variant-iter-{}", discr.to_string()).as_slice() ); let rhs_val = C_integral(ll_inttype(ccx, ity), discr as u64, true); - AddCase(llswitch, rhs_val, variant_cx.llbb); + AddCase(llswitch, rhs_val, variant_cx.data.llbb); let fields = case.fields.iter().map(|&ty| type_of::type_of(bcx.ccx(), ty)).collect::>(); @@ -908,7 +908,7 @@ pub fn fold_variants<'blk, 'tcx>( let variant_value = PointerCast(variant_cx, value, real_ty.ptr_to()); variant_cx = f(variant_cx, case, variant_value); - Br(variant_cx, bcx_next.llbb); + Br(variant_cx, bcx_next.data.llbb); } bcx_next @@ -918,8 +918,8 @@ pub fn fold_variants<'blk, 'tcx>( } /// Access the struct drop flag, if present. -pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef) - -> datum::DatumBlock<'blk, 'tcx, datum::Expr> { +pub fn trans_drop_flag_ptr<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef) + -> datum::DatumBlock<'fcx, 'blk, 'tcx, datum::Expr> { let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), ty::mk_bool()); match *r { Univariant(ref st, true) => { diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 9b499b6d1a147..96ce12124e169 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -28,8 +28,8 @@ use syntax::ast; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM -pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm) - -> Block<'blk, 'tcx> { +pub fn trans_inline_asm<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ia: &ast::InlineAsm) + -> Block<'fcx, 'blk, 'tcx> { let fcx = bcx.fcx; let mut bcx = bcx; let mut constraints = Vec::new(); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index bdf2eca21d6ec..fc28cb8b25968 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -345,7 +345,7 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, // Returns a pointer to the body for the box. The box may be an opaque // box. The result will be casted to the type of body_t, if it is statically // known. -pub fn at_box_body<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn at_box_body<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, body_t: Ty<'tcx>, boxptr: ValueRef) -> ValueRef { let _icx = push_ctxt("at_box_body"); let ccx = bcx.ccx(); @@ -354,7 +354,7 @@ pub fn at_box_body<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, GEPi(bcx, boxptr, &[0u, abi::BOX_FIELD_BODY]) } -fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn require_alloc_fn<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, info_ty: Ty<'tcx>, it: LangItem) -> ast::DefId { match bcx.tcx().lang_items.require(it) { Ok(id) => id, @@ -369,12 +369,12 @@ fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // The following malloc_raw_dyn* functions allocate a box to contain // a given type, but with a potentially dynamic size. -pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn malloc_raw_dyn<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, llty_ptr: Type, info_ty: Ty<'tcx>, size: ValueRef, align: ValueRef) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("malloc_raw_exchange"); // Allocate space: @@ -386,8 +386,8 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } -pub fn malloc_raw_dyn_proc<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>) - -> Result<'blk, 'tcx> { +pub fn malloc_raw_dyn_proc<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>) + -> Result<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("malloc_raw_dyn_proc"); let ccx = bcx.ccx(); @@ -560,12 +560,12 @@ pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) { // Used only for creating scalar comparison glue. pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, } -pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn compare_scalar_types<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, t: Ty<'tcx>, op: ast::BinOp) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op)); match t.sty { @@ -581,7 +581,7 @@ pub fn compare_scalar_types<'blk, 'tcx>(cx: Block<'blk, 'tcx>, // A helper function to do the actual comparison of scalar values. -pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn compare_scalar_values<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, nt: scalar_type, @@ -641,8 +641,8 @@ pub fn compare_scalar_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>, } } -pub fn compare_simd_types<'blk, 'tcx>( - cx: Block<'blk, 'tcx>, +pub fn compare_simd_types<'fcx, 'blk, 'tcx>( + cx: Block<'fcx, 'blk, 'tcx>, lhs: ValueRef, rhs: ValueRef, t: Ty<'tcx>, @@ -679,24 +679,24 @@ pub fn compare_simd_types<'blk, 'tcx>( } } -pub type val_and_ty_fn<'a, 'blk, 'tcx> = - |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>; +pub type val_and_ty_fn<'a, 'fcx, 'blk, 'tcx> = + |Block<'fcx, 'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'fcx, 'blk, 'tcx>; // Iterates through the elements of a structural type. -pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn iter_structural_ty<'a, 'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, av: ValueRef, t: Ty<'tcx>, - f: val_and_ty_fn<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: val_and_ty_fn<'a, 'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("iter_structural_ty"); - fn iter_variant<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, + fn iter_variant<'a, 'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, repr: &adt::Repr<'tcx>, av: ValueRef, variant: &ty::VariantInfo<'tcx>, substs: &subst::Substs<'tcx>, - f: val_and_ty_fn<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: val_and_ty_fn<'a, 'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("iter_variant"); let tcx = cx.tcx(); let mut cx = cx; @@ -779,7 +779,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, cx = f(cx, lldiscrim_a, ty::mk_int()); let unr_cx = fcx.new_temp_block("enum-iter-unr"); Unreachable(unr_cx); - let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, + let llswitch = Switch(cx, lldiscrim_a, unr_cx.data.llbb, n_variants); let next_cx = fcx.new_temp_block("enum-iter-next"); @@ -791,7 +791,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, .as_slice()); match adt::trans_case(cx, &*repr, variant.disr_val) { _match::SingleResult(r) => { - AddCase(llswitch, r.val, variant_cx.llbb) + AddCase(llswitch, r.val, variant_cx.data.llbb) } _ => ccx.sess().unimpl("value from adt::trans_case \ in iter_structural_ty") @@ -803,7 +803,7 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, &**variant, substs, |x,y,z| f(x,y,z)); - Br(variant_cx, next_cx.llbb); + Br(variant_cx, next_cx.data.llbb); } cx = next_cx; } @@ -863,14 +863,14 @@ pub fn cast_shift_rhs(op: ast::BinOp, } } -pub fn fail_if_zero_or_overflows<'blk, 'tcx>( - cx: Block<'blk, 'tcx>, +pub fn fail_if_zero_or_overflows<'fcx, 'blk, 'tcx>( + cx: Block<'fcx, 'blk, 'tcx>, span: Span, divrem: ast::BinOp, lhs: ValueRef, rhs: ValueRef, rhs_t: Ty<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let (zero_text, overflow_text) = if divrem == ast::BiDiv { ("attempted to divide by zero", "attempted to divide with overflow") @@ -963,7 +963,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn invoke<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, llfn: ValueRef, llargs: Vec , fn_ty: Ty<'tcx>, @@ -971,9 +971,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // FIXME(15064) is_lang_item is a horrible hack, please remove it // at the soonest opportunity. is_lang_item: bool) - -> (ValueRef, Block<'blk, 'tcx>) { + -> (ValueRef, Block<'fcx, 'blk, 'tcx>) { let _icx = push_ctxt("invoke_"); - if bcx.unreachable.get() { + if bcx.data.unreachable.get() { return (C_null(Type::i8(bcx.ccx())), bcx); } @@ -985,7 +985,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, get_fn_llvm_attributes(bcx.ccx(), fn_ty) }; - match bcx.opt_node_id { + match bcx.data.opt_node_id { None => { debug!("invoke at ???"); } @@ -995,7 +995,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } if need_invoke(bcx) { - debug!("invoking {} at {}", llfn, bcx.llbb); + debug!("invoking {} at {}", llfn, bcx.data.llbb); for &llarg in llargs.iter() { debug!("arg: {}", llarg); } @@ -1010,12 +1010,12 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llresult = Invoke(bcx, llfn, llargs.as_slice(), - normal_bcx.llbb, + normal_bcx.data.llbb, landing_pad, Some(attributes)); return (llresult, normal_bcx); } else { - debug!("calling {} at {}", llfn, bcx.llbb); + debug!("calling {} at {}", llfn, bcx.data.llbb); for &llarg in llargs.iter() { debug!("arg: {}", llarg); } @@ -1036,21 +1036,21 @@ pub fn need_invoke(bcx: Block) -> bool { } // Avoid using invoke if we are already inside a landing pad. - if bcx.is_lpad { + if bcx.data.is_lpad { return false; } bcx.fcx.needs_invoke() } -pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn load_if_immediate<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>) -> ValueRef { let _icx = push_ctxt("load_if_immediate"); if type_is_immediate(cx.ccx(), t) { return load_ty(cx, v, t); } return v; } -pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn load_ty<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef { /*! * Helper for loading values from memory. Does the necessary conversion if @@ -1089,33 +1089,33 @@ pub fn ignore_lhs(_bcx: Block, local: &ast::Local) -> bool { } } -pub fn init_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, local: &ast::Local) - -> Block<'blk, 'tcx> { +pub fn init_local<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, local: &ast::Local) + -> Block<'fcx, 'blk, 'tcx> { debug!("init_local(bcx={}, local.id={})", bcx.to_str(), local.id); let _indenter = indenter(); let _icx = push_ctxt("init_local"); _match::store_local(bcx, local) } -pub fn raw_block<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, +pub fn raw_block<'fcx, 'blk, 'tcx>(fcx: &'fcx FunctionContext<'blk, 'tcx>, is_lpad: bool, llbb: BasicBlockRef) - -> Block<'blk, 'tcx> { - common::BlockS::new(llbb, is_lpad, None, fcx) + -> Block<'fcx, 'blk, 'tcx> { + common::Block::new(llbb, is_lpad, None, fcx) } -pub fn with_cond<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn with_cond<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef, - f: |Block<'blk, 'tcx>| -> Block<'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: |Block<'fcx, 'blk, 'tcx>| -> Block<'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("with_cond"); let fcx = bcx.fcx; let next_cx = fcx.new_temp_block("next"); let cond_cx = fcx.new_temp_block("cond"); - CondBr(bcx, val, cond_cx.llbb, next_cx.llbb); + CondBr(bcx, val, cond_cx.data.llbb, next_cx.data.llbb); let after_cx = f(cond_cx); - if !after_cx.terminated.get() { - Br(after_cx, next_cx.llbb); + if !after_cx.data.terminated.get() { + Br(after_cx, next_cx.data.llbb); } next_cx } @@ -1165,7 +1165,7 @@ pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, a Call(cx, memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } -pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn memcpy_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>) { let _icx = push_ctxt("memcpy_ty"); @@ -1180,8 +1180,8 @@ pub fn memcpy_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn zero_mem<'blk, 'tcx>(cx: Block<'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { - if cx.unreachable.get() { return; } +pub fn zero_mem<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, llptr: ValueRef, t: Ty<'tcx>) { + if cx.data.unreachable.get() { return; } let _icx = push_ctxt("zero_mem"); let bcx = cx; memzero(&B(bcx), llptr, t); @@ -1213,7 +1213,7 @@ fn memzero<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>) { b.call(llintrinsicfn, &[llptr, llzeroval, size, align, volatile], None); } -pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef { +pub fn alloc_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef { let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); @@ -1230,7 +1230,7 @@ pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef { pub fn alloca_no_lifetime(cx: Block, ty: Type, name: &str) -> ValueRef { let _icx = push_ctxt("alloca"); - if cx.unreachable.get() { + if cx.data.unreachable.get() { unsafe { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } @@ -1239,10 +1239,10 @@ pub fn alloca_no_lifetime(cx: Block, ty: Type, name: &str) -> ValueRef { Alloca(cx, ty, name) } -pub fn alloca_zeroed<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, +pub fn alloca_zeroed<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef { let llty = type_of::type_of(cx.ccx(), ty); - if cx.unreachable.get() { + if cx.data.unreachable.get() { unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); } @@ -1256,7 +1256,7 @@ pub fn alloca_zeroed<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, pub fn arrayalloca(cx: Block, ty: Type, v: ValueRef) -> ValueRef { let _icx = push_ctxt("arrayalloca"); - if cx.unreachable.get() { + if cx.data.unreachable.get() { unsafe { return llvm::LLVMGetUndef(ty.to_ref()); } @@ -1423,15 +1423,15 @@ fn has_nested_returns(tcx: &ty::ctxt, id: ast::NodeId) -> bool { // // Be warned! You must call `init_function` before doing anything with the // returned function context. -pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, +pub fn new_fn_ctxt<'blk, 'tcx>(ccx: &'blk CrateContext<'blk, 'tcx>, llfndecl: ValueRef, id: ast::NodeId, has_env: bool, output_type: ty::FnOutput<'tcx>, - param_substs: &'a Substs<'tcx>, + param_substs: &'blk Substs<'tcx>, sp: Option, - block_arena: &'a TypedArena>) - -> FunctionContext<'a, 'tcx> { + block_arena: &'blk TypedArena) + -> FunctionContext<'blk, 'tcx> { common::validate_substs(param_substs); debug!("new_fn_ctxt(path={}, id={}, param_substs={})", @@ -1481,17 +1481,17 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, /// Performs setup on a newly created function, creating the entry scope block /// and allocating space for the return pointer. -pub fn init_function<'a, 'tcx>(fcx: &'a FunctionContext<'a, 'tcx>, +pub fn init_function<'fcx, 'blk, 'tcx>(fcx: &'fcx FunctionContext<'blk, 'tcx>, skip_retptr: bool, output: ty::FnOutput<'tcx>) - -> Block<'a, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let entry_bcx = fcx.new_temp_block("entry-block"); // Use a dummy instruction as the insertion point for all allocas. // This is later removed in FunctionContext::cleanup. fcx.alloca_insert_pt.set(Some(unsafe { Load(entry_bcx, C_null(Type::i8p(fcx.ccx))); - llvm::LLVMGetFirstInstruction(entry_bcx.llbb) + llvm::LLVMGetFirstInstruction(entry_bcx.data.llbb) })); if let ty::FnConverging(output_type) = output { @@ -1554,8 +1554,8 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>, /// datums. /// /// FIXME(pcwalton): Reduce the amount of code bloat this is responsible for. -fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, +fn create_datums_for_fn_args_under_call_abi<'fcx, 'blk, 'tcx>( + mut bcx: Block<'fcx, 'blk, 'tcx>, arg_scope: cleanup::CustomScopeIndex, arg_tys: &[Ty<'tcx>]) -> Vec> { @@ -1615,12 +1615,12 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>( result } -fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, +fn copy_args_to_allocas<'fcx, 'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, arg_scope: cleanup::CustomScopeIndex, - bcx: Block<'blk, 'tcx>, + bcx: Block<'fcx, 'blk, 'tcx>, args: &[ast::Arg], arg_datums: Vec>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { debug!("copy_args_to_allocas"); let _icx = push_ctxt("copy_args_to_allocas"); @@ -1647,13 +1647,13 @@ fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, bcx } -fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, +fn copy_unboxed_closure_args_to_allocas<'fcx, 'blk, 'tcx>( + mut bcx: Block<'fcx, 'blk, 'tcx>, arg_scope: cleanup::CustomScopeIndex, args: &[ast::Arg], arg_datums: Vec>, monomorphized_arg_types: &[Ty<'tcx>]) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("copy_unboxed_closure_args_to_allocas"); let arg_scope_id = cleanup::CustomScope(arg_scope); @@ -1701,14 +1701,14 @@ fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>( // Ties up the llstaticallocas -> llloadenv -> lltop edges, // and builds the return block. -pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, - last_bcx: Block<'blk, 'tcx>, +pub fn finish_fn<'fcx, 'blk, 'tcx>(fcx: &'fcx FunctionContext<'blk, 'tcx>, + last_bcx: Block<'fcx, 'blk, 'tcx>, retty: ty::FnOutput<'tcx>) { let _icx = push_ctxt("finish_fn"); let ret_cx = match fcx.llreturn.get() { Some(llreturn) => { - if !last_bcx.terminated.get() { + if !last_bcx.data.terminated.get() { Br(last_bcx, llreturn); } raw_block(fcx, false, llreturn) @@ -1726,8 +1726,8 @@ pub fn finish_fn<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>, } // Builds the return block for a function. -pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, - ret_cx: Block<'blk, 'tcx>, +pub fn build_return_block<'fcx, 'blk, 'tcx>(fcx: &'fcx FunctionContext<'blk, 'tcx>, + ret_cx: Block<'fcx, 'blk, 'tcx>, retty: ty::FnOutput<'tcx>) { if fcx.llretslotptr.get().is_none() || (!fcx.needs_ret_allocas && fcx.caller_expects_out_pointer) { @@ -1921,7 +1921,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, unsafe { let llreturn = fcx.llreturn.get(); for &llreturn in llreturn.iter() { - llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb); + llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.data.llbb); } } @@ -1973,13 +1973,13 @@ pub fn trans_enum_variant<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfndecl); } -pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +pub fn trans_named_tuple_constructor<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, ctor_ty: Ty<'tcx>, disr: ty::Disr, args: callee::CallArgs, dest: expr::Dest, call_info: Option) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let ccx = bcx.fcx.ccx; let tcx = ccx.tcx(); diff --git a/src/librustc_trans/trans/build.rs b/src/librustc_trans/trans/build.rs index 1f77f625c9db3..5a6c2030d247f 100644 --- a/src/librustc_trans/trans/build.rs +++ b/src/librustc_trans/trans/build.rs @@ -25,18 +25,18 @@ use libc::{c_uint, c_char}; pub fn terminate(cx: Block, _: &str) { debug!("terminate({})", cx.to_str()); - cx.terminated.set(true); + cx.data.terminated.set(true); } pub fn check_not_terminated(cx: Block) { - if cx.terminated.get() { + if cx.data.terminated.get() { panic!("already terminated!"); } } -pub fn B<'blk, 'tcx>(cx: Block<'blk, 'tcx>) -> Builder<'blk, 'tcx> { +pub fn B<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>) -> Builder<'blk, 'tcx> { let b = cx.fcx.ccx.builder(); - b.position_at_end(cx.llbb); + b.position_at_end(cx.data.llbb); b } @@ -49,28 +49,28 @@ pub fn B<'blk, 'tcx>(cx: Block<'blk, 'tcx>) -> Builder<'blk, 'tcx> { // further instructions to the block should simply be ignored. pub fn RetVoid(cx: Block) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "RetVoid"); B(cx).ret_void(); } pub fn Ret(cx: Block, v: ValueRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "Ret"); B(cx).ret(v); } pub fn AggregateRet(cx: Block, ret_vals: &[ValueRef]) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "AggregateRet"); B(cx).aggregate_ret(ret_vals); } pub fn Br(cx: Block, dest: BasicBlockRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "Br"); B(cx).br(dest); @@ -80,7 +80,7 @@ pub fn CondBr(cx: Block, if_: ValueRef, then: BasicBlockRef, else_: BasicBlockRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "CondBr"); B(cx).cond_br(if_, then, else_); @@ -88,7 +88,7 @@ pub fn CondBr(cx: Block, pub fn Switch(cx: Block, v: ValueRef, else_: BasicBlockRef, num_cases: uint) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } check_not_terminated(cx); terminate(cx, "Switch"); B(cx).switch(v, else_, num_cases) @@ -102,7 +102,7 @@ pub fn AddCase(s: ValueRef, on_val: ValueRef, dest: BasicBlockRef) { } pub fn IndirectBr(cx: Block, addr: ValueRef, num_dests: uint) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } check_not_terminated(cx); terminate(cx, "IndirectBr"); B(cx).indirect_br(addr, num_dests); @@ -115,7 +115,7 @@ pub fn Invoke(cx: Block, catch: BasicBlockRef, attributes: Option) -> ValueRef { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return C_null(Type::i8(cx.ccx())); } check_not_terminated(cx); @@ -127,11 +127,11 @@ pub fn Invoke(cx: Block, } pub fn Unreachable(cx: Block) { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return } - cx.unreachable.set(true); - if !cx.terminated.get() { + cx.data.unreachable.set(true); + if !cx.data.terminated.get() { B(cx).unreachable(); } } @@ -144,164 +144,164 @@ pub fn _Undef(val: ValueRef) -> ValueRef { /* Arithmetic */ pub fn Add(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).add(lhs, rhs) } pub fn NSWAdd(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nswadd(lhs, rhs) } pub fn NUWAdd(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nuwadd(lhs, rhs) } pub fn FAdd(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).fadd(lhs, rhs) } pub fn Sub(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).sub(lhs, rhs) } pub fn NSWSub(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nswsub(lhs, rhs) } pub fn NUWSub(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nuwsub(lhs, rhs) } pub fn FSub(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).fsub(lhs, rhs) } pub fn Mul(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).mul(lhs, rhs) } pub fn NSWMul(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nswmul(lhs, rhs) } pub fn NUWMul(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).nuwmul(lhs, rhs) } pub fn FMul(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).fmul(lhs, rhs) } pub fn UDiv(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).udiv(lhs, rhs) } pub fn SDiv(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).sdiv(lhs, rhs) } pub fn ExactSDiv(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).exactsdiv(lhs, rhs) } pub fn FDiv(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).fdiv(lhs, rhs) } pub fn URem(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).urem(lhs, rhs) } pub fn SRem(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).srem(lhs, rhs) } pub fn FRem(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).frem(lhs, rhs) } pub fn Shl(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).shl(lhs, rhs) } pub fn LShr(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).lshr(lhs, rhs) } pub fn AShr(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).ashr(lhs, rhs) } pub fn And(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).and(lhs, rhs) } pub fn Or(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).or(lhs, rhs) } pub fn Xor(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).xor(lhs, rhs) } pub fn BinOp(cx: Block, op: Opcode, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(lhs); } + if cx.data.unreachable.get() { return _Undef(lhs); } B(cx).binop(op, lhs, rhs) } pub fn Neg(cx: Block, v: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } B(cx).neg(v) } pub fn NSWNeg(cx: Block, v: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } B(cx).nswneg(v) } pub fn NUWNeg(cx: Block, v: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } B(cx).nuwneg(v) } pub fn FNeg(cx: Block, v: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } B(cx).fneg(v) } pub fn Not(cx: Block, v: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(v); } + if cx.data.unreachable.get() { return _Undef(v); } B(cx).not(v) } /* Memory */ pub fn Malloc(cx: Block, ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref()); } B(cx).malloc(ty) @@ -310,7 +310,7 @@ pub fn Malloc(cx: Block, ty: Type) -> ValueRef { pub fn ArrayMalloc(cx: Block, ty: Type, val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref()); } B(cx).array_malloc(ty, val) @@ -319,7 +319,7 @@ pub fn ArrayMalloc(cx: Block, ty: Type, val: ValueRef) -> ValueRef { pub fn Alloca(cx: Block, ty: Type, name: &str) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } AllocaFcx(cx.fcx, ty, name) } } @@ -332,7 +332,7 @@ pub fn AllocaFcx(fcx: &FunctionContext, ty: Type, name: &str) -> ValueRef { pub fn ArrayAlloca(cx: Block, ty: Type, val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ty.ptr_to().to_ref()); } let b = cx.fcx.ccx.builder(); b.position_before(cx.fcx.alloca_insert_pt.get().unwrap()); b.array_alloca(ty, val) @@ -340,14 +340,14 @@ pub fn ArrayAlloca(cx: Block, ty: Type, val: ValueRef) -> ValueRef { } pub fn Free(cx: Block, pointer_val: ValueRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).free(pointer_val) } pub fn Load(cx: Block, pointer_val: ValueRef) -> ValueRef { unsafe { let ccx = cx.fcx.ccx; - if cx.unreachable.get() { + if cx.data.unreachable.get() { let ty = val_ty(pointer_val); let eltty = if ty.kind() == llvm::Array { ty.element_type() @@ -362,7 +362,7 @@ pub fn Load(cx: Block, pointer_val: ValueRef) -> ValueRef { pub fn VolatileLoad(cx: Block, pointer_val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).volatile_load(pointer_val) @@ -372,7 +372,7 @@ pub fn VolatileLoad(cx: Block, pointer_val: ValueRef) -> ValueRef { pub fn AtomicLoad(cx: Block, pointer_val: ValueRef, order: AtomicOrdering) -> ValueRef { unsafe { let ccx = cx.fcx.ccx; - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ccx.int_type().to_ref()); } B(cx).atomic_load(pointer_val, order) @@ -382,7 +382,7 @@ pub fn AtomicLoad(cx: Block, pointer_val: ValueRef, order: AtomicOrdering) -> Va pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: u64, hi: u64, signed: llvm::Bool) -> ValueRef { - if cx.unreachable.get() { + if cx.data.unreachable.get() { let ccx = cx.fcx.ccx; let ty = val_ty(pointer_val); let eltty = if ty.kind() == llvm::Array { @@ -399,23 +399,23 @@ pub fn LoadRangeAssert(cx: Block, pointer_val: ValueRef, lo: u64, } pub fn Store(cx: Block, val: ValueRef, ptr: ValueRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).store(val, ptr) } pub fn VolatileStore(cx: Block, val: ValueRef, ptr: ValueRef) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).volatile_store(val, ptr) } pub fn AtomicStore(cx: Block, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).atomic_store(val, ptr, order) } pub fn GEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref()); } B(cx).gep(pointer, indices) @@ -427,7 +427,7 @@ pub fn GEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef { #[inline] pub fn GEPi(cx: Block, base: ValueRef, ixs: &[uint]) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref()); } B(cx).gepi(base, ixs) @@ -436,7 +436,7 @@ pub fn GEPi(cx: Block, base: ValueRef, ixs: &[uint]) -> ValueRef { pub fn InBoundsGEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref()); } B(cx).inbounds_gep(pointer, indices) @@ -445,7 +445,7 @@ pub fn InBoundsGEP(cx: Block, pointer: ValueRef, indices: &[ValueRef]) -> ValueR pub fn StructGEP(cx: Block, pointer: ValueRef, idx: uint) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).ptr_to().to_ref()); } B(cx).struct_gep(pointer, idx) @@ -454,7 +454,7 @@ pub fn StructGEP(cx: Block, pointer: ValueRef, idx: uint) -> ValueRef { pub fn GlobalString(cx: Block, _str: *const c_char) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref()); } B(cx).global_string(_str) @@ -463,7 +463,7 @@ pub fn GlobalString(cx: Block, _str: *const c_char) -> ValueRef { pub fn GlobalStringPtr(cx: Block, _str: *const c_char) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i8p(cx.ccx()).to_ref()); } B(cx).global_string_ptr(_str) @@ -473,105 +473,105 @@ pub fn GlobalStringPtr(cx: Block, _str: *const c_char) -> ValueRef { /* Casts */ pub fn Trunc(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).trunc(val, dest_ty) } } pub fn ZExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).zext(val, dest_ty) } } pub fn SExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).sext(val, dest_ty) } } pub fn FPToUI(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).fptoui(val, dest_ty) } } pub fn FPToSI(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).fptosi(val, dest_ty) } } pub fn UIToFP(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).uitofp(val, dest_ty) } } pub fn SIToFP(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).sitofp(val, dest_ty) } } pub fn FPTrunc(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).fptrunc(val, dest_ty) } } pub fn FPExt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).fpext(val, dest_ty) } } pub fn PtrToInt(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).ptrtoint(val, dest_ty) } } pub fn IntToPtr(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).inttoptr(val, dest_ty) } } pub fn BitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).bitcast(val, dest_ty) } } pub fn ZExtOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).zext_or_bitcast(val, dest_ty) } } pub fn SExtOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).sext_or_bitcast(val, dest_ty) } } pub fn TruncOrBitCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).trunc_or_bitcast(val, dest_ty) } } @@ -580,28 +580,28 @@ pub fn Cast(cx: Block, op: Opcode, val: ValueRef, dest_ty: Type, _: *const u8) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).cast(op, val, dest_ty) } } pub fn PointerCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).pointercast(val, dest_ty) } } pub fn IntCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).intcast(val, dest_ty) } } pub fn FPCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(dest_ty.to_ref()); } B(cx).fpcast(val, dest_ty) } } @@ -611,7 +611,7 @@ pub fn FPCast(cx: Block, val: ValueRef, dest_ty: Type) -> ValueRef { pub fn ICmp(cx: Block, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref()); } B(cx).icmp(op, lhs, rhs) @@ -621,7 +621,7 @@ pub fn ICmp(cx: Block, op: IntPredicate, lhs: ValueRef, rhs: ValueRef) pub fn FCmp(cx: Block, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref()); } B(cx).fcmp(op, lhs, rhs) @@ -631,7 +631,7 @@ pub fn FCmp(cx: Block, op: RealPredicate, lhs: ValueRef, rhs: ValueRef) /* Miscellaneous instructions */ pub fn EmptyPhi(cx: Block, ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } B(cx).empty_phi(ty) } } @@ -639,7 +639,7 @@ pub fn EmptyPhi(cx: Block, ty: Type) -> ValueRef { pub fn Phi(cx: Block, ty: Type, vals: &[ValueRef], bbs: &[BasicBlockRef]) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } B(cx).phi(ty, vals, bbs) } } @@ -682,36 +682,36 @@ pub fn InlineAsmCall(cx: Block, asm: *const c_char, cons: *const c_char, pub fn Call(cx: Block, fn_: ValueRef, args: &[ValueRef], attributes: Option) -> ValueRef { - if cx.unreachable.get() { return _UndefReturn(cx, fn_); } + if cx.data.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call(fn_, args, attributes) } pub fn CallWithConv(cx: Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv, attributes: Option) -> ValueRef { - if cx.unreachable.get() { return _UndefReturn(cx, fn_); } + if cx.data.unreachable.get() { return _UndefReturn(cx, fn_); } B(cx).call_with_conv(fn_, args, conv, attributes) } pub fn AtomicFence(cx: Block, order: AtomicOrdering) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).atomic_fence(order) } pub fn Select(cx: Block, if_: ValueRef, then: ValueRef, else_: ValueRef) -> ValueRef { - if cx.unreachable.get() { return _Undef(then); } + if cx.data.unreachable.get() { return _Undef(then); } B(cx).select(if_, then, else_) } pub fn VAArg(cx: Block, list: ValueRef, ty: Type) -> ValueRef { unsafe { - if cx.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ty.to_ref()); } B(cx).va_arg(list, ty) } } pub fn ExtractElement(cx: Block, vec_val: ValueRef, index: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).extract_element(vec_val, index) @@ -721,7 +721,7 @@ pub fn ExtractElement(cx: Block, vec_val: ValueRef, index: ValueRef) -> ValueRef pub fn InsertElement(cx: Block, vec_val: ValueRef, elt_val: ValueRef, index: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).insert_element(vec_val, elt_val, index) @@ -731,7 +731,7 @@ pub fn InsertElement(cx: Block, vec_val: ValueRef, elt_val: ValueRef, pub fn ShuffleVector(cx: Block, v1: ValueRef, v2: ValueRef, mask: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).shuffle_vector(v1, v2, mask) @@ -740,7 +740,7 @@ pub fn ShuffleVector(cx: Block, v1: ValueRef, v2: ValueRef, pub fn VectorSplat(cx: Block, num_elts: uint, elt_val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).vector_splat(num_elts, elt_val) @@ -749,7 +749,7 @@ pub fn VectorSplat(cx: Block, num_elts: uint, elt_val: ValueRef) -> ValueRef { pub fn ExtractValue(cx: Block, agg_val: ValueRef, index: uint) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).extract_value(agg_val, index) @@ -758,7 +758,7 @@ pub fn ExtractValue(cx: Block, agg_val: ValueRef, index: uint) -> ValueRef { pub fn InsertValue(cx: Block, agg_val: ValueRef, elt_val: ValueRef, index: uint) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::nil(cx.ccx()).to_ref()); } B(cx).insert_value(agg_val, elt_val, index) @@ -767,7 +767,7 @@ pub fn InsertValue(cx: Block, agg_val: ValueRef, elt_val: ValueRef, index: uint) pub fn IsNull(cx: Block, val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref()); } B(cx).is_null(val) @@ -776,7 +776,7 @@ pub fn IsNull(cx: Block, val: ValueRef) -> ValueRef { pub fn IsNotNull(cx: Block, val: ValueRef) -> ValueRef { unsafe { - if cx.unreachable.get() { + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(Type::i1(cx.ccx()).to_ref()); } B(cx).is_not_null(val) @@ -786,20 +786,20 @@ pub fn IsNotNull(cx: Block, val: ValueRef) -> ValueRef { pub fn PtrDiff(cx: Block, lhs: ValueRef, rhs: ValueRef) -> ValueRef { unsafe { let ccx = cx.fcx.ccx; - if cx.unreachable.get() { return llvm::LLVMGetUndef(ccx.int_type().to_ref()); } + if cx.data.unreachable.get() { return llvm::LLVMGetUndef(ccx.int_type().to_ref()); } B(cx).ptrdiff(lhs, rhs) } } pub fn Trap(cx: Block) { - if cx.unreachable.get() { return; } + if cx.data.unreachable.get() { return; } B(cx).trap(); } pub fn LandingPad(cx: Block, ty: Type, pers_fn: ValueRef, num_clauses: uint) -> ValueRef { check_not_terminated(cx); - assert!(!cx.unreachable.get()); + assert!(!cx.data.unreachable.get()); B(cx).landing_pad(ty, pers_fn, num_clauses) } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 6d0f598044235..299249b473d6c 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -83,13 +83,13 @@ pub enum CalleeData<'tcx> { TraitItem(MethodData) } -pub struct Callee<'blk, 'tcx: 'blk> { - pub bcx: Block<'blk, 'tcx>, +pub struct Callee<'fcx, 'blk: 'fcx, 'tcx: 'blk> { + pub bcx: Block<'fcx, 'blk, 'tcx>, pub data: CalleeData<'tcx>, } -fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) - -> Callee<'blk, 'tcx> { +fn trans<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) + -> Callee<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_callee"); debug!("callee::trans(expr={})", expr.repr(bcx.tcx())); @@ -104,8 +104,8 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) // any other expressions are closures: return datum_callee(bcx, expr); - fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) - -> Callee<'blk, 'tcx> { + fn datum_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) + -> Callee<'fcx, 'blk, 'tcx> { let DatumBlock {mut bcx, datum} = expr::trans(bcx, expr); match datum.ty.sty { ty::ty_bare_fn(..) => { @@ -133,18 +133,18 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } } - fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn: ValueRef) - -> Callee<'blk, 'tcx> { + fn fn_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, llfn: ValueRef) + -> Callee<'fcx, 'blk, 'tcx> { return Callee { bcx: bcx, data: Fn(llfn), }; } - fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn trans_def<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, def: def::Def, ref_expr: &ast::Expr) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { debug!("trans_def(def={}, ref_expr={})", def.repr(bcx.tcx()), ref_expr.repr(bcx.tcx())); let expr_ty = node_id_type(bcx, ref_expr.id); match def { @@ -237,11 +237,11 @@ pub fn trans_fn_ref(bcx: Block, def_id: ast::DefId, node: ExprOrMethodCall) -> V trans_fn_ref_with_substs(bcx, def_id, node, substs) } -fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_fn_ref_with_substs_to_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, def_id: ast::DefId, ref_id: ast::NodeId, substs: subst::Substs<'tcx>) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { Callee { bcx: bcx, data: Fn(trans_fn_ref_with_substs(bcx, @@ -253,7 +253,7 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Translates the adapter that deconstructs a `Box` object into /// `Trait` so that a by-value self method can be called. -pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_unboxing_shim<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, llshimmedfn: ValueRef, fty: &ty::BareFnTy<'tcx>, method_id: ast::DefId, @@ -318,9 +318,9 @@ pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, boxed_function_type, function_name.as_slice()); - let block_arena = TypedArena::new(); let empty_param_substs = Substs::trans_empty(); let return_type = ty::ty_fn_ret(boxed_function_type); + let block_arena = TypedArena::new(); let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, @@ -398,8 +398,8 @@ pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, llfn } -pub fn trans_fn_ref_with_substs<'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, // +pub fn trans_fn_ref_with_substs<'fcx, 'blk, 'tcx>( + bcx: Block<'fcx, 'blk, 'tcx>, // def_id: ast::DefId, // def id of fn node: ExprOrMethodCall, // node id of use of fn; may be zero if N/A substs: subst::Substs<'tcx>) // vtables for the call @@ -609,12 +609,12 @@ pub fn trans_fn_ref_with_substs<'blk, 'tcx>( // ______________________________________________________________________ // Translating calls -pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>, +pub fn trans_call<'a, 'fcx, 'blk, 'tcx>(in_cx: Block<'fcx, 'blk, 'tcx>, call_ex: &ast::Expr, f: &ast::Expr, args: CallArgs<'a, 'tcx>, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_call"); trans_call_inner(in_cx, Some(common::expr_info(call_ex)), @@ -624,12 +624,12 @@ pub fn trans_call<'a, 'blk, 'tcx>(in_cx: Block<'blk, 'tcx>, Some(dest)).bcx } -pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_method_call<'a, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, call_ex: &ast::Expr, rcvr: &ast::Expr, args: CallArgs<'a, 'tcx>, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_method_call"); debug!("trans_method_call(call_ex={})", call_ex.repr(bcx.tcx())); let method_call = MethodCall::expr(call_ex.id); @@ -645,11 +645,11 @@ pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(dest)).bcx } -pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_lang_call<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, did: ast::DefId, args: &[ValueRef], dest: Option) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let fty = if did.krate == ast::LOCAL_CRATE { ty::node_id_to_type(bcx.tcx(), did.node) } else { @@ -668,15 +668,15 @@ pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dest) } -pub fn trans_call_inner<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_call_inner<'a, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, call_info: Option, callee_ty: Ty<'tcx>, - get_callee: |bcx: Block<'blk, 'tcx>, + get_callee: |bcx: Block<'fcx, 'blk, 'tcx>, arg_cleanup_scope: cleanup::ScopeId| - -> Callee<'blk, 'tcx>, + -> Callee<'fcx, 'blk, 'tcx>, args: CallArgs<'a, 'tcx>, dest: Option) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { /*! * This behemoth of a function translates function calls. * Unfortunately, in order to generate more efficient LLVM @@ -909,14 +909,14 @@ pub enum CallArgs<'a, 'tcx> { ArgOverloadedCall(Vec<&'a ast::Expr>), } -fn trans_args_under_call_abi<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, +fn trans_args_under_call_abi<'fcx, 'blk, 'tcx>( + mut bcx: Block<'fcx, 'blk, 'tcx>, arg_exprs: &[P], fn_ty: Ty<'tcx>, llargs: &mut Vec, arg_cleanup_scope: cleanup::ScopeId, ignore_self: bool) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { // Translate the `self` argument first. if !ignore_self { let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &*arg_exprs[0])); @@ -968,14 +968,14 @@ fn trans_args_under_call_abi<'blk, 'tcx>( bcx } -fn trans_overloaded_call_args<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, +fn trans_overloaded_call_args<'fcx, 'blk, 'tcx>( + mut bcx: Block<'fcx, 'blk, 'tcx>, arg_exprs: Vec<&ast::Expr>, fn_ty: Ty<'tcx>, llargs: &mut Vec, arg_cleanup_scope: cleanup::ScopeId, ignore_self: bool) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { // Translate the `self` argument first. let arg_tys = ty::ty_fn_args(fn_ty); if !ignore_self { @@ -1014,14 +1014,14 @@ fn trans_overloaded_call_args<'blk, 'tcx>( bcx } -pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, +pub fn trans_args<'a, 'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, args: CallArgs<'a, 'tcx>, fn_ty: Ty<'tcx>, llargs: &mut Vec, arg_cleanup_scope: cleanup::ScopeId, ignore_self: bool, abi: synabi::Abi) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { debug!("trans_args(abi={})", abi); let _icx = push_ctxt("trans_args"); @@ -1105,12 +1105,12 @@ pub enum AutorefArg { DoAutorefArg(ast::NodeId) } -pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_arg_datum<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, formal_arg_ty: Ty<'tcx>, arg_datum: Datum<'tcx, Expr>, arg_cleanup_scope: cleanup::ScopeId, autoref_arg: AutorefArg) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_arg_datum"); let mut bcx = bcx; let ccx = bcx.ccx(); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 21589874f5c44..d294dcb97575c 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -23,7 +23,7 @@ use trans::base; use trans::build; use trans::callee; use trans::common; -use trans::common::{Block, FunctionContext, ExprId, NodeInfo}; +use trans::common::{Block, BlockS, FunctionContext, ExprId, NodeInfo}; use trans::debuginfo; use trans::glue; use middle::region; @@ -33,13 +33,13 @@ use std::fmt; use syntax::ast; use util::ppaux::Repr; -pub struct CleanupScope<'blk, 'tcx: 'blk> { +pub struct CleanupScope<'blk, 'tcx> { // The id of this cleanup scope. If the id is None, // this is a *temporary scope* that is pushed during trans to // cleanup miscellaneous garbage that trans may generate whose // lifetime is a subset of some expression. See module doc for // more details. - kind: CleanupScopeKind<'blk, 'tcx>, + kind: CleanupScopeKind<'blk>, // Cleanups to run upon scope exit. cleanups: Vec>, @@ -61,13 +61,13 @@ pub const EXIT_BREAK: uint = 0; pub const EXIT_LOOP: uint = 1; pub const EXIT_MAX: uint = 2; -pub enum CleanupScopeKind<'blk, 'tcx: 'blk> { +pub enum CleanupScopeKind<'blk> { CustomScopeKind, AstScopeKind(ast::NodeId), - LoopScopeKind(ast::NodeId, [Block<'blk, 'tcx>, ..EXIT_MAX]) + LoopScopeKind(ast::NodeId, [&'blk BlockS, ..EXIT_MAX]) } -impl<'blk, 'tcx: 'blk> fmt::Show for CleanupScopeKind<'blk, 'tcx> { +impl<'blk> fmt::Show for CleanupScopeKind<'blk> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { CustomScopeKind => write!(f, "CustomScopeKind"), @@ -99,10 +99,10 @@ pub trait Cleanup<'tcx> { fn must_unwind(&self) -> bool; fn clean_on_unwind(&self) -> bool; fn is_lifetime_end(&self) -> bool; - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, + fn trans<'fcx, 'blk>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, debug_loc: Option) - -> Block<'blk, 'tcx>; + -> Block<'fcx, 'blk, 'tcx>; } pub type CleanupObj<'tcx> = Box+'tcx>; @@ -154,7 +154,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { fn push_loop_cleanup_scope(&self, id: ast::NodeId, - exits: [Block<'blk, 'tcx>, ..EXIT_MAX]) { + exits: [&'blk BlockS, ..EXIT_MAX]) { debug!("push_loop_cleanup_scope({})", self.ccx.tcx().map.node_to_string(id)); assert_eq!(Some(id), self.top_ast_scope()); @@ -194,10 +194,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { CustomScopeIndex { index: index } } - fn pop_and_trans_ast_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, + fn pop_and_trans_ast_cleanup_scope<'fcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, cleanup_scope: ast::NodeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Removes the cleanup scope for id `cleanup_scope`, which * must be at the top of the cleanup stack, and generates the @@ -243,10 +243,10 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { let _ = self.pop_scope(); } - fn pop_and_trans_custom_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, + fn pop_and_trans_custom_cleanup_scope<'fcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, custom_scope: CustomScopeIndex) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Removes the top cleanup scope from the stack, which must be * a temporary scope, and generates the code to do its @@ -276,7 +276,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { self.ccx.sess().bug("no loop scope found"); } - fn normal_exit_block(&'blk self, + fn normal_exit_block(&self, cleanup_scope: ast::NodeId, exit: uint) -> BasicBlockRef { /*! @@ -288,7 +288,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { self.trans_cleanups_to_exit_scope(LoopExit(cleanup_scope, exit)) } - fn return_exit_block(&'blk self) -> BasicBlockRef { + fn return_exit_block(&self) -> BasicBlockRef { /*! * Returns a block to branch to which will perform all pending * cleanups and then return from this function @@ -495,7 +495,7 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> { self.scopes.borrow().iter().rev().any(|s| s.needs_invoke()) } - fn get_landing_pad(&'blk self) -> BasicBlockRef { + fn get_landing_pad(&self) -> BasicBlockRef { /*! * Returns a basic block to branch to in the event of a panic. * This block will run the panic cleanups and eventually @@ -564,13 +564,13 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx (*scopes)[custom_scope.index].kind.is_temp() } - fn trans_scope_cleanups(&self, // cannot borrow self, will recurse - bcx: Block<'blk, 'tcx>, - scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx> { + fn trans_scope_cleanups<'fcx>(&self, // cannot borrow self, will recurse + bcx: Block<'fcx, 'blk, 'tcx>, + scope: &CleanupScope<'blk, 'tcx>) -> Block<'fcx, 'blk, 'tcx> { /*! Generates the cleanups for `scope` into `bcx` */ let mut bcx = bcx; - if !bcx.unreachable.get() { + if !bcx.data.unreachable.get() { for cleanup in scope.cleanups.iter().rev() { bcx = cleanup.trans(bcx, scope.debug_loc); } @@ -598,7 +598,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx f(self.scopes.borrow().last().unwrap()) } - fn trans_cleanups_to_exit_scope(&'blk self, + fn trans_cleanups_to_exit_scope(&self, label: EarlyExitLabel) -> BasicBlockRef { /*! @@ -654,7 +654,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx "create_landing_pad() should have set this"); build::Resume(prev_bcx, build::Load(prev_bcx, personality)); - prev_llbb = prev_bcx.llbb; + prev_llbb = prev_bcx.data.llbb; break; } @@ -745,7 +745,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx } } build::Br(bcx_out, prev_llbb); - prev_llbb = bcx_in.llbb; + prev_llbb = bcx_in.data.llbb; } else { debug!("no suitable cleanups in {}", scope.block_name("clean")); @@ -761,7 +761,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx prev_llbb } - fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef { + fn get_or_create_landing_pad(&self) -> BasicBlockRef { /*! * Creates a landing pad for the top scope, if one does not * exist. The landing pad will perform all cleanups necessary @@ -788,7 +788,7 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx None => { let name = last_scope.block_name("unwind"); pad_bcx = self.new_block(true, name.as_slice(), None); - last_scope.cached_landing_pad = Some(pad_bcx.llbb); + last_scope.cached_landing_pad = Some(pad_bcx.data.llbb); } } } @@ -850,12 +850,12 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx let cleanup_llbb = self.trans_cleanups_to_exit_scope(UnwindExit); build::Br(pad_bcx, cleanup_llbb); - return pad_bcx.llbb; + return pad_bcx.data.llbb; } } impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { - fn new(kind: CleanupScopeKind<'blk, 'tcx>, + fn new(kind: CleanupScopeKind<'blk>, debug_loc: Option) -> CleanupScope<'blk, 'tcx> { CleanupScope { @@ -913,7 +913,7 @@ impl<'blk, 'tcx> CleanupScope<'blk, 'tcx> { } } -impl<'blk, 'tcx> CleanupScopeKind<'blk, 'tcx> { +impl<'blk> CleanupScopeKind<'blk> { fn is_temp(&self) -> bool { match *self { CustomScopeKind => true, @@ -983,10 +983,10 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { false } - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, + fn trans<'fcx, 'blk>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, debug_loc: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let bcx = if self.is_immediate { glue::drop_ty_immediate(bcx, self.val, self.ty, debug_loc) } else { @@ -1023,10 +1023,10 @@ impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { false } - fn trans<'blk>(&self, - bcx: Block<'blk, 'tcx>, + fn trans<'fcx, 'blk>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, debug_loc: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { apply_debug_loc(bcx.fcx, debug_loc); match self.heap { @@ -1057,10 +1057,10 @@ impl<'tcx> Cleanup<'tcx> for FreeSlice { false } - fn trans<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn trans<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, debug_loc: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { apply_debug_loc(bcx.fcx, debug_loc); match self.heap { @@ -1088,10 +1088,10 @@ impl<'tcx> Cleanup<'tcx> for LifetimeEnd { true } - fn trans<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn trans<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, debug_loc: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { apply_debug_loc(bcx.fcx, debug_loc); base::call_lifetime_end(bcx, self.ptr); bcx @@ -1145,28 +1145,28 @@ pub trait CleanupMethods<'blk, 'tcx> { fn push_ast_cleanup_scope(&self, id: NodeInfo); fn push_loop_cleanup_scope(&self, id: ast::NodeId, - exits: [Block<'blk, 'tcx>, ..EXIT_MAX]); + exits: [&'blk BlockS, ..EXIT_MAX]); fn push_custom_cleanup_scope(&self) -> CustomScopeIndex; fn push_custom_cleanup_scope_with_debug_loc(&self, debug_loc: NodeInfo) -> CustomScopeIndex; - fn pop_and_trans_ast_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, + fn pop_and_trans_ast_cleanup_scope<'fcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, cleanup_scope: ast::NodeId) - -> Block<'blk, 'tcx>; + -> Block<'fcx, 'blk, 'tcx>; fn pop_loop_cleanup_scope(&self, cleanup_scope: ast::NodeId); fn pop_custom_cleanup_scope(&self, custom_scope: CustomScopeIndex); - fn pop_and_trans_custom_cleanup_scope(&self, - bcx: Block<'blk, 'tcx>, + fn pop_and_trans_custom_cleanup_scope<'fcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, custom_scope: CustomScopeIndex) - -> Block<'blk, 'tcx>; + -> Block<'fcx, 'blk, 'tcx>; fn top_loop_scope(&self) -> ast::NodeId; - fn normal_exit_block(&'blk self, + fn normal_exit_block(&self, cleanup_scope: ast::NodeId, exit: uint) -> BasicBlockRef; - fn return_exit_block(&'blk self) -> BasicBlockRef; + fn return_exit_block(&self) -> BasicBlockRef; fn schedule_lifetime_end(&self, cleanup_scope: ScopeId, val: ValueRef); @@ -1203,7 +1203,7 @@ pub trait CleanupMethods<'blk, 'tcx> { custom_scope: CustomScopeIndex, cleanup: CleanupObj<'tcx>); fn needs_invoke(&self) -> bool; - fn get_landing_pad(&'blk self) -> BasicBlockRef; + fn get_landing_pad(&self) -> BasicBlockRef; } trait CleanupHelperMethods<'blk, 'tcx> { @@ -1211,13 +1211,13 @@ trait CleanupHelperMethods<'blk, 'tcx> { fn top_nonempty_cleanup_scope(&self) -> Option; fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool; fn is_valid_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool; - fn trans_scope_cleanups(&self, - bcx: Block<'blk, 'tcx>, - scope: &CleanupScope<'blk, 'tcx>) -> Block<'blk, 'tcx>; - fn trans_cleanups_to_exit_scope(&'blk self, + fn trans_scope_cleanups<'fcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, + scope: &CleanupScope<'blk, 'tcx>) -> Block<'fcx, 'blk, 'tcx>; + fn trans_cleanups_to_exit_scope(&self, label: EarlyExitLabel) -> BasicBlockRef; - fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef; + fn get_or_create_landing_pad(&self) -> BasicBlockRef; fn scopes_len(&self) -> uint; fn push_scope(&self, scope: CleanupScope<'blk, 'tcx>); fn pop_scope(&self) -> CleanupScope<'blk, 'tcx>; diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index ca955975dfb30..796d5ad3f51be 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -137,10 +137,10 @@ fn tuplify_box_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { ty::mk_tup(tcx, vec!(ty::mk_uint(), ty::mk_nil_ptr(tcx), ptr, ptr, t)) } -fn allocate_cbox<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn allocate_cbox<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, store: ty::TraitStore, cdata_ty: Ty<'tcx>) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::allocate_cbox"); let tcx = bcx.tcx(); @@ -157,20 +157,20 @@ fn allocate_cbox<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub struct ClosureResult<'blk, 'tcx: 'blk> { +pub struct ClosureResult<'fcx, 'blk: 'fcx, 'tcx: 'blk> { llbox: ValueRef, // llvalue of ptr to closure cdata_ty: Ty<'tcx>, // type of the closure data - bcx: Block<'blk, 'tcx> // final bcx + bcx: Block<'fcx, 'blk, 'tcx> // final bcx } // Given a block context and a list of tydescs and values to bind // construct a closure out of them. If copying is true, it is a // heap allocated closure that copies the upvars into environment. // Otherwise, it is stack allocated and copies pointers to the upvars. -pub fn store_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn store_environment<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, bound_values: Vec> , store: ty::TraitStore) - -> ClosureResult<'blk, 'tcx> { + -> ClosureResult<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::store_environment"); let ccx = bcx.ccx(); let tcx = ccx.tcx(); @@ -225,11 +225,11 @@ pub fn store_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Given a context and a list of upvars, build a closure. This just // collects the upvars and packages them up for store_environment. -fn build_closure<'blk, 'tcx>(bcx0: Block<'blk, 'tcx>, +fn build_closure<'fcx, 'blk, 'tcx>(bcx0: Block<'fcx, 'blk, 'tcx>, freevar_mode: ast::CaptureClause, freevars: &Vec, store: ty::TraitStore) - -> ClosureResult<'blk, 'tcx> { + -> ClosureResult<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::build_closure"); // If we need to, package up the iterator body to call @@ -248,11 +248,11 @@ fn build_closure<'blk, 'tcx>(bcx0: Block<'blk, 'tcx>, // Given an enclosing block context, a new function context, a closure type, // and a list of upvars, generate code to load and populate the environment // with the upvars and type descriptors. -fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn load_environment<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, cdata_ty: Ty<'tcx>, freevars: &[ty::Freevar], store: ty::TraitStore) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::load_environment"); // Load a pointer to the closure data, skipping over the box header: @@ -296,12 +296,12 @@ fn load_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx } -fn load_unboxed_closure_environment<'blk, 'tcx>( - bcx: Block<'blk, 'tcx>, +fn load_unboxed_closure_environment<'fcx, 'blk, 'tcx>( + bcx: Block<'fcx, 'blk, 'tcx>, arg_scope_id: ScopeId, freevar_mode: ast::CaptureClause, freevars: &[ty::Freevar]) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::load_environment"); // Special case for small by-value selfs. @@ -367,8 +367,8 @@ impl<'a, 'tcx> ClosureEnv<'a, 'tcx> { } } - pub fn load<'blk>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId) - -> Block<'blk, 'tcx> { + pub fn load<'fcx, 'blk>(self, bcx: Block<'fcx, 'blk, 'tcx>, arg_scope: ScopeId) + -> Block<'fcx, 'blk, 'tcx> { // Don't bother to create the block if there's nothing to load if self.freevars.is_empty() { return bcx; @@ -386,13 +386,13 @@ impl<'a, 'tcx> ClosureEnv<'a, 'tcx> { } } -pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_expr_fn<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, store: ty::TraitStore, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * * Translates the body of a closure expression. @@ -453,7 +453,7 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Returns the LLVM function declaration for an unboxed closure, creating it /// if necessary. If the ID does not correspond to a closure ID, returns None. -pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn get_or_create_declaration_if_unboxed_closure<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, closure_id: ast::DefId, substs: &Substs<'tcx>) -> Option { @@ -505,13 +505,13 @@ pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, Some(llfn) } -pub fn trans_unboxed_closure<'blk, 'tcx>( - mut bcx: Block<'blk, 'tcx>, +pub fn trans_unboxed_closure<'fcx, 'blk, 'tcx>( + mut bcx: Block<'fcx, 'blk, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, id: ast::NodeId, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("closure::trans_unboxed_closure"); debug!("trans_unboxed_closure()"); @@ -632,8 +632,8 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let _icx = push_ctxt("closure::get_wrapper_for_bare_fn"); - let arena = TypedArena::new(); let empty_param_substs = Substs::trans_empty(); + let arena = TypedArena::new(); let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, true, f.sig.output, &empty_param_substs, None, &arena); let bcx = init_function(&fcx, true, f.sig.output); @@ -672,11 +672,11 @@ pub fn get_wrapper_for_bare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } -pub fn make_closure_from_bare_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn make_closure_from_bare_fn<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, closure_ty: Ty<'tcx>, def: def::Def, fn_ptr: ValueRef) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let scratch = rvalue_scratch_datum(bcx, closure_ty, "__adjust"); let wrapper = get_wrapper_for_bare_fn(bcx.ccx(), closure_ty, def, fn_ptr, true); fill_fn_pair(bcx, scratch.val, wrapper, C_null(Type::i8p(bcx.ccx()))); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 235805a7c8308..b7cffe2dc945e 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -200,7 +200,7 @@ pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>; // Function context. Every LLVM function we create will have one of // these. -pub struct FunctionContext<'a, 'tcx: 'a> { +pub struct FunctionContext<'blk, 'tcx: 'blk> { // The ValueRef returned from a call to llvm::LLVMAddFunction; the // address of the first instruction in the sequence of // instructions for this function that will go in the .text @@ -251,26 +251,26 @@ pub struct FunctionContext<'a, 'tcx: 'a> { // If this function is being monomorphized, this contains the type // substitutions used. - pub param_substs: &'a Substs<'tcx>, + pub param_substs: &'blk Substs<'tcx>, // The source span and nesting context where this function comes from, for // error reporting and symbol generation. pub span: Option, // The arena that blocks are allocated from. - pub block_arena: &'a TypedArena>, + pub block_arena: &'blk TypedArena, // This function's enclosing crate context. - pub ccx: &'a CrateContext<'a, 'tcx>, + pub ccx: &'blk CrateContext<'blk, 'tcx>, // Used and maintained by the debuginfo module. pub debug_context: debuginfo::FunctionDebugContext, // Cleanup scopes. - pub scopes: RefCell>>, + pub scopes: RefCell>>, } -impl<'a, 'tcx> FunctionContext<'a, 'tcx> { +impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> { pub fn arg_pos(&self, arg: uint) -> uint { let arg = self.env_arg_pos() + arg; if self.llenv.is_some() { @@ -314,7 +314,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { self.llreturn.get().unwrap() } - pub fn get_ret_slot(&self, bcx: Block<'a, 'tcx>, + pub fn get_ret_slot<'fcx>(&'fcx self, bcx: Block<'fcx, 'blk, 'tcx>, output: ty::FnOutput<'tcx>, name: &str) -> ValueRef { if self.needs_ret_allocas { @@ -327,43 +327,43 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { } } - pub fn new_block(&'a self, + pub fn new_block<'fcx>(&'fcx self, is_lpad: bool, name: &str, opt_node_id: Option) - -> Block<'a, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { unsafe { let llbb = name.with_c_str(|buf| { llvm::LLVMAppendBasicBlockInContext(self.ccx.llcx(), self.llfn, buf) }); - BlockS::new(llbb, is_lpad, opt_node_id, self) + Block::new(llbb, is_lpad, opt_node_id, self) } } - pub fn new_id_block(&'a self, + pub fn new_id_block<'fcx>(&'fcx self, name: &str, node_id: ast::NodeId) - -> Block<'a, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { self.new_block(false, name, Some(node_id)) } - pub fn new_temp_block(&'a self, + pub fn new_temp_block<'fcx>(&'fcx self, name: &str) - -> Block<'a, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { self.new_block(false, name, None) } - pub fn join_blocks(&'a self, + pub fn join_blocks<'fcx>(&'fcx self, id: ast::NodeId, - in_cxs: &[Block<'a, 'tcx>]) - -> Block<'a, 'tcx> { + in_cxs: &[Block<'fcx, 'blk, 'tcx>]) + -> Block<'fcx, 'blk, 'tcx> { let out = self.new_id_block("join", id); let mut reachable = false; for bcx in in_cxs.iter() { - if !bcx.unreachable.get() { - build::Br(*bcx, out.llbb); + if !bcx.data.unreachable.get() { + build::Br(*bcx, out.data.llbb); reachable = true; } } @@ -379,7 +379,16 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { // code. Each basic block we generate is attached to a function, typically // with many basic blocks per function. All the basic blocks attached to a // function are organized as a directed graph. -pub struct BlockS<'blk, 'tcx: 'blk> { +pub struct Block<'fcx, 'blk: 'fcx, 'tcx: 'blk> { + // The function context for the function to which this block is + // attached. + pub fcx: &'fcx FunctionContext<'blk, 'tcx>, + + // The block payload (stored in an arena). + pub data: &'blk BlockS, +} + +pub struct BlockS { // The BasicBlockRef returned from a call to // llvm::LLVMAppendBasicBlock(llfn, name), which adds a basic // block to the function pointed to by llfn. We insert @@ -396,29 +405,9 @@ pub struct BlockS<'blk, 'tcx: 'blk> { // debugging purposes only. pub opt_node_id: Option, - // The function context for the function to which this block is - // attached. - pub fcx: &'blk FunctionContext<'blk, 'tcx>, } -pub type Block<'blk, 'tcx> = &'blk BlockS<'blk, 'tcx>; - -impl<'blk, 'tcx> BlockS<'blk, 'tcx> { - pub fn new(llbb: BasicBlockRef, - is_lpad: bool, - opt_node_id: Option, - fcx: &'blk FunctionContext<'blk, 'tcx>) - -> Block<'blk, 'tcx> { - fcx.block_arena.alloc(BlockS { - llbb: llbb, - terminated: Cell::new(false), - unreachable: Cell::new(false), - is_lpad: is_lpad, - opt_node_id: opt_node_id, - fcx: fcx - }) - } - +impl<'fcx, 'blk, 'tcx> Block<'fcx, 'blk, 'tcx> { pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> { self.fcx.ccx } @@ -461,18 +450,41 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { t.repr(self.tcx()) } + pub fn to_str(&self) -> String { + self.data.to_str() + } + + pub fn new(llbb: BasicBlockRef, + is_lpad: bool, + opt_node_id: Option, + fcx: &'fcx FunctionContext<'blk, 'tcx>) -> Block<'fcx, 'blk, 'tcx> { + let data = fcx.block_arena.alloc(BlockS { + llbb: llbb, + terminated: Cell::new(false), + unreachable: Cell::new(false), + is_lpad: is_lpad, + opt_node_id: opt_node_id, + }); + Block { + fcx: fcx, + data: data, + } + } +} + +impl BlockS { pub fn to_str(&self) -> String { format!("[block {:p}]", self) } } -impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { +impl<'fcx, 'blk, 'tcx> mc::Typer<'tcx> for Block<'fcx, 'blk, 'tcx> { fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.tcx() } fn node_ty(&self, id: ast::NodeId) -> mc::McResult> { - Ok(node_id_type(self, id)) + Ok(node_id_type(*self, id)) } fn node_method_ty(&self, method_call: typeck::MethodCall) -> Option> { @@ -480,7 +492,7 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { .method_map .borrow() .get(&method_call) - .map(|method| monomorphize_type(self, method.ty)) + .map(|method| monomorphize_type(*self, method.ty)) } fn adjustments<'a>(&'a self) -> &'a RefCell>> { @@ -510,13 +522,13 @@ impl<'blk, 'tcx> mc::Typer<'tcx> for BlockS<'blk, 'tcx> { } } -pub struct Result<'blk, 'tcx: 'blk> { - pub bcx: Block<'blk, 'tcx>, +pub struct Result<'fcx, 'blk: 'fcx, 'tcx: 'blk> { + pub bcx: Block<'fcx, 'blk, 'tcx>, pub val: ValueRef } -impl<'b, 'tcx> Result<'b, 'tcx> { - pub fn new(bcx: Block<'b, 'tcx>, val: ValueRef) -> Result<'b, 'tcx> { +impl<'fcx, 'blk, 'tcx> Result<'fcx, 'blk, 'tcx> { + pub fn new(bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef) -> Result<'fcx, 'blk, 'tcx> { Result { bcx: bcx, val: val, @@ -750,21 +762,21 @@ pub fn is_null(val: ValueRef) -> bool { } } -pub fn monomorphize_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { +pub fn monomorphize_type<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { t.subst(bcx.tcx(), bcx.fcx.param_substs) } -pub fn node_id_type<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> { +pub fn node_id_type<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, id: ast::NodeId) -> Ty<'tcx> { let tcx = bcx.tcx(); let t = ty::node_id_to_type(tcx, id); monomorphize_type(bcx, t) } -pub fn expr_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { +pub fn expr_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { node_id_type(bcx, ex.id) } -pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { +pub fn expr_ty_adjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex)) } @@ -885,9 +897,9 @@ pub enum ExprOrMethodCall { MethodCall(typeck::MethodCall) } -pub fn node_id_substs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - node: ExprOrMethodCall) - -> subst::Substs<'tcx> +pub fn node_id_substs<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + node: ExprOrMethodCall) + -> subst::Substs<'tcx> { let tcx = bcx.tcx(); diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 10a73033b64af..9019db2dfefd6 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -40,9 +40,9 @@ use syntax::parse::token::InternedString; use syntax::parse::token; use syntax::visit::Visitor; -pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, - s: &ast::Stmt) - -> Block<'blk, 'tcx> { +pub fn trans_stmt<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, + s: &ast::Stmt) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_stmt"); let fcx = cx.fcx; debug!("trans_stmt({})", s.repr(cx.tcx())); @@ -83,8 +83,8 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, return bcx; } -pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) - -> Block<'blk, 'tcx> { +pub fn trans_stmt_semi<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, e: &ast::Expr) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_stmt_semi"); let ty = expr_ty(cx, e); if ty::type_needs_drop(cx.tcx(), ty) { @@ -94,10 +94,10 @@ pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) } } -pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - b: &ast::Block, - mut dest: expr::Dest) - -> Block<'blk, 'tcx> { +pub fn trans_block<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + b: &ast::Block, + mut dest: expr::Dest) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_block"); let fcx = bcx.fcx; let mut bcx = bcx; @@ -122,7 +122,7 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx = expr::trans_into(bcx, &**e, dest); } None => { - assert!(dest == expr::Ignore || bcx.unreachable.get()); + assert!(dest == expr::Ignore || bcx.data.unreachable.get()); } } @@ -131,13 +131,13 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return bcx; } -pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - if_id: ast::NodeId, - cond: &ast::Expr, - thn: &ast::Block, - els: Option<&ast::Expr>, - dest: expr::Dest) - -> Block<'blk, 'tcx> { +pub fn trans_if<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + if_id: ast::NodeId, + cond: &ast::Expr, + thn: &ast::Block, + els: Option<&ast::Expr>, + dest: expr::Dest) + -> Block<'fcx, 'blk, 'tcx> { debug!("trans_if(bcx={}, if_id={}, cond={}, thn={}, dest={})", bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id, dest.to_string(bcx.ccx())); @@ -190,13 +190,13 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let else_bcx_out = expr::trans_into(else_bcx_in, &*elexpr, dest); next_bcx = bcx.fcx.join_blocks(if_id, &[then_bcx_out, else_bcx_out]); - CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb); + CondBr(bcx, cond_val, then_bcx_in.data.llbb, else_bcx_in.data.llbb); } None => { next_bcx = bcx.fcx.new_id_block("next-block", if_id); - Br(then_bcx_out, next_bcx.llbb); - CondBr(bcx, cond_val, then_bcx_in.llbb, next_bcx.llbb); + Br(then_bcx_out, next_bcx.data.llbb); + CondBr(bcx, cond_val, then_bcx_in.data.llbb, next_bcx.data.llbb); } } @@ -207,11 +207,11 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, next_bcx } -pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - loop_id: ast::NodeId, - cond: &ast::Expr, - body: &ast::Block) - -> Block<'blk, 'tcx> { +pub fn trans_while<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + loop_id: ast::NodeId, + cond: &ast::Expr, + body: &ast::Block) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_while"); let fcx = bcx.fcx; @@ -230,9 +230,9 @@ pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let cond_bcx_in = fcx.new_id_block("while_cond", cond.id); let body_bcx_in = fcx.new_id_block("while_body", body.id); - fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, cond_bcx_in]); + fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in.data, cond_bcx_in.data]); - Br(bcx, cond_bcx_in.llbb); + Br(bcx, cond_bcx_in.data.llbb); // compile the block where we will handle loop cleanups let cleanup_llbb = fcx.normal_exit_block(loop_id, cleanup::EXIT_BREAK); @@ -240,23 +240,23 @@ pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // compile the condition let Result {bcx: cond_bcx_out, val: cond_val} = expr::trans(cond_bcx_in, cond).to_llbool(); - CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, cleanup_llbb); + CondBr(cond_bcx_out, cond_val, body_bcx_in.data.llbb, cleanup_llbb); // loop body: let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore); - Br(body_bcx_out, cond_bcx_in.llbb); + Br(body_bcx_out, cond_bcx_in.data.llbb); fcx.pop_loop_cleanup_scope(loop_id); return next_bcx_in; } /// Translates a `for` loop. -pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, - loop_info: NodeInfo, - pat: &ast::Pat, - head: &ast::Expr, - body: &ast::Block) - -> Block<'blk, 'tcx> { +pub fn trans_for<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, + loop_info: NodeInfo, + pat: &ast::Pat, + head: &ast::Expr, + body: &ast::Block) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_for"); // bcx @@ -284,8 +284,8 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let loopback_bcx_in = bcx.fcx.new_id_block("for_loopback", head.id); let body_bcx_in = bcx.fcx.new_id_block("for_body", body.id); bcx.fcx.push_loop_cleanup_scope(loop_info.id, - [next_bcx_in, loopback_bcx_in]); - Br(bcx, loopback_bcx_in.llbb); + [next_bcx_in.data, loopback_bcx_in.data]); + Br(bcx, loopback_bcx_in.data.llbb); let cleanup_llbb = bcx.fcx.normal_exit_block(loop_info.id, cleanup::EXIT_BREAK); @@ -338,7 +338,7 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, None); let i1_type = Type::i1(loopback_bcx_out.ccx()); let llcondition = Trunc(loopback_bcx_out, lldiscriminant, i1_type); - CondBr(loopback_bcx_out, llcondition, body_bcx_in.llbb, cleanup_llbb); + CondBr(loopback_bcx_out, llcondition, body_bcx_in.data.llbb, cleanup_llbb); // Now we're in the body. Unpack the `Option` value into the programmer- // supplied pattern. @@ -366,17 +366,17 @@ pub fn trans_for<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, body_bcx_out.fcx .pop_and_trans_custom_cleanup_scope(body_bcx_out, option_cleanup_scope); - Br(body_bcx_out, loopback_bcx_in.llbb); + Br(body_bcx_out, loopback_bcx_in.data.llbb); // Codegen cleanups and leave. next_bcx_in.fcx.pop_loop_cleanup_scope(loop_info.id); next_bcx_in } -pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - loop_id: ast::NodeId, - body: &ast::Block) - -> Block<'blk, 'tcx> { +pub fn trans_loop<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + loop_id: ast::NodeId, + body: &ast::Block) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_loop"); let fcx = bcx.fcx; @@ -394,26 +394,26 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let next_bcx_in = bcx.fcx.new_id_block("loop_exit", loop_id); let body_bcx_in = bcx.fcx.new_id_block("loop_body", body.id); - fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in, body_bcx_in]); + fcx.push_loop_cleanup_scope(loop_id, [next_bcx_in.data, body_bcx_in.data]); - Br(bcx, body_bcx_in.llbb); + Br(bcx, body_bcx_in.data.llbb); let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore); - Br(body_bcx_out, body_bcx_in.llbb); + Br(body_bcx_out, body_bcx_in.data.llbb); fcx.pop_loop_cleanup_scope(loop_id); return next_bcx_in; } -pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr_id: ast::NodeId, - opt_label: Option, - exit: uint) - -> Block<'blk, 'tcx> { +pub fn trans_break_cont<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + expr_id: ast::NodeId, + opt_label: Option, + exit: uint) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_break_cont"); let fcx = bcx.fcx; - if bcx.unreachable.get() { + if bcx.data.unreachable.get() { return bcx; } @@ -438,23 +438,23 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return bcx; } -pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr_id: ast::NodeId, - label_opt: Option) - -> Block<'blk, 'tcx> { +pub fn trans_break<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + expr_id: ast::NodeId, + label_opt: Option) + -> Block<'fcx, 'blk, 'tcx> { return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_BREAK); } -pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - expr_id: ast::NodeId, - label_opt: Option) - -> Block<'blk, 'tcx> { +pub fn trans_cont<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + expr_id: ast::NodeId, + label_opt: Option) + -> Block<'fcx, 'blk, 'tcx> { return trans_break_cont(bcx, expr_id, label_opt, cleanup::EXIT_LOOP); } -pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - e: Option<&ast::Expr>) - -> Block<'blk, 'tcx> { +pub fn trans_ret<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + e: Option<&ast::Expr>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_ret"); let fcx = bcx.fcx; let mut bcx = bcx; @@ -483,10 +483,10 @@ pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return bcx; } -pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - sp: Span, - fail_str: InternedString) - -> Block<'blk, 'tcx> { +pub fn trans_fail<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + sp: Span, + fail_str: InternedString) + -> Block<'fcx, 'blk, 'tcx> { let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_value"); @@ -507,11 +507,11 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return bcx; } -pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - sp: Span, - index: ValueRef, - len: ValueRef) - -> Block<'blk, 'tcx> { +pub fn trans_fail_bounds_check<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + sp: Span, + index: ValueRef, + len: ValueRef) + -> Block<'fcx, 'blk, 'tcx> { let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_bounds_check"); diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 354a607220715..8e28bf7bc0519 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -50,8 +50,8 @@ pub struct Datum<'tcx, K> { pub kind: K, } -pub struct DatumBlock<'blk, 'tcx: 'blk, K> { - pub bcx: Block<'blk, 'tcx>, +pub struct DatumBlock<'fcx, 'blk: 'fcx, 'tcx: 'blk, K> { + pub bcx: Block<'fcx, 'blk, 'tcx>, pub datum: Datum<'tcx, K>, } @@ -99,23 +99,23 @@ pub fn immediate_rvalue<'tcx>(val: ValueRef, ty: Ty<'tcx>) -> Datum<'tcx, Rvalue return Datum::new(val, ty, Rvalue::new(ByValue)); } -pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn immediate_rvalue_bcx<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef, ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { + -> DatumBlock<'fcx, 'blk, 'tcx, Rvalue> { return DatumBlock::new(bcx, immediate_rvalue(val, ty)) } -pub fn lvalue_scratch_datum<'blk, 'tcx, A>(bcx: Block<'blk, 'tcx>, +pub fn lvalue_scratch_datum<'fcx, 'blk, 'tcx, A>(bcx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>, name: &str, zero: bool, scope: cleanup::ScopeId, arg: A, - populate: |A, Block<'blk, 'tcx>, ValueRef| - -> Block<'blk, 'tcx>) - -> DatumBlock<'blk, 'tcx, Lvalue> { + populate: |A, Block<'fcx, 'blk, 'tcx>, ValueRef| + -> Block<'fcx, 'blk, 'tcx>) + -> DatumBlock<'fcx, 'blk, 'tcx, Lvalue> { /*! * Allocates temporary space on the stack using alloca() and * returns a by-ref Datum pointing to it. The memory will be @@ -140,7 +140,7 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue)) } -pub fn rvalue_scratch_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn rvalue_scratch_datum<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> Datum<'tcx, Rvalue> { @@ -174,8 +174,8 @@ pub fn appropriate_rvalue_mode<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -fn add_rvalue_clean<'a, 'tcx>(mode: RvalueMode, - fcx: &FunctionContext<'a, 'tcx>, +fn add_rvalue_clean<'fcx, 'blk, 'tcx>(mode: RvalueMode, + fcx: &FunctionContext<'blk, 'tcx>, scope: cleanup::ScopeId, val: ValueRef, ty: Ty<'tcx>) { @@ -194,11 +194,11 @@ pub trait KindOps { * Take appropriate action after the value in `datum` has been * stored to a new location. */ - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn post_store<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef, ty: Ty<'tcx>) - -> Block<'blk, 'tcx>; + -> Block<'fcx, 'blk, 'tcx>; /** * True if this mode is a reference mode, meaning that the datum's @@ -214,11 +214,11 @@ pub trait KindOps { } impl KindOps for Rvalue { - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn post_store<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, _val: ValueRef, _ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { // No cleanup is scheduled for an rvalue, so we don't have // to do anything after a move to cancel or duplicate it. bcx @@ -234,11 +234,11 @@ impl KindOps for Rvalue { } impl KindOps for Lvalue { - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn post_store<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef, ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * If an lvalue is moved, we must zero out the memory in which * it resides so as to cancel cleanup. If an @T lvalue is @@ -264,11 +264,11 @@ impl KindOps for Lvalue { } impl KindOps for Expr { - fn post_store<'blk, 'tcx>(&self, - bcx: Block<'blk, 'tcx>, + fn post_store<'fcx, 'blk, 'tcx>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, val: ValueRef, ty: Ty<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { match *self { LvalueExpr => Lvalue.post_store(bcx, val, ty), RvalueExpr(ref r) => r.post_store(bcx, val, ty), @@ -288,8 +288,8 @@ impl KindOps for Expr { } impl<'tcx> Datum<'tcx, Rvalue> { - pub fn add_clean<'a>(self, - fcx: &FunctionContext<'a, 'tcx>, + pub fn add_clean<'blk>(self, + fcx: &FunctionContext<'blk, 'tcx>, scope: cleanup::ScopeId) -> ValueRef { /*! @@ -303,11 +303,11 @@ impl<'tcx> Datum<'tcx, Rvalue> { self.val } - pub fn to_lvalue_datum_in_scope<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn to_lvalue_datum_in_scope<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, name: &str, scope: cleanup::ScopeId) - -> DatumBlock<'blk, 'tcx, Lvalue> { + -> DatumBlock<'fcx, 'blk, 'tcx, Lvalue> { /*! * Returns an lvalue datum (that is, a by ref datum with * cleanup scheduled). If `self` is not already an lvalue, @@ -329,8 +329,8 @@ impl<'tcx> Datum<'tcx, Rvalue> { } } - pub fn to_ref_datum<'blk>(self, bcx: Block<'blk, 'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { + pub fn to_ref_datum<'fcx, 'blk>(self, bcx: Block<'fcx, 'blk, 'tcx>) + -> DatumBlock<'fcx, 'blk, 'tcx, Rvalue> { let mut bcx = bcx; match self.kind.mode { ByRef => DatumBlock::new(bcx, self), @@ -342,8 +342,8 @@ impl<'tcx> Datum<'tcx, Rvalue> { } } - pub fn to_appropriate_datum<'blk>(self, bcx: Block<'blk, 'tcx>) - -> DatumBlock<'blk, 'tcx, Rvalue> { + pub fn to_appropriate_datum<'fcx, 'blk>(self, bcx: Block<'fcx, 'blk, 'tcx>) + -> DatumBlock<'fcx, 'blk, 'tcx, Rvalue> { match self.appropriate_rvalue_mode(bcx.ccx()) { ByRef => { self.to_ref_datum(bcx) @@ -402,11 +402,11 @@ impl<'tcx> Datum<'tcx, Expr> { |r| r) } - pub fn store_to_dest<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn store_to_dest<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, dest: expr::Dest, expr_id: ast::NodeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { match dest { expr::Ignore => { self.add_clean_if_rvalue(bcx, expr_id); @@ -418,8 +418,8 @@ impl<'tcx> Datum<'tcx, Expr> { } } - pub fn add_clean_if_rvalue<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn add_clean_if_rvalue<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, expr_id: ast::NodeId) { /*! * Arranges cleanup for `self` if it is an rvalue. Use when @@ -434,11 +434,11 @@ impl<'tcx> Datum<'tcx, Expr> { }) } - pub fn clean<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn clean<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, name: &'static str, expr_id: ast::NodeId) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Ensures that `self` will get cleaned up, if it is not an lvalue * already. @@ -447,11 +447,11 @@ impl<'tcx> Datum<'tcx, Expr> { self.to_lvalue_datum(bcx, name, expr_id).bcx } - pub fn to_lvalue_datum<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn to_lvalue_datum<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, name: &str, expr_id: ast::NodeId) - -> DatumBlock<'blk, 'tcx, Lvalue> { + -> DatumBlock<'fcx, 'blk, 'tcx, Lvalue> { debug!("to_lvalue_datum self: {}", self.to_string(bcx.ccx())); assert!(ty::lltype_is_sized(bcx.tcx(), self.ty), @@ -464,10 +464,10 @@ impl<'tcx> Datum<'tcx, Expr> { }) } - pub fn to_rvalue_datum<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn to_rvalue_datum<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, name: &'static str) - -> DatumBlock<'blk, 'tcx, Rvalue> { + -> DatumBlock<'fcx, 'blk, 'tcx, Rvalue> { /*! * Ensures that we have an rvalue datum (that is, a datum with * no cleanup scheduled). @@ -515,7 +515,7 @@ impl<'tcx> Datum<'tcx, Lvalue> { // datum may also be unsized _without the size information_. It is the // callers responsibility to package the result in some way to make a valid // datum in that case (e.g., by making a fat pointer or opened pair). - pub fn get_element<'blk>(&self, bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>, + pub fn get_element<'fcx, 'blk>(&self, bcx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>, gep: |ValueRef| -> ValueRef) -> Datum<'tcx, Lvalue> { let val = match self.ty.sty { @@ -555,10 +555,10 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { Datum { val: val, ty: ty, kind: kind.to_expr_kind() } } - pub fn store_to<'blk>(self, - bcx: Block<'blk, 'tcx>, + pub fn store_to<'fcx, 'blk>(self, + bcx: Block<'fcx, 'blk, 'tcx>, dst: ValueRef) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Moves or copies this value into a new home, as appropriate * depending on the type of the datum. This method consumes @@ -572,10 +572,10 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { self.kind.post_store(bcx, self.val, self.ty) } - fn shallow_copy_raw<'blk>(&self, - bcx: Block<'blk, 'tcx>, + fn shallow_copy_raw<'fcx, 'blk>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, dst: ValueRef) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Helper function that performs a shallow copy of this value * into `dst`, which should be a pointer to a memory location @@ -604,10 +604,10 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { return bcx; } - pub fn shallow_copy<'blk>(&self, - bcx: Block<'blk, 'tcx>, + pub fn shallow_copy<'fcx, 'blk>(&self, + bcx: Block<'fcx, 'blk, 'tcx>, dst: ValueRef) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Copies the value into a new location. This function always * preserves the existing datum as a valid value. Therefore, @@ -634,7 +634,7 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { appropriate_rvalue_mode(ccx, self.ty) } - pub fn to_llscalarish<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { + pub fn to_llscalarish<'fcx, 'blk>(self, bcx: Block<'fcx, 'blk, 'tcx>) -> ValueRef { /*! * Converts `self` into a by-value `ValueRef`. Consumes this * datum (i.e., absolves you of responsibility to cleanup the @@ -653,34 +653,34 @@ impl<'tcx, K: KindOps + fmt::Show> Datum<'tcx, K> { } } - pub fn to_llbool<'blk>(self, bcx: Block<'blk, 'tcx>) -> ValueRef { + pub fn to_llbool<'fcx, 'blk>(self, bcx: Block<'fcx, 'blk, 'tcx>) -> ValueRef { assert!(ty::type_is_bool(self.ty)) self.to_llscalarish(bcx) } } -impl<'blk, 'tcx, K> DatumBlock<'blk, 'tcx, K> { - pub fn new(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, K>) - -> DatumBlock<'blk, 'tcx, K> { +impl<'fcx, 'blk, 'tcx, K> DatumBlock<'fcx, 'blk, 'tcx, K> { + pub fn new(bcx: Block<'fcx, 'blk, 'tcx>, datum: Datum<'tcx, K>) + -> DatumBlock<'fcx, 'blk, 'tcx, K> { DatumBlock { bcx: bcx, datum: datum } } } -impl<'blk, 'tcx, K: KindOps + fmt::Show> DatumBlock<'blk, 'tcx, K> { - pub fn to_expr_datumblock(self) -> DatumBlock<'blk, 'tcx, Expr> { +impl<'fcx, 'blk, 'tcx, K: KindOps + fmt::Show> DatumBlock<'fcx, 'blk, 'tcx, K> { + pub fn to_expr_datumblock(self) -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { DatumBlock::new(self.bcx, self.datum.to_expr_datum()) } } -impl<'blk, 'tcx> DatumBlock<'blk, 'tcx, Expr> { +impl<'fcx, 'blk, 'tcx> DatumBlock<'fcx, 'blk, 'tcx, Expr> { pub fn store_to_dest(self, dest: expr::Dest, - expr_id: ast::NodeId) -> Block<'blk, 'tcx> { + expr_id: ast::NodeId) -> Block<'fcx, 'blk, 'tcx> { let DatumBlock { bcx, datum } = self; datum.store_to_dest(bcx, dest, expr_id) } - pub fn to_llbool(self) -> Result<'blk, 'tcx> { + pub fn to_llbool(self) -> Result<'fcx, 'blk, 'tcx> { let DatumBlock { datum, bcx } = self; Result::new(bcx, datum.to_llbool(bcx)) } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index a3472e194cf58..aeffc5fb0deba 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -881,7 +881,7 @@ pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) { /// Creates debug information for a variable captured in a closure. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn create_captured_var_metadata<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, node_id: ast::NodeId, env_data_type: Ty<'tcx>, env_pointer: ValueRef, @@ -968,7 +968,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// match-statement arm. /// /// Adds the created metadata nodes directly to the crate's IR. -pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn create_match_binding_metadata<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, variable_ident: ast::Ident, binding: BindingInfo<'tcx>) { if fn_should_be_ignored(bcx.fcx) { @@ -1586,7 +1586,7 @@ fn compile_unit_metadata(cx: &CrateContext) { } } -fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn declare_local<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, variable_ident: ast::Ident, variable_type: Ty<'tcx>, scope_metadata: DIScope, @@ -1653,7 +1653,7 @@ fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DIB(cx), var_alloca, var_metadata, - bcx.llbb); + bcx.data.llbb); llvm::LLVMSetInstDebugLocation(trans::build::B(bcx).llbuilder, instr); } diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 482b318e37202..9382b2f19d9b9 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -82,10 +82,10 @@ impl Dest { } } -pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_into<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * This function is equivalent to `trans(bcx, expr).store_to_dest(dest)` * but it may generate better optimized LLVM code. @@ -124,9 +124,9 @@ pub fn trans_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.fcx.pop_and_trans_ast_cleanup_scope(bcx, expr.id) } -pub fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { /*! * Translates an expression, returning a datum (and new block) * encapsulating the result. When possible, it is preferred to @@ -157,10 +157,10 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef { GEPi(bcx, fat_ptr, &[0u, abi::FAT_PTR_ADDR]) } -fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn apply_adjustments<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { /*! * Helper for trans that apply adjustments from `expr` to `datum`, * which should be the unadjusted translation of `expr`. @@ -235,11 +235,11 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); return DatumBlock::new(bcx, datum); - fn apply_autoref<'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>, - bcx: Block<'blk, 'tcx>, + fn apply_autoref<'fcx, 'blk, 'tcx>(autoref: &ty::AutoRef<'tcx>, + bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let mut datum = datum; @@ -272,10 +272,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, datum) } - fn ref_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn ref_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { debug!("ref_ptr(expr={}, datum={})", expr.repr(bcx.tcx()), datum.to_string(bcx.ccx())); @@ -298,7 +298,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // into a type to be destructed. If we want to end up with a Box pointer, // then mk_ty should make a Box pointer (T -> Box), if we want a // borrowed reference then it should be T -> &T. - fn unsized_info<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn unsized_info<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, kind: &ty::UnsizeKind<'tcx>, id: ast::NodeId, unadjusted_ty: Ty<'tcx>, @@ -331,11 +331,11 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } - fn unsize_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn unsize_expr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let tcx = bcx.tcx(); let datum_ty = datum.ty; let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span); @@ -367,10 +367,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, into_fat_ptr(bcx, expr, datum, dest_ty, base, info) } - fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn ref_fat_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let tcx = bcx.tcx(); let dest_ty = ty::close_type(tcx, datum.ty); let base = |bcx, val| Load(bcx, get_dataptr(bcx, val)); @@ -378,13 +378,13 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, into_fat_ptr(bcx, expr, datum, dest_ty, base, len) } - fn into_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn into_fat_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, dest_ty: Ty<'tcx>, - base: |Block<'blk, 'tcx>, ValueRef| -> ValueRef, - info: |Block<'blk, 'tcx>, ValueRef| -> ValueRef) - -> DatumBlock<'blk, 'tcx, Expr> { + base: |Block<'fcx, 'blk, 'tcx>, ValueRef| -> ValueRef, + info: |Block<'fcx, 'blk, 'tcx>, ValueRef| -> ValueRef) + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; // Arrange cleanup @@ -400,11 +400,11 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, scratch.to_expr_datum()) } - fn unsize_unique_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn unsize_unique_vec<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, len: uint) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let tcx = bcx.tcx(); @@ -428,11 +428,11 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, scratch.to_expr_datum()) } - fn unsize_unique_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn unsize_unique_expr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, k: &ty::UnsizeKind<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let tcx = bcx.tcx(); @@ -463,10 +463,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, scratch.to_expr_datum()) } - fn add_env<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn add_env<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { // This is not the most efficient thing possible; since closures // are two words it'd be better if this were compiled in // 'dest' mode, but I can't find a nice way to structure the @@ -480,10 +480,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_to_lvalue<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, name: &str) - -> DatumBlock<'blk, 'tcx, Lvalue> { + -> DatumBlock<'fcx, 'blk, 'tcx, Lvalue> { /*! * Translates an expression in "lvalue" mode -- meaning that it * returns a reference to the memory that the expr represents. @@ -500,9 +500,9 @@ pub fn trans_to_lvalue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return datum.to_lvalue_datum(bcx, name, expr.id); } -fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { /*! * A version of `trans` that ignores adjustments. You almost * certainly do not want to call this directly. @@ -556,17 +556,17 @@ fn trans_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } }; - fn nil<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + fn nil<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>) + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let llval = C_undef(type_of::type_of(bcx.ccx(), ty)); let datum = immediate_rvalue(llval, ty); DatumBlock::new(bcx, datum.to_expr_datum()) } } -fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_datum_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let fcx = bcx.fcx; let _icx = push_ctxt("trans_datum_unadjusted"); @@ -666,10 +666,10 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_field<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, base: &ast::Expr, get_idx: |&'blk ty::ctxt<'tcx>, &[ty::field<'tcx>]| -> uint) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let _icx = push_ctxt("trans_rec_field"); @@ -699,27 +699,27 @@ fn trans_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } /// Translates `base.field`. -fn trans_rec_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_rec_field<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, base: &ast::Expr, field: ast::Ident) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { trans_field(bcx, base, |tcx, field_tys| ty::field_idx_strict(tcx, field.name, field_tys)) } /// Translates `base.`. -fn trans_rec_tup_field<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_rec_tup_field<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, base: &ast::Expr, idx: uint) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { trans_field(bcx, base, |_, _| idx) } -fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_index<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, index_expr: &ast::Expr, base: &ast::Expr, idx: &ast::Expr, method_call: MethodCall) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { //! Translates `base[idx]`. let _icx = push_ctxt("trans_index"); @@ -825,10 +825,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, elt_datum) } -fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_def<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ref_expr: &ast::Expr, def: def::Def) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { //! Translates a reference to a path. let _icx = push_ctxt("trans_def_lvalue"); @@ -847,7 +847,7 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // pointer to that. let const_ty = expr_ty(bcx, ref_expr); - fn get_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, did: ast::DefId, + fn get_val<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, did: ast::DefId, const_ty: Ty<'tcx>) -> ValueRef { // For external constants, we don't inline. if did.krate == ast::LOCAL_CRATE { @@ -901,13 +901,13 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_rvalue_stmt_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let mut bcx = bcx; let _icx = push_ctxt("trans_rvalue_stmt"); - if bcx.unreachable.get() { + if bcx.data.unreachable.get() { return bcx; } @@ -988,10 +988,10 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_rvalue_dps_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_rvalue_dps_unadjusted"); let mut bcx = bcx; let tcx = bcx.tcx(); @@ -1140,11 +1140,11 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_def_dps_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ref_expr: &ast::Expr, def: def::Def, dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_def_dps_unadjusted"); let lldest = match dest { @@ -1188,10 +1188,10 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_def_fn_unadjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ref_expr: &ast::Expr, def: def::Def) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_def_datum_unadjusted"); let llfn = match def { @@ -1218,7 +1218,7 @@ fn trans_def_fn_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, Datum::new(llfn, fn_ty, RvalueExpr(Rvalue::new(ByValue)))) } -pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_local_var<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, def: def::Def) -> Datum<'tcx, Lvalue> { /*! @@ -1320,12 +1320,12 @@ pub fn with_field_tys<'tcx, R>(tcx: &ty::ctxt<'tcx>, } } -fn trans_struct<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_struct<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, fields: &[ast::Field], base: Option<&ast::Expr>, expr_span: codemap::Span, expr_id: ast::NodeId, - dest: Dest) -> Block<'blk, 'tcx> { + dest: Dest) -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_rec"); let ty = node_id_type(bcx, expr_id); @@ -1402,14 +1402,14 @@ pub struct StructBaseInfo<'a, 'tcx> { * - `optbase` contains information on the base struct (if any) from * which remaining fields are copied; see comments on `StructBaseInfo`. */ -pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +pub fn trans_adt<'a, 'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, ty: Ty<'tcx>, discr: ty::Disr, fields: &[(uint, &ast::Expr)], optbase: Option>, dest: Dest, source_location: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_adt"); let fcx = bcx.fcx; let repr = adt::represent_type(bcx.ccx(), ty); @@ -1508,10 +1508,10 @@ pub fn trans_adt<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } -fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_immediate_lit<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, lit: &ast::Lit) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { // must not be a string constant, that is a RvalueDpsExpr let _icx = push_ctxt("trans_immediate_lit"); let ty = expr_ty(bcx, expr); @@ -1519,11 +1519,11 @@ fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, immediate_rvalue_bcx(bcx, v, ty).to_expr_datumblock() } -fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_unary<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, op: ast::UnOp, sub_expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let ccx = bcx.ccx(); let mut bcx = bcx; let _icx = push_ctxt("trans_unary_datum"); @@ -1567,11 +1567,11 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_uniq_expr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, box_ty: Ty<'tcx>, contents: &ast::Expr, contents_ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_uniq_expr"); let fcx = bcx.fcx; assert!(ty::type_is_sized(bcx.tcx(), contents_ty)); @@ -1596,10 +1596,10 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() } -fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_addr_of<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, subexpr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_addr_of"); let mut bcx = bcx; let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of")); @@ -1629,7 +1629,7 @@ fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Important to get types for both lhs and rhs, because one might be _|_ // and the other not. -fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_eager_binop<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, binop_expr: &ast::Expr, binop_ty: Ty<'tcx>, op: ast::BinOp, @@ -1637,7 +1637,7 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, lhs: ValueRef, rhs_t: Ty<'tcx>, rhs: ValueRef) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_eager_binop"); let tcx = bcx.tcx(); @@ -1725,12 +1725,12 @@ enum lazy_binop_ty { lazy_or, } -fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_lazy_binop<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, binop_expr: &ast::Expr, op: lazy_binop_ty, a: &ast::Expr, b: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_lazy_binop"); let binop_ty = expr_ty(bcx, binop_expr); let fcx = bcx.fcx; @@ -1738,7 +1738,7 @@ fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let DatumBlock {bcx: past_lhs, datum: lhs} = trans(bcx, a); let lhs = lhs.to_llscalarish(past_lhs); - if past_lhs.unreachable.get() { + if past_lhs.data.unreachable.get() { return immediate_rvalue_bcx(past_lhs, lhs, binop_ty).to_expr_datumblock(); } @@ -1746,30 +1746,30 @@ fn trans_lazy_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let before_rhs = fcx.new_id_block("before_rhs", b.id); match op { - lazy_and => CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb), - lazy_or => CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb) + lazy_and => CondBr(past_lhs, lhs, before_rhs.data.llbb, join.data.llbb), + lazy_or => CondBr(past_lhs, lhs, join.data.llbb, before_rhs.data.llbb) } let DatumBlock {bcx: past_rhs, datum: rhs} = trans(before_rhs, b); let rhs = rhs.to_llscalarish(past_rhs); - if past_rhs.unreachable.get() { + if past_rhs.data.unreachable.get() { return immediate_rvalue_bcx(join, lhs, binop_ty).to_expr_datumblock(); } - Br(past_rhs, join.llbb); + Br(past_rhs, join.data.llbb); let phi = Phi(join, Type::i1(bcx.ccx()), &[lhs, rhs], - &[past_lhs.llbb, past_rhs.llbb]); + &[past_lhs.data.llbb, past_rhs.data.llbb]); return immediate_rvalue_bcx(join, phi, binop_ty).to_expr_datumblock(); } -fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_binary<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_binary"); let ccx = bcx.ccx(); @@ -1806,13 +1806,13 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_overloaded_op<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, method_call: MethodCall, lhs: Datum<'tcx, Expr>, rhs: Vec<(Datum<'tcx, Expr>, ast::NodeId)>, dest: Option) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let method_ty = (*bcx.tcx().method_map.borrow())[method_call].ty; callee::trans_call_inner(bcx, Some(expr_info(expr)), @@ -1827,12 +1827,12 @@ fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, dest) } -fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +fn trans_overloaded_call<'a, 'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, callee: &'a ast::Expr, args: &'a [P], dest: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let method_call = MethodCall::expr(expr.id); let method_type = (*bcx.tcx() .method_map @@ -1932,10 +1932,10 @@ fn cast_is_noop<'tcx>(t_in: Ty<'tcx>, t_out: Ty<'tcx>) -> bool { } } -fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_imm_cast<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, id: ast::NodeId) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let _icx = push_ctxt("trans_cast"); let mut bcx = bcx; let ccx = bcx.ccx(); @@ -2024,12 +2024,12 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return immediate_rvalue_bcx(bcx, newval, t_out).to_expr_datumblock(); } -fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_assign_op<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, op: ast::BinOp, dst: &ast::Expr, src: &ast::Expr) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_assign_op"); let mut bcx = bcx; @@ -2056,10 +2056,10 @@ fn trans_assign_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return result_datum.store_to(bcx, dst_datum.val); } -fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn auto_ref<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, datum: Datum<'tcx, Expr>, expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; // Ensure cleanup of `datum` if not already scheduled and obtain @@ -2080,11 +2080,11 @@ fn auto_ref<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock::new(bcx, Datum::new(llref, ptr_ty, RvalueExpr(Rvalue::new(ByValue)))) } -fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn deref_multiple<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, times: uint) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let mut bcx = bcx; let mut datum = datum; for i in range(0, times) { @@ -2094,11 +2094,11 @@ fn deref_multiple<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, DatumBlock { bcx: bcx, datum: datum } } -fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn deref_once<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, method_call: MethodCall) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { let ccx = bcx.ccx(); debug!("deref_once(expr={}, datum={}, method_call={})", @@ -2189,11 +2189,11 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return r; - fn deref_owned_pointer<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + fn deref_owned_pointer<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, datum: Datum<'tcx, Expr>, content_ty: Ty<'tcx>) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { /*! * We microoptimize derefs of owned pointers a bit here. * Basically, the idea is to make the deref of an rvalue diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 1f6aeacc86058..04c3759d69bc1 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -201,13 +201,13 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfn } -pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_native_call<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, callee_ty: Ty<'tcx>, llfn: ValueRef, llretptr: ValueRef, llargs_rust: &[ValueRef], passed_arg_tys: Vec>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Prepares a call to a native function. This requires adapting * from the Rust argument passing rules to the native rules. diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 4ed7983789696..cb7f90b1206f2 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -44,9 +44,9 @@ use libc::c_uint; use syntax::ast; use syntax::parse::token; -pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, - size: ValueRef, align: ValueRef) - -> Block<'blk, 'tcx> { +pub fn trans_exchange_free_dyn<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, v: ValueRef, + size: ValueRef, align: ValueRef) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("trans_exchange_free"); let ccx = cx.ccx(); callee::trans_lang_call(cx, @@ -55,14 +55,14 @@ pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, Some(expr::Ignore)).bcx } -pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, - size: u64, align: u32) -> Block<'blk, 'tcx> { +pub fn trans_exchange_free<'fcx, 'blk, 'tcx>(cx: Block<'fcx, 'blk, 'tcx>, v: ValueRef, + size: u64, align: u32) -> Block<'fcx, 'blk, 'tcx> { trans_exchange_free_dyn(cx, v, C_uint(cx.ccx(), size), C_uint(cx.ccx(), align)) } -pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef, - content_ty: Ty<'tcx>) -> Block<'blk, 'tcx> { +pub fn trans_exchange_free_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ptr: ValueRef, + content_ty: Ty<'tcx>) -> Block<'fcx, 'blk, 'tcx> { assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty)); let sizing_type = sizing_type_of(bcx.ccx(), content_ty); let content_size = llsize_of_alloc(bcx.ccx(), sizing_type); @@ -102,11 +102,11 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } } -pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn drop_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, source_location: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { // NB: v is an *alias* of type t here, not a direct value. debug!("drop_ty(t={})", t.repr(bcx.tcx())); let _icx = push_ctxt("drop_ty"); @@ -130,11 +130,11 @@ pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx } -pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn drop_ty_immediate<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, v: ValueRef, t: Ty<'tcx>, source_location: Option) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("drop_ty_immediate"); let vp = alloca(bcx, type_of(bcx.ccx(), t), ""); Store(bcx, v, vp); @@ -185,13 +185,13 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val glue } -fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +fn trans_struct_drop_flag<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, dtor_did: ast::DefId, class_did: ast::DefId, substs: &subst::Substs<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let repr = adt::represent_type(bcx.ccx(), t); let struct_data = if ty::type_is_sized(bcx.tcx(), t) { v0 @@ -205,13 +205,13 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }) } -fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_struct_drop<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, dtor_did: ast::DefId, class_did: ast::DefId, substs: &subst::Substs<'tcx>) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let repr = adt::represent_type(bcx.ccx(), t); // Find and call the actual destructor @@ -298,7 +298,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }) } -fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) +fn size_and_align_of_dst<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) -> (ValueRef, ValueRef) { debug!("calculate size of DST: {}; with lost info: {}", bcx.ty_to_string(t), bcx.val_to_string(info)); @@ -354,8 +354,8 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: } } -fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) - -> Block<'blk, 'tcx> { +fn make_drop_glue<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>) + -> Block<'fcx, 'blk, 'tcx> { // NB: v0 is an *alias* of type t here, not a direct value. let _icx = push_ctxt("make_drop_glue"); match t.sty { @@ -532,8 +532,8 @@ fn declare_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, fn make_generic_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, llfn: ValueRef, - helper: for<'blk> |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>| - -> Block<'blk, 'tcx>, + helper: for<'fcx, 'blk> |Block<'fcx, 'blk, 'tcx>, ValueRef, Ty<'tcx>| + -> Block<'fcx, 'blk, 'tcx>, name: &str) -> ValueRef { let _icx = push_ctxt("make_generic_glue"); diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 6bdb35f8d6074..7dd55ef9b5753 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -135,7 +135,7 @@ pub fn check_intrinsics(ccx: &CrateContext) { ccx.sess().abort_if_errors(); } -pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, +pub fn trans_intrinsic_call<'a, 'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, node: ast::NodeId, callee_ty: Ty<'tcx>, cleanup_scope: cleanup::CustomScopeIndex, @@ -143,7 +143,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, dest: expr::Dest, substs: subst::Substs<'tcx>, call_info: NodeInfo) - -> Result<'blk, 'tcx> { + -> Result<'fcx, 'blk, 'tcx> { let fcx = bcx.fcx; let ccx = fcx.ccx; @@ -557,7 +557,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, Result::new(bcx, llresult) } -fn copy_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn copy_intrinsic<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, allow_overlap: bool, volatile: bool, tp_ty: Ty<'tcx>, dst: ValueRef, src: ValueRef, count: ValueRef) -> ValueRef { let ccx = bcx.ccx(); @@ -587,7 +587,7 @@ fn copy_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, C_bool(ccx, volatile)], None) } -fn memset_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, volatile: bool, tp_ty: Ty<'tcx>, +fn memset_intrinsic<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, volatile: bool, tp_ty: Ty<'tcx>, dst: ValueRef, val: ValueRef, count: ValueRef) -> ValueRef { let ccx = bcx.ccx(); let lltp_ty = type_of::type_of(ccx, tp_ty); @@ -612,7 +612,7 @@ fn count_zeros_intrinsic(bcx: Block, name: &'static str, val: ValueRef) -> Value Call(bcx, llfn, &[val, y], None) } -fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, name: &'static str, +fn with_overflow_intrinsic<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, name: &'static str, t: Ty<'tcx>, a: ValueRef, b: ValueRef) -> ValueRef { let llfn = bcx.ccx().get_intrinsic(&name); diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 0ff7f3ee71cc6..74271176e9698 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -106,11 +106,11 @@ pub fn trans_impl(ccx: &CrateContext, } } -pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_method_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, method_call: MethodCall, self_expr: Option<&ast::Expr>, arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("meth::trans_method_callee"); let (origin, method_ty) = @@ -323,12 +323,12 @@ fn method_with_name(ccx: &CrateContext, impl_id: ast::DefId, name: ast::Name) meth_did.def_id() } -fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_monomorphized_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, method_call: MethodCall, trait_id: ast::DefId, n_method: uint, vtable: traits::Vtable<'tcx, ()>) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("meth::trans_monomorphized_callee"); match vtable { traits::VtableImpl(vtable_impl) => { @@ -377,7 +377,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn combine_impl_and_methods_tps<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, node: ExprOrMethodCall, rcvr_substs: subst::Substs<'tcx>) -> subst::Substs<'tcx> @@ -422,12 +422,12 @@ fn combine_impl_and_methods_tps<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn trans_trait_callee<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, method_ty: Ty<'tcx>, n_method: uint, self_expr: &ast::Expr, arg_cleanup_scope: cleanup::ScopeId) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { /*! * Create a method callee where the method is coming from a trait * object (e.g., Box type). In this case, we must pull the fn @@ -466,11 +466,11 @@ fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, trans_trait_callee_from_llval(bcx, method_ty, n_method, llval) } -pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_trait_callee_from_llval<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, callee_ty: Ty<'tcx>, n_method: uint, llpair: ValueRef) - -> Callee<'blk, 'tcx> { + -> Callee<'fcx, 'blk, 'tcx> { /*! * Same as `trans_trait_callee()` above, except that it is given * a by-ref pointer to the object pair. @@ -525,7 +525,7 @@ pub fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// `trait_ref` would map `T:Trait`, but `box_ty` would be /// `Foo`. This `box_ty` is primarily used to encode the destructor. /// This will hopefully change now that DST is underway. -pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn get_vtable<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, box_ty: Ty<'tcx>, trait_ref: Rc>) -> ValueRef @@ -674,7 +674,7 @@ pub fn make_vtable>(ccx: &CrateContext, } } -fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +fn emit_vtable_methods<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, impl_id: ast::DefId, substs: subst::Substs<'tcx>) -> Vec { @@ -731,12 +731,12 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }).collect() } -pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_trait_cast<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, datum: Datum<'tcx, Expr>, id: ast::NodeId, trait_ref: Rc>, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Generates the code to convert from a pointer (`Box`, `&T`, etc) * into an object (`Box`, `&Trait`, etc). This means creating a diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 8e986defb6a36..28cfaa81e11c1 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -50,11 +50,11 @@ pub fn pointer_add_byte(bcx: Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef return PointerCast(bcx, InBoundsGEP(bcx, bptr, &[bytes]), old_ty); } -pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn make_drop_glue_unboxed<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, vptr: ValueRef, unit_ty: Ty<'tcx>, should_deallocate: bool) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let not_null = IsNotNull(bcx, vptr); with_cond(bcx, not_null, |bcx| { let ccx = bcx.ccx(); @@ -107,10 +107,10 @@ impl<'tcx> VecTypes<'tcx> { } } -pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_fixed_vstore<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, expr: &ast::Expr, dest: expr::Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { //! // // [...] allocates a fixed-size array and moves it around "by value". @@ -134,10 +134,10 @@ pub fn trans_fixed_vstore<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; } -pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_slice_vec<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, slice_expr: &ast::Expr, content_expr: &ast::Expr) - -> DatumBlock<'blk, 'tcx, Expr> { + -> DatumBlock<'fcx, 'blk, 'tcx, Expr> { /*! * &[...] allocates memory on the stack and writes the values into it, * returning the vector (the caller must make the reference). "..." is @@ -208,11 +208,11 @@ pub fn trans_slice_vec<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock() } -pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn trans_lit_str<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, lit_expr: &ast::Expr, str_lit: InternedString, dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { /*! * Literal strings translate to slices into static memory. This is * different from trans_slice_vstore() above because it doesn't need to copy @@ -239,12 +239,12 @@ pub fn trans_lit_str<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn write_content<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, vt: &VecTypes<'tcx>, vstore_expr: &ast::Expr, content_expr: &ast::Expr, dest: Dest) - -> Block<'blk, 'tcx> { + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("tvec::write_content"); let fcx = bcx.fcx; let mut bcx = bcx; @@ -337,14 +337,14 @@ pub fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -pub fn vec_types_from_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn vec_types_from_expr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, vec_expr: &ast::Expr) -> VecTypes<'tcx> { let vec_ty = node_id_type(bcx, vec_expr.id); vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty)) } -pub fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn vec_types<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, unit_ty: Ty<'tcx>) -> VecTypes<'tcx> { let ccx = bcx.ccx(); @@ -440,15 +440,15 @@ pub fn get_base_and_len(bcx: Block, } } -pub type iter_vec_block<'a, 'blk, 'tcx> = - |Block<'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'blk, 'tcx>; +pub type iter_vec_block<'a, 'fcx, 'blk, 'tcx> = + |Block<'fcx, 'blk, 'tcx>, ValueRef, Ty<'tcx>|: 'a -> Block<'fcx, 'blk, 'tcx>; -pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn iter_vec_loop<'a, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, data_ptr: ValueRef, vt: &VecTypes<'tcx>, count: ValueRef, - f: iter_vec_block<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: iter_vec_block<'a, 'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("tvec::iter_vec_loop"); let fcx = bcx.fcx; @@ -457,14 +457,14 @@ pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let cond_bcx = fcx.new_temp_block("expr_repeat: loop cond"); let body_bcx = fcx.new_temp_block("expr_repeat: body: set"); let inc_bcx = fcx.new_temp_block("expr_repeat: body: inc"); - Br(bcx, loop_bcx.llbb); + Br(bcx, loop_bcx.data.llbb); let loop_counter = { // i = 0 let i = alloca(loop_bcx, bcx.ccx().int_type(), "__i"); Store(loop_bcx, C_uint(bcx.ccx(), 0u), i); - Br(loop_bcx, cond_bcx.llbb); + Br(loop_bcx, cond_bcx.data.llbb); i }; @@ -473,7 +473,7 @@ pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let rhs = count; let cond_val = ICmp(cond_bcx, llvm::IntULT, lhs, rhs); - CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb); + CondBr(cond_bcx, cond_val, body_bcx.data.llbb, next_bcx.data.llbb); } { // loop body @@ -485,7 +485,7 @@ pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let body_bcx = f(body_bcx, lleltptr, vt.unit_ty); - Br(body_bcx, inc_bcx.llbb); + Br(body_bcx, inc_bcx.data.llbb); } { // i += 1 @@ -493,18 +493,18 @@ pub fn iter_vec_loop<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1u)); Store(inc_bcx, plusone, loop_counter); - Br(inc_bcx, cond_bcx.llbb); + Br(inc_bcx, cond_bcx.data.llbb); } next_bcx } -pub fn iter_vec_raw<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, +pub fn iter_vec_raw<'a, 'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, data_ptr: ValueRef, unit_ty: Ty<'tcx>, len: ValueRef, - f: iter_vec_block<'a, 'blk, 'tcx>) - -> Block<'blk, 'tcx> { + f: iter_vec_block<'a, 'fcx, 'blk, 'tcx>) + -> Block<'fcx, 'blk, 'tcx> { let _icx = push_ctxt("tvec::iter_vec_raw"); let fcx = bcx.fcx; @@ -523,19 +523,19 @@ pub fn iter_vec_raw<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Now perform the iteration. let header_bcx = fcx.new_temp_block("iter_vec_loop_header"); - Br(bcx, header_bcx.llbb); + Br(bcx, header_bcx.data.llbb); let data_ptr = - Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.llbb]); + Phi(header_bcx, val_ty(data_ptr), &[data_ptr], &[bcx.data.llbb]); let not_yet_at_end = ICmp(header_bcx, llvm::IntULT, data_ptr, data_end_ptr); let body_bcx = fcx.new_temp_block("iter_vec_loop_body"); let next_bcx = fcx.new_temp_block("iter_vec_next"); - CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb); + CondBr(header_bcx, not_yet_at_end, body_bcx.data.llbb, next_bcx.data.llbb); let body_bcx = f(body_bcx, data_ptr, vt.unit_ty); AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, &[C_int(bcx.ccx(), 1i)]), - body_bcx.llbb); - Br(body_bcx, header_bcx.llbb); + body_bcx.data.llbb); + Br(body_bcx, header_bcx.data.llbb); next_bcx } } diff --git a/src/librustc_trans/trans/value.rs b/src/librustc_trans/trans/value.rs index 8d74275c92ac7..4352b46ad5794 100644 --- a/src/librustc_trans/trans/value.rs +++ b/src/librustc_trans/trans/value.rs @@ -59,7 +59,7 @@ impl Value { match self.get_single_user().and_then(|user| user.as_store_inst()) { Some(store) => { store.get_parent().and_then(|store_bb| { - let mut bb = BasicBlock(bcx.llbb); + let mut bb = BasicBlock(bcx.data.llbb); let mut ret = Some(store); while bb.get() != store_bb.get() { match bb.get_single_predecessor() { From 4351a7bf62275617c0cb18db507bb6c285df69ae Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 19 Dec 2014 15:11:48 +0100 Subject: [PATCH 47/65] librustc_trans: Accomodate new lifetime restrictions. Accomodate new lifetime restrictions by ensuring `type_arena` outlives `ast_map`. --- src/librustc_trans/driver/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/driver/driver.rs b/src/librustc_trans/driver/driver.rs index b3b68d0c22b38..2dcc4fe7f7b72 100644 --- a/src/librustc_trans/driver/driver.rs +++ b/src/librustc_trans/driver/driver.rs @@ -76,13 +76,13 @@ pub fn compile_input(sess: Session, }; let mut forest = ast_map::Forest::new(expanded_crate); + let type_arena = TypedArena::new(); let ast_map = assign_node_ids_and_map(&sess, &mut forest); write_out_deps(&sess, input, &outputs, id.as_slice()); if stop_after_phase_2(&sess) { return; } - let type_arena = TypedArena::new(); let analysis = phase_3_run_analysis_passes(sess, ast_map, &type_arena, id); phase_save_analysis(&analysis.ty_cx.sess, analysis.ty_cx.map.krate(), &analysis, outdir); if stop_after_phase_3(&analysis.ty_cx.sess) { return; } From fc18f8be94218a029282b934b67ee0ae976956ad Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 19 Dec 2014 15:12:08 +0100 Subject: [PATCH 48/65] librustdoc: Accomodate new lifetime restrictions. Accomodate new lifetime restrictions by ensuring `type_arena` outlives `ast_map`. --- src/librustdoc/core.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index b040a4bfd2a09..9b319bb328c8f 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -119,9 +119,9 @@ pub fn run_core(libs: Vec, cfgs: Vec, externs: Externs, .expect("phase_2_configure_and_expand aborted in rustdoc!"); let mut forest = ast_map::Forest::new(krate); + let type_arena = TypedArena::new(); let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest); - let type_arena = TypedArena::new(); let driver::CrateAnalysis { exported_items, public_items, ty_cx, .. } = driver::phase_3_run_analysis_passes(sess, ast_map, &type_arena, name); From f1867594baa44e6d58abf837922b6015d9bb7ad7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 22 Dec 2014 18:59:54 +0100 Subject: [PATCH 49/65] Fixes for compile-fail/ tests in wake of destructor lifetime changes. --- .../borrowck-borrowed-uniq-rvalue.rs | 5 ++-- .../compile-fail/borrowck-let-suggestion.rs | 2 +- src/test/compile-fail/issue-16465.rs | 24 ------------------- .../compile-fail/kindck-destructor-owned.rs | 1 - .../unsafe-destructor-check-crash.rs | 23 ------------------ 5 files changed, 4 insertions(+), 51 deletions(-) delete mode 100644 src/test/compile-fail/issue-16465.rs delete mode 100644 src/test/compile-fail/unsafe-destructor-check-crash.rs diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index f2ff5f86f6393..538dfa0a2518b 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -14,10 +14,11 @@ extern crate collections; use std::collections::HashMap; fn main() { + let tmp; let mut buggy_map: HashMap = HashMap::new(); buggy_map.insert(42, &*box 1); //~ ERROR borrowed value does not live long enough - // but it is ok if we use a temporary - let tmp = box 2; + // but it is ok if we use a temporary that outlives `buggy_map`. + tmp = box 2; buggy_map.insert(43, &*tmp); } diff --git a/src/test/compile-fail/borrowck-let-suggestion.rs b/src/test/compile-fail/borrowck-let-suggestion.rs index cd1101c05d15f..961ecd4d4114d 100644 --- a/src/test/compile-fail/borrowck-let-suggestion.rs +++ b/src/test/compile-fail/borrowck-let-suggestion.rs @@ -10,7 +10,7 @@ fn f() { let x = [1i].iter(); //~ ERROR borrowed value does not live long enough - //~^^ NOTE reference must be valid for the block + //~^ NOTE reference must be valid for the block //~^^ HELP consider using a `let` binding to increase its lifetime } diff --git a/src/test/compile-fail/issue-16465.rs b/src/test/compile-fail/issue-16465.rs deleted file mode 100644 index 280f19cfe9cc7..0000000000000 --- a/src/test/compile-fail/issue-16465.rs +++ /dev/null @@ -1,24 +0,0 @@ -// 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. - -// Used to cause an ICE - -struct Foo{ - x : T -} - -type FooInt = Foo; - -impl Drop for FooInt { -//~^ ERROR cannot implement a destructor on a structure with type parameters - fn drop(&mut self){} -} - -fn main() {} diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index 26b0c5503e32f..9d73d20d2478f 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -27,7 +27,6 @@ struct Bar<'a> { } impl<'a> Drop for Bar<'a> { -//~^ ERROR E0141 fn drop(&mut self) { } } diff --git a/src/test/compile-fail/unsafe-destructor-check-crash.rs b/src/test/compile-fail/unsafe-destructor-check-crash.rs deleted file mode 100644 index af675587728be..0000000000000 --- a/src/test/compile-fail/unsafe-destructor-check-crash.rs +++ /dev/null @@ -1,23 +0,0 @@ -// 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 issue #15557 - -#![allow(dead_code)] -struct AReg1<'a>(&'a u32); - -impl<'a> Drop for AReg1<'a> { -//~^ ERROR: cannot implement a destructor on a structure with type parameters - fn drop(&mut self) {} -} - -fn main() {} From 8df61aa95637a4bfe5a3d914f847a99308d1ab59 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 22 Dec 2014 19:02:11 +0100 Subject: [PATCH 50/65] improve `compiletest` error message when path option missing. (I often run `compiletest` by hand by cut-and-pasting from what `make` runs, but then I need to tweak it (cut out options) and its useful to be told when I have removed an option that is actually required, such as `--android-cross-path=path`.) --- src/compiletest/compiletest.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index f76cefcd94127..dc39d4ca2d6ab 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -111,7 +111,10 @@ pub fn parse_config(args: Vec ) -> Config { } fn opt_path(m: &getopts::Matches, nm: &str) -> Path { - Path::new(m.opt_str(nm).unwrap()) + match m.opt_str(nm) { + Some(s) => Path::new(s), + None => panic!("no option (=path) found for {}", nm), + } } let filter = if !matches.free.is_empty() { From a32202952759b856fc9bccebba91a8d64e87d0ac Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 22 Dec 2014 19:02:55 +0100 Subject: [PATCH 51/65] FIXME some compiler error messages that are newly emitted in drop-lts branch. This needs investigation: What did pnkfelix do that caused this to change? --- src/test/compile-fail/regionck-closure-lifetimes.rs | 1 + src/test/compile-fail/regions-freevar.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/regionck-closure-lifetimes.rs b/src/test/compile-fail/regionck-closure-lifetimes.rs index bb895a318ff17..1e1e7f40d9c4c 100644 --- a/src/test/compile-fail/regionck-closure-lifetimes.rs +++ b/src/test/compile-fail/regionck-closure-lifetimes.rs @@ -16,6 +16,7 @@ fn env<'a>(blk: |p: ||: 'a|) { let mut state = 0i; let statep = &mut state; blk(|| *statep = 1i); //~ ERROR captured variable `statep` does not outlive + //~^ ERROR closure outlives stack frame } fn no_env_no_for<'a>(blk: |p: |||: 'a) { diff --git a/src/test/compile-fail/regions-freevar.rs b/src/test/compile-fail/regions-freevar.rs index 76bbe71cf75b5..1a186ddb8bd1a 100644 --- a/src/test/compile-fail/regions-freevar.rs +++ b/src/test/compile-fail/regions-freevar.rs @@ -12,7 +12,7 @@ fn wants_static_fn(_x: ||: 'static) {} fn main() { let i = 3i; - wants_static_fn(|| { + wants_static_fn(|| { //~ ERROR closure outlives stack frame println!("i={}", i); //~ ERROR captured variable `i` does not outlive }) } From 2c02fd93b8a659d03934dcdbfb97e39d28f1d5bb Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 20:50:59 +0100 Subject: [PATCH 52/65] fix exponential time blowup on compile-fail/huge-struct.rs by keeping the breadcrumbs until end of traversal. --- src/librustc/middle/typeck/check/dropck.rs | 3 ++- src/librustc/middle/typeck/check/regionck.rs | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index 67e15ac03dec4..7ef697e1b8f63 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -19,7 +19,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx> span, scope, false, - 0) + 0); + rcx.reset_traversal(); } fn constrain_region_for_destructor_safety(rcx: &mut Rcx, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index d5eed8064faf5..08e7a483a4b6a 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -278,6 +278,11 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { maybe_links: RefCell::new(FnvHashMap::new()) } } + pub fn reset_traversal(&mut self) { + self.breadcrumbs.clear(); + self.breadcrumbs.shrink_to_fit(); + } + pub fn traverse_type_if_unseen(&mut self, typ: ty::Ty<'tcx>, keep_going: |&mut Rcx<'a, 'tcx>| -> bool) -> bool { @@ -287,8 +292,18 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { if !rcx.breadcrumbs.contains(&typ) { rcx.breadcrumbs.push(typ); let keep_going = keep_going(rcx); - let top_t = rcx.breadcrumbs.pop(); - assert_eq!(top_t, Some(typ)); + + // FIXME: popping the breadcrumbs here is a reasonable + // idea, but then you fall victim to exponential time on + // examples like src/tests/compile-fail/huge-struct.rs. + // So pnkfelix is trying to experimentally not remove + // anything from the vector during any particular + // traversal, and instead clear it after the whole + // traversal is done. + // + // let top_t = rcx.breadcrumbs.pop(); + // assert_eq!(top_t, Some(typ)); + keep_going } else { false From ecf6a6cb7d46b8168432b094f65abe394915354a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 21:06:43 +0100 Subject: [PATCH 53/65] libregex: accomodate new lifetime rules for droppable things. In particular, ensure that both of the thread objects created for nlist and clist both outlive nlist and clist themselves. --- src/libregex_macros/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libregex_macros/lib.rs b/src/libregex_macros/lib.rs index 3cc6d361e3c58..14d23ecc9fb96 100644 --- a/src/libregex_macros/lib.rs +++ b/src/libregex_macros/lib.rs @@ -183,8 +183,10 @@ fn exec<'t>(which: ::regex::native::MatchKind, input: &'t str, fn run(&mut self, start: uint, end: uint) -> Vec> { let mut matched = false; let prefix_bytes: &[u8] = $prefix_bytes; - let mut clist = &mut Threads::new(self.which); - let mut nlist = &mut Threads::new(self.which); + let mut cthread = Threads::new(self.which); + let mut nthread = Threads::new(self.which); + let mut clist = &mut cthread; + let mut nlist = &mut nthread; let mut groups = $init_groups; From 73ae146ef27ca3c8d03373ba268f3ce3b4829274 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 21:06:53 +0100 Subject: [PATCH 54/65] remove outdated test. --- .../compile-fail/kindck-destructor-owned.rs | 43 ------------------- 1 file changed, 43 deletions(-) delete mode 100644 src/test/compile-fail/kindck-destructor-owned.rs diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs deleted file mode 100644 index 9d73d20d2478f..0000000000000 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ /dev/null @@ -1,43 +0,0 @@ -// 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. - - -use std::rc::Rc; - -struct Foo { - f: Rc, -} - -impl Drop for Foo { -//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo` -//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send - fn drop(&mut self) { - } -} - -struct Bar<'a> { - f: &'a int, -} - -impl<'a> Drop for Bar<'a> { - fn drop(&mut self) { - } -} - -struct Baz { - f: &'static int, -} - -impl Drop for Baz { - fn drop(&mut self) { - } -} - -fn main() { } From 76955734d22fad5c4547018dfecb7ba21d1bbd15 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 21:27:44 +0100 Subject: [PATCH 55/65] update flowgraph graphviz test output to include new destruction scopes. It is very unfortunate that the destruction scopes are not printed in some distinguished way here. It is also unfortunate that the graphviz tests are so hard to maintain -- it would probably be better to just have a flowgraph graphviz mode that does not include the exiting-scope edge labels, and then only test in that mode. --- src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot | 2 +- src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot | 4 ++-- src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot | 4 ++-- src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot | 2 +- src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot | 2 +- src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot | 6 +++--- src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot | 8 ++++---- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot index d89a37308de06..566b09bcf84eb 100644 --- a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -34,7 +34,7 @@ digraph block { N11 -> N12; N12 -> N13; N13 -> N14; - N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; + N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if x == 2i { break ; \"unreachable\"; },\lexiting scope_6 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } },\lexiting scope_7 block { x -= 1i; if x == 2i { break ; \"unreachable\"; } }"]; N15 -> N16; N16 -> N17; N17 -> N18; diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index 4bd9fc9ec1ad1..394cbcb060232 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -61,7 +61,7 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 stmt break \'outer ;,\lexiting scope_3 block { break \'outer ; \"unreachable\"; },\lexiting scope_4 block { break \'outer ; \"unreachable\"; },\lexiting scope_5 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_6 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_7 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_9 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_10 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_11 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_12 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_13 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l,\lexiting scope_14 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; @@ -73,7 +73,7 @@ digraph block { N23 -> N24; N24 -> N25; N25 -> N26; - N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; + N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_6 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_7 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_9 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N27 -> N28; N28 -> N29; N29 -> N30; diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index 16b871bd844bf..b27154418b4c5 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -64,7 +64,7 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 stmt continue \'outer ;,\lexiting scope_3 block { continue \'outer ; \"unreachable\"; },\lexiting scope_4 block { continue \'outer ; \"unreachable\"; },\lexiting scope_5 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_6 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_7 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_9 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_10 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_11 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_12 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_13 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l,\lexiting scope_14 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; @@ -76,7 +76,7 @@ digraph block { N23 -> N24; N24 -> N25; N25 -> N26; - N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; + N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_6 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_7 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_9 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N27 -> N28; N28 -> N29; N29 -> N30; diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot index ad2ef60ce2918..431711179d71f 100644 --- a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -59,7 +59,7 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; + N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 stmt break \'outer ;,\lexiting scope_3 block { break \'outer ; \"unreachable\"; },\lexiting scope_4 block { break \'outer ; \"unreachable\"; },\lexiting scope_5 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_6 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_7 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l,\lexiting scope_9 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l}\l,\lexiting scope_10 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_11 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_12 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l,\lexiting scope_13 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l,\lexiting scope_14 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l y -= 3i;\l x -= 5i;\l }\l \"unreachable\";\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot index dcceb5bb937da..babdf6f410dd9 100644 --- a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -62,7 +62,7 @@ digraph block { N12 -> N13; N13 -> N14; N14 -> N15; - N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; + N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 stmt continue \'outer ;,\lexiting scope_3 block { continue \'outer ; \"unreachable\"; },\lexiting scope_4 block { continue \'outer ; \"unreachable\"; },\lexiting scope_5 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_6 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_7 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l,\lexiting scope_9 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l}\l,\lexiting scope_10 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_11 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_12 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l,\lexiting scope_13 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l,\lexiting scope_14 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 2i { return; \"unreachable\"; }\l x -= 1i;\l y -= 3i;\l }\l \"unreachable\";\l}\l"]; N16 -> N17; N17 -> N18; N18 -> N19; diff --git a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot index ddb5b865c2edb..6620a28dbe435 100644 --- a/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f24.dot-expected.dot @@ -90,7 +90,7 @@ digraph block { N13 -> N14; N14 -> N15; N15 -> N16; - N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; + N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l,\lexiting scope_9 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l }\l}\l"]; N17 -> N18; N18 -> N19; N19 -> N20; @@ -107,7 +107,7 @@ digraph block { N30 -> N31; N31 -> N32; N32 -> N33; - N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; + N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l,\lexiting scope_9 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { return; \"unreachable\"; }\l}\l"]; N34 -> N35; N35 -> N36; N36 -> N37; @@ -124,7 +124,7 @@ digraph block { N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_8 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; },\lexiting scope_9 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; N51 -> N52; N52 -> N53; N53 -> N54; diff --git a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot index 9fd4dbfc39553..1204b800213af 100644 --- a/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f25.dot-expected.dot @@ -90,7 +90,7 @@ digraph block { N13 -> N14; N14 -> N15; N15 -> N16; - N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; + N16 -> N12[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if x == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if x == 0i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l,\lexiting scope_9 block {\l if x == 0i { break ; \"unreachable\"; }\l x -= 1i;\l \'a:\l loop {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l }\l}\l"]; N17 -> N18; N18 -> N19; N19 -> N20; @@ -107,7 +107,7 @@ digraph block { N30 -> N31; N31 -> N32; N32 -> N33; - N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N33 -> N29[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if y == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if y == 0i { break ; \"unreachable\"; },\lexiting scope_8 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l,\lexiting scope_9 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; N34 -> N35; N35 -> N36; N36 -> N37; @@ -124,7 +124,7 @@ digraph block { N47 -> N48; N48 -> N49; N49 -> N50; - N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_4 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_5 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; + N50 -> N46[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 stmt break ;,\lexiting scope_3 block { break ; \"unreachable\"; },\lexiting scope_4 block { break ; \"unreachable\"; },\lexiting scope_5 expr if z == 0i { break ; \"unreachable\"; },\lexiting scope_6 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_7 stmt if z == 0i { break ; \"unreachable\"; },\lexiting scope_8 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; },\lexiting scope_9 block { if z == 0i { break ; \"unreachable\"; } z -= 1i; }"]; N51 -> N52; N52 -> N53; N53 -> N54; @@ -143,7 +143,7 @@ digraph block { N64 -> N65; N65 -> N66; N66 -> N67; - N67 -> N28[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 block { continue \'a ; \"unreachable\"; },\lexiting scope_3 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_4 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; + N67 -> N28[label="exiting scope_0 expr continue \'a,\lexiting scope_1 stmt continue \'a ;,\lexiting scope_2 stmt continue \'a ;,\lexiting scope_3 block { continue \'a ; \"unreachable\"; },\lexiting scope_4 block { continue \'a ; \"unreachable\"; },\lexiting scope_5 expr if x > 10i { continue \'a ; \"unreachable\"; },\lexiting scope_6 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l,\lexiting scope_7 block {\l if y == 0i { break ; \"unreachable\"; }\l y -= 1i;\l \'a: loop { if z == 0i { break ; \"unreachable\"; } z -= 1i; }\l if x > 10i { continue \'a ; \"unreachable\"; }\l}\l"]; N68 -> N69; N69 -> N70; N70 -> N71; From 31cec2791babe227b9db2d5a1a9ad3b734e45afa Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 21:35:32 +0100 Subject: [PATCH 56/65] std::io::process test: ensure that `path_val` outlives the container that borrows it. (part of fallout from new destructor lifetime rules.) --- src/libstd/io/process.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index d4d24c1e12fc8..c007196a9f878 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -1065,13 +1065,13 @@ mod tests { #[test] fn test_override_env() { use os; + let path_val: String; let mut new_env = vec![("RUN_TEST_NEW_ENV", "123")]; // In some build environments (such as chrooted Nix builds), `env` can // only be found in the explicitly-provided PATH env variable, not in // default places such as /bin or /usr/bin. So we need to pass through // PATH to our sub-process. - let path_val: String; match os::getenv("PATH") { None => {} Some(val) => { From f08a61983965a35fd50fcad6a0c45105ccf60b45 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sun, 4 Jan 2015 21:54:44 +0100 Subject: [PATCH 57/65] remove span_note output from dropck; at this point it is more noise than info. --- src/librustc/middle/typeck/check/dropck.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index 7ef697e1b8f63..d5d8cad320a6e 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -57,11 +57,6 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, debug!("constrain_region_for_destructor_safety region: {} :> parent_inner_region: {} (from inner_scope: {}){}", region, parent_inner_region, inner_scope, if could_have_been_re_function { " could_have_been_re_function" } else { "" }); - rcx.tcx().sess.span_note( - span, - format!("constrain_region_for_destructor_safety \ - region: {} sub/inner_scope: {} sup/parent_inner_region: {}", - region, inner_scope, parent_inner_region).as_slice()); rcx.mk_subr(infer::SafeDestructor(span), parent_inner_region, From a63ae49b0dc4215a6b02f7adb29000e3bf48627e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 11:15:10 +0100 Subject: [PATCH 58/65] fallout from new scoping rules for destructors. --- src/libcollections/hash/sip.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcollections/hash/sip.rs b/src/libcollections/hash/sip.rs index ab69a3ad8b883..c5a2dd559c4e8 100644 --- a/src/libcollections/hash/sip.rs +++ b/src/libcollections/hash/sip.rs @@ -490,8 +490,10 @@ mod tests { assert!(s != t && t != u); assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - let v: (&[u8], &[u8], &[u8]) = (&[1u8], &[0u8, 0], &[0u8]); - let w: (&[u8], &[u8], &[u8]) = (&[1u8, 0, 0, 0], &[], &[]); + let (v1, v2, v3) = ([1u8], [0u8, 0], [0u8]); + let (w1, w2, w3) = ([1u8, 0, 0, 0], [], []); + let v: (&[u8], &[u8], &[u8]) = (&v1, &v2, &v3); + let w: (&[u8], &[u8], &[u8]) = (&w1, &w2, &w3); assert!(v != w); assert!(hash(&v) != hash(&w)); From 20372ae4a4ec2dc125c5339d1f7880767b9e8f32 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 11:16:16 +0100 Subject: [PATCH 59/65] make `record_encl_scope` pub to accommodate src/librustc_trans/test.rs Though arguably it might be better to refactor the test to avoid having to make that method public. --- src/librustc/middle/region.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index cd780e5cc131e..773fbe1c06d2a 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -266,7 +266,7 @@ impl RegionMaps { self.free_region_map.borrow_mut().insert(sub, vec!(sup)); } - fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { + pub fn record_encl_scope(&self, sub: CodeExtent, sup: CodeExtent) { debug!("record_encl_scope(sub={}, sup={})", sub, sup); assert!(sub != sup); assert!(self.scope_map.borrow().get(&sup) != Some(&sub), From b79ed775fbfcce0688bdb231e63d9480f588c7a5 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 12:56:08 +0100 Subject: [PATCH 60/65] accommodate new scoping rules for destructors. --- src/librustc_trans/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_trans/test.rs b/src/librustc_trans/test.rs index 1e8c1fd14787d..50bcc698e896c 100644 --- a/src/librustc_trans/test.rs +++ b/src/librustc_trans/test.rs @@ -118,6 +118,7 @@ fn test_env(source_string: &str, .expect("phase 2 aborted"); let mut forest = ast_map::Forest::new(krate); + let type_arena = TypedArena::new(); let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest); let krate = ast_map.krate(); @@ -128,7 +129,6 @@ fn test_env(source_string: &str, let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map); let region_map = region::resolve_crate(&sess, krate); let stability_index = stability::Index::build(krate); - let type_arena = TypedArena::new(); let tcx = ty::mk_ctxt(sess, &type_arena, def_map, From c134e3a9d3b4951f855d157ece7c13d06273385d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 13:09:48 +0100 Subject: [PATCH 61/65] work-around for a wart in the current implementation of new destructor semantics. --- src/liballoc/rc.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index df84ac9aec935..c390a8b0f7d5d 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -142,6 +142,14 @@ //! // destroyed. There are now no strong (Rc) references to the gadgets. //! // Once they get destroyed, the Gadgets get destroyed. This zeroes the //! // reference count on Gadget Man, so he gets destroyed as well. +//! +//! // This is an unfortunate wart that is a side-effect of the implmentation +//! // of new destructor semantics: if the above for-loop is the final expression +//! // in the function, the borrow-checker treats the gadget_owner as needing to +//! // live past the destruction scope of the function (which of course it does not). +//! // To work around this, for now I am inserting a dummy value just so the above +//! // for-loop is no longer the final expression in the block. +//! () //! } //! ``` From 1a6790116d9126fb13a4ab137b8ed009bda7ce8e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 13:25:04 +0100 Subject: [PATCH 62/65] remove the (temporary from the start) libst2 tree. --- src/libst2/ascii.rs | 382 ------- src/libst2/bitflags.rs | 463 --------- src/libst2/c_vec.rs | 118 --- src/libst2/collections/hash/bench.rs | 0 src/libst2/collections/hash/map.rs | 880 ---------------- src/libst2/collections/hash/mod.rs | 15 - src/libst2/collections/hash/set.rs | 519 ---------- src/libst2/collections/hash/table.rs | 408 -------- src/libst2/collections/lru_cache.rs | 245 ----- src/libst2/collections/mod.rs | 354 ------- src/libst2/dynamic_lib.rs | 154 --- src/libst2/error.rs | 106 -- src/libst2/failure.rs | 37 - src/libst2/fmt.rs | 446 -------- src/libst2/hash.rs | 94 -- src/libst2/io/buffered.rs | 246 ----- src/libst2/io/comm_adapters.rs | 88 -- src/libst2/io/extensions.rs | 97 -- src/libst2/io/fs.rs | 530 ---------- src/libst2/io/mem.rs | 235 ----- src/libst2/io/mod.rs | 1258 ----------------------- src/libst2/io/net/addrinfo.rs | 96 -- src/libst2/io/net/ip.rs | 231 ----- src/libst2/io/net/mod.rs | 27 - src/libst2/io/net/pipe.rs | 206 ---- src/libst2/io/net/tcp.rs | 400 ------- src/libst2/io/net/udp.rs | 182 ---- src/libst2/io/pipe.rs | 93 -- src/libst2/io/process.rs | 470 --------- src/libst2/io/result.rs | 42 - src/libst2/io/stdio.rs | 396 ------- src/libst2/io/tempfile.rs | 69 -- src/libst2/io/test.rs | 81 -- src/libst2/io/timer.rs | 192 ---- src/libst2/io/util.rs | 161 --- src/libst2/lib.rs | 280 ----- src/libst2/macros.rs | 626 ----------- src/libst2/num/f32.rs | 261 ----- src/libst2/num/f64.rs | 269 ----- src/libst2/num/float_macros.rs | 22 - src/libst2/num/i16.rs | 18 - src/libst2/num/i32.rs | 18 - src/libst2/num/i64.rs | 18 - src/libst2/num/i8.rs | 18 - src/libst2/num/int.rs | 18 - src/libst2/num/int_macros.rs | 17 - src/libst2/num/mod.rs | 143 --- src/libst2/num/strconv.rs | 558 ---------- src/libst2/num/u16.rs | 18 - src/libst2/num/u32.rs | 18 - src/libst2/num/u64.rs | 18 - src/libst2/num/u8.rs | 18 - src/libst2/num/uint.rs | 18 - src/libst2/num/uint_macros.rs | 37 - src/libst2/os.rs | 894 ---------------- src/libst2/path/mod.rs | 780 -------------- src/libst2/path/posix.rs | 167 --- src/libst2/path/windows.rs | 383 ------- src/libst2/prelude.rs | 94 -- src/libst2/rand/mod.rs | 362 ------- src/libst2/rand/os.rs | 384 ------- src/libst2/rand/reader.rs | 123 --- src/libst2/rt/backtrace.rs | 501 --------- src/libst2/rt/mod.rs | 114 -- src/libst2/rt/util.rs | 38 - src/libst2/rtdeps.rs | 52 - src/libst2/sync/future.rs | 67 -- src/libst2/sync/mod.rs | 33 - src/libst2/sync/task_pool.rs | 80 -- src/libst2/sys/common/helper_thread.rs | 78 -- src/libst2/sys/common/mod.rs | 55 - src/libst2/sys/common/net.rs | 298 ------ src/libst2/sys/common/thread_local.rs | 215 ---- src/libst2/sys/unix/c.rs | 257 ----- src/libst2/sys/unix/fs.rs | 95 -- src/libst2/sys/unix/helper_signal.rs | 22 - src/libst2/sys/unix/mod.rs | 82 -- src/libst2/sys/unix/os.rs | 25 - src/libst2/sys/unix/pipe.rs | 151 --- src/libst2/sys/unix/process.rs | 69 -- src/libst2/sys/unix/tcp.rs | 71 -- src/libst2/sys/unix/thread_local.rs | 40 - src/libst2/sys/unix/timer.rs | 110 -- src/libst2/sys/unix/tty.rs | 29 - src/libst2/sys/unix/udp.rs | 11 - src/libst2/sys/windows/c.rs | 250 ----- src/libst2/sys/windows/fs.rs | 460 --------- src/libst2/sys/windows/helper_signal.rs | 38 - src/libst2/sys/windows/mod.rs | 85 -- src/libst2/sys/windows/os.rs | 103 -- src/libst2/sys/windows/pipe.rs | 751 -------------- src/libst2/sys/windows/process.rs | 511 --------- src/libst2/sys/windows/tcp.rs | 219 ---- src/libst2/sys/windows/thread_local.rs | 238 ----- src/libst2/sys/windows/timer.rs | 210 ---- src/libst2/sys/windows/tty.rs | 166 --- src/libst2/sys/windows/udp.rs | 11 - src/libst2/task.rs | 183 ---- src/libst2/thread_local/mod.rs | 313 ------ src/libst2/thread_local/scoped.rs | 199 ---- src/libst2/time/duration.rs | 557 ---------- src/libst2/time/mod.rs | 46 - 102 files changed, 21734 deletions(-) delete mode 100644 src/libst2/ascii.rs delete mode 100644 src/libst2/bitflags.rs delete mode 100644 src/libst2/c_vec.rs delete mode 100644 src/libst2/collections/hash/bench.rs delete mode 100644 src/libst2/collections/hash/map.rs delete mode 100644 src/libst2/collections/hash/mod.rs delete mode 100644 src/libst2/collections/hash/set.rs delete mode 100644 src/libst2/collections/hash/table.rs delete mode 100644 src/libst2/collections/lru_cache.rs delete mode 100644 src/libst2/collections/mod.rs delete mode 100644 src/libst2/dynamic_lib.rs delete mode 100644 src/libst2/error.rs delete mode 100644 src/libst2/failure.rs delete mode 100644 src/libst2/fmt.rs delete mode 100644 src/libst2/hash.rs delete mode 100644 src/libst2/io/buffered.rs delete mode 100644 src/libst2/io/comm_adapters.rs delete mode 100644 src/libst2/io/extensions.rs delete mode 100644 src/libst2/io/fs.rs delete mode 100644 src/libst2/io/mem.rs delete mode 100644 src/libst2/io/mod.rs delete mode 100644 src/libst2/io/net/addrinfo.rs delete mode 100644 src/libst2/io/net/ip.rs delete mode 100644 src/libst2/io/net/mod.rs delete mode 100644 src/libst2/io/net/pipe.rs delete mode 100644 src/libst2/io/net/tcp.rs delete mode 100644 src/libst2/io/net/udp.rs delete mode 100644 src/libst2/io/pipe.rs delete mode 100644 src/libst2/io/process.rs delete mode 100644 src/libst2/io/result.rs delete mode 100644 src/libst2/io/stdio.rs delete mode 100644 src/libst2/io/tempfile.rs delete mode 100644 src/libst2/io/test.rs delete mode 100644 src/libst2/io/timer.rs delete mode 100644 src/libst2/io/util.rs delete mode 100644 src/libst2/lib.rs delete mode 100644 src/libst2/macros.rs delete mode 100644 src/libst2/num/f32.rs delete mode 100644 src/libst2/num/f64.rs delete mode 100644 src/libst2/num/float_macros.rs delete mode 100644 src/libst2/num/i16.rs delete mode 100644 src/libst2/num/i32.rs delete mode 100644 src/libst2/num/i64.rs delete mode 100644 src/libst2/num/i8.rs delete mode 100644 src/libst2/num/int.rs delete mode 100644 src/libst2/num/int_macros.rs delete mode 100644 src/libst2/num/mod.rs delete mode 100644 src/libst2/num/strconv.rs delete mode 100644 src/libst2/num/u16.rs delete mode 100644 src/libst2/num/u32.rs delete mode 100644 src/libst2/num/u64.rs delete mode 100644 src/libst2/num/u8.rs delete mode 100644 src/libst2/num/uint.rs delete mode 100644 src/libst2/num/uint_macros.rs delete mode 100644 src/libst2/os.rs delete mode 100644 src/libst2/path/mod.rs delete mode 100644 src/libst2/path/posix.rs delete mode 100644 src/libst2/path/windows.rs delete mode 100644 src/libst2/prelude.rs delete mode 100644 src/libst2/rand/mod.rs delete mode 100644 src/libst2/rand/os.rs delete mode 100644 src/libst2/rand/reader.rs delete mode 100644 src/libst2/rt/backtrace.rs delete mode 100644 src/libst2/rt/mod.rs delete mode 100644 src/libst2/rt/util.rs delete mode 100644 src/libst2/rtdeps.rs delete mode 100644 src/libst2/sync/future.rs delete mode 100644 src/libst2/sync/mod.rs delete mode 100644 src/libst2/sync/task_pool.rs delete mode 100644 src/libst2/sys/common/helper_thread.rs delete mode 100644 src/libst2/sys/common/mod.rs delete mode 100644 src/libst2/sys/common/net.rs delete mode 100644 src/libst2/sys/common/thread_local.rs delete mode 100644 src/libst2/sys/unix/c.rs delete mode 100644 src/libst2/sys/unix/fs.rs delete mode 100644 src/libst2/sys/unix/helper_signal.rs delete mode 100644 src/libst2/sys/unix/mod.rs delete mode 100644 src/libst2/sys/unix/os.rs delete mode 100644 src/libst2/sys/unix/pipe.rs delete mode 100644 src/libst2/sys/unix/process.rs delete mode 100644 src/libst2/sys/unix/tcp.rs delete mode 100644 src/libst2/sys/unix/thread_local.rs delete mode 100644 src/libst2/sys/unix/timer.rs delete mode 100644 src/libst2/sys/unix/tty.rs delete mode 100644 src/libst2/sys/unix/udp.rs delete mode 100644 src/libst2/sys/windows/c.rs delete mode 100644 src/libst2/sys/windows/fs.rs delete mode 100644 src/libst2/sys/windows/helper_signal.rs delete mode 100644 src/libst2/sys/windows/mod.rs delete mode 100644 src/libst2/sys/windows/os.rs delete mode 100644 src/libst2/sys/windows/pipe.rs delete mode 100644 src/libst2/sys/windows/process.rs delete mode 100644 src/libst2/sys/windows/tcp.rs delete mode 100644 src/libst2/sys/windows/thread_local.rs delete mode 100644 src/libst2/sys/windows/timer.rs delete mode 100644 src/libst2/sys/windows/tty.rs delete mode 100644 src/libst2/sys/windows/udp.rs delete mode 100644 src/libst2/task.rs delete mode 100644 src/libst2/thread_local/mod.rs delete mode 100644 src/libst2/thread_local/scoped.rs delete mode 100644 src/libst2/time/duration.rs delete mode 100644 src/libst2/time/mod.rs diff --git a/src/libst2/ascii.rs b/src/libst2/ascii.rs deleted file mode 100644 index 272851218f370..0000000000000 --- a/src/libst2/ascii.rs +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15679 - -//! Operations on ASCII strings and characters - -#![unstable = "unsure about placement and naming"] -#![allow(deprecated)] - -use core::kinds::Sized; -use fmt; -use iter::Iterator; -use mem; -use option::{Option, Some, None}; -use slice::{SlicePrelude, AsSlice}; -use str::{Str, StrPrelude}; -use string::{String, IntoString}; -use vec::Vec; - -/// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. -#[deriving(Clone, PartialEq, PartialOrd, Ord, Eq, Hash)] -pub struct Ascii { chr: u8 } - -impl Ascii { - /// Converts an ascii character into a `u8`. - #[inline] - #[unstable = "recently renamed"] - pub fn as_byte(&self) -> u8 { unimplemented!() } - - /// Deprecated: use `as_byte` isntead. - #[deprecated = "use as_byte"] - pub fn to_byte(self) -> u8 { unimplemented!() } - - /// Converts an ascii character into a `char`. - #[inline] - #[unstable = "recently renamed"] - pub fn as_char(&self) -> char { unimplemented!() } - - /// Deprecated: use `as_char` isntead. - #[deprecated = "use as_char"] - pub fn to_char(self) -> char { unimplemented!() } - - /// Convert to lowercase. - #[inline] - #[stable] - pub fn to_lowercase(&self) -> Ascii { unimplemented!() } - - /// Convert to uppercase. - #[inline] - #[stable] - pub fn to_uppercase(&self) -> Ascii { unimplemented!() } - - /// Compares two ascii characters of equality, ignoring case. - #[inline] - #[deprecated = "normalize with to_lowercase"] - pub fn eq_ignore_case(self, other: Ascii) -> bool { unimplemented!() } - - // the following methods are like ctype, and the implementation is inspired by musl - - /// Check if the character is a letter (a-z, A-Z) - #[inline] - #[stable] - pub fn is_alphabetic(&self) -> bool { unimplemented!() } - - /// Check if the character is a number (0-9) - #[inline] - #[unstable = "may be renamed"] - pub fn is_digit(&self) -> bool { unimplemented!() } - - /// Check if the character is a letter or number - #[inline] - #[stable] - pub fn is_alphanumeric(&self) -> bool { unimplemented!() } - - /// Check if the character is a space or horizontal tab - #[inline] - #[experimental = "likely to be removed"] - pub fn is_blank(&self) -> bool { unimplemented!() } - - /// Check if the character is a control character - #[inline] - #[stable] - pub fn is_control(&self) -> bool { unimplemented!() } - - /// Checks if the character is printable (except space) - #[inline] - #[experimental = "unsure about naming, or whether this is needed"] - pub fn is_graph(&self) -> bool { unimplemented!() } - - /// Checks if the character is printable (including space) - #[inline] - #[unstable = "unsure about naming"] - pub fn is_print(&self) -> bool { unimplemented!() } - - /// Checks if the character is alphabetic and lowercase - #[inline] - #[stable] - pub fn is_lowercase(&self) -> bool { unimplemented!() } - - /// Checks if the character is alphabetic and uppercase - #[inline] - #[stable] - pub fn is_uppercase(&self) -> bool { unimplemented!() } - - /// Checks if the character is punctuation - #[inline] - #[stable] - pub fn is_punctuation(&self) -> bool { unimplemented!() } - - /// Checks if the character is a valid hex digit - #[inline] - #[stable] - pub fn is_hex(&self) -> bool { unimplemented!() } -} - -impl<'a> fmt::Show for Ascii { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -/// Trait for converting into an ascii type. -#[experimental = "may be replaced by generic conversion traits"] -pub trait AsciiCast { - /// Convert to an ascii type, panic on non-ASCII input. - #[inline] - fn to_ascii(&self) -> T { unimplemented!() } - - /// Convert to an ascii type, return None on non-ASCII input. - #[inline] - fn to_ascii_opt(&self) -> Option { unimplemented!() } - - /// Convert to an ascii type, not doing any range asserts - unsafe fn to_ascii_nocheck(&self) -> T; - - /// Check if convertible to ascii - fn is_ascii(&self) -> bool; -} - -#[experimental = "may be replaced by generic conversion traits"] -impl<'a> AsciiCast<&'a[Ascii]> for &'a [u8] { - #[inline] - unsafe fn to_ascii_nocheck(&self) -> &'a[Ascii] { unimplemented!() } - - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } -} - -#[experimental = "may be replaced by generic conversion traits"] -impl<'a> AsciiCast<&'a [Ascii]> for &'a str { - #[inline] - unsafe fn to_ascii_nocheck(&self) -> &'a [Ascii] { unimplemented!() } - - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } -} - -#[experimental = "may be replaced by generic conversion traits"] -impl AsciiCast for u8 { - #[inline] - unsafe fn to_ascii_nocheck(&self) -> Ascii { unimplemented!() } - - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } -} - -#[experimental = "may be replaced by generic conversion traits"] -impl AsciiCast for char { - #[inline] - unsafe fn to_ascii_nocheck(&self) -> Ascii { unimplemented!() } - - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } -} - -/// Trait for copyless casting to an ascii vector. -#[experimental = "may be replaced by generic conversion traits"] -pub trait OwnedAsciiCast { - /// Check if convertible to ascii - fn is_ascii(&self) -> bool; - - /// Take ownership and cast to an ascii vector. - /// # Panics - /// - /// Panic on non-ASCII input. - #[inline] - fn into_ascii(self) -> Vec { unimplemented!() } - - /// Take ownership and cast to an ascii vector. Return None on non-ASCII input. - #[inline] - fn into_ascii_opt(self) -> Option> { unimplemented!() } - - /// Take ownership and cast to an ascii vector. - /// Does not perform validation checks. - unsafe fn into_ascii_nocheck(self) -> Vec; -} - -#[experimental = "may be replaced by generic conversion traits"] -impl OwnedAsciiCast for String { - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } - - #[inline] - unsafe fn into_ascii_nocheck(self) -> Vec { unimplemented!() } -} - -#[experimental = "may be replaced by generic conversion traits"] -impl OwnedAsciiCast for Vec { - #[inline] - fn is_ascii(&self) -> bool { unimplemented!() } - - #[inline] - unsafe fn into_ascii_nocheck(self) -> Vec { unimplemented!() } -} - -/// Trait for converting an ascii type to a string. Needed to convert -/// `&[Ascii]` to `&str`. -#[experimental = "may be replaced by generic conversion traits"] -pub trait AsciiStr for Sized? { - /// Convert to a string. - fn as_str_ascii<'a>(&'a self) -> &'a str; - - /// Deprecated: use `to_lowercase` - #[deprecated="renamed `to_lowercase`"] - fn to_lower(&self) -> Vec; - - /// Convert to vector representing a lower cased ascii string. - #[deprecated = "use iterators instead"] - fn to_lowercase(&self) -> Vec; - - /// Deprecated: use `to_uppercase` - #[deprecated="renamed `to_uppercase`"] - fn to_upper(&self) -> Vec; - - /// Convert to vector representing a upper cased ascii string. - #[deprecated = "use iterators instead"] - fn to_uppercase(&self) -> Vec; - - /// Compares two Ascii strings ignoring case. - #[deprecated = "use iterators instead"] - fn eq_ignore_case(&self, other: &[Ascii]) -> bool; -} - -#[experimental = "may be replaced by generic conversion traits"] -impl AsciiStr for [Ascii] { - #[inline] - fn as_str_ascii<'a>(&'a self) -> &'a str { unimplemented!() } - - #[inline] - fn to_lower(&self) -> Vec { unimplemented!() } - - #[inline] - fn to_lowercase(&self) -> Vec { unimplemented!() } - - #[inline] - fn to_upper(&self) -> Vec { unimplemented!() } - - #[inline] - fn to_uppercase(&self) -> Vec { unimplemented!() } - - #[inline] - fn eq_ignore_case(&self, other: &[Ascii]) -> bool { unimplemented!() } -} - -impl IntoString for Vec { - #[inline] - fn into_string(self) -> String { unimplemented!() } -} - -/// Trait to convert to an owned byte vector by consuming self -#[experimental = "may be replaced by generic conversion traits"] -pub trait IntoBytes { - /// Converts to an owned byte vector by consuming self - fn into_bytes(self) -> Vec; -} - -#[experimental = "may be replaced by generic conversion traits"] -impl IntoBytes for Vec { - fn into_bytes(self) -> Vec { unimplemented!() } -} - - -/// Extension methods for ASCII-subset only operations on owned strings -#[experimental = "would prefer to do this in a more general way"] -pub trait OwnedAsciiExt { - /// Convert the string to ASCII upper case: - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - fn into_ascii_upper(self) -> Self; - - /// Convert the string to ASCII lower case: - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - fn into_ascii_lower(self) -> Self; -} - -/// Extension methods for ASCII-subset only operations on string slices -#[experimental = "would prefer to do this in a more general way"] -pub trait AsciiExt for Sized? { - /// Makes a copy of the string in ASCII upper case: - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - fn to_ascii_upper(&self) -> T; - - /// Makes a copy of the string in ASCII lower case: - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - fn to_ascii_lower(&self) -> T; - - /// Check that two strings are an ASCII case-insensitive match. - /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`, - /// but without allocating and copying temporary strings. - fn eq_ignore_ascii_case(&self, other: &Self) -> bool; -} - -#[experimental = "would prefer to do this in a more general way"] -impl AsciiExt for str { - #[inline] - fn to_ascii_upper(&self) -> String { unimplemented!() } - - #[inline] - fn to_ascii_lower(&self) -> String { unimplemented!() } - - #[inline] - fn eq_ignore_ascii_case(&self, other: &str) -> bool { unimplemented!() } -} - -#[experimental = "would prefer to do this in a more general way"] -impl OwnedAsciiExt for String { - #[inline] - fn into_ascii_upper(self) -> String { unimplemented!() } - - #[inline] - fn into_ascii_lower(self) -> String { unimplemented!() } -} - -#[experimental = "would prefer to do this in a more general way"] -impl AsciiExt> for [u8] { - #[inline] - fn to_ascii_upper(&self) -> Vec { unimplemented!() } - - #[inline] - fn to_ascii_lower(&self) -> Vec { unimplemented!() } - - #[inline] - fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { unimplemented!() } -} - -#[experimental = "would prefer to do this in a more general way"] -impl OwnedAsciiExt for Vec { - #[inline] - fn into_ascii_upper(mut self) -> Vec { unimplemented!() } - - #[inline] - fn into_ascii_lower(mut self) -> Vec { unimplemented!() } -} - -/// Returns a 'default' ASCII and C++11-like literal escape of a `u8` -/// -/// The default is chosen with a bias toward producing literals that are -/// legal in a variety of languages, including C++11 and similar C-family -/// languages. The exact rules are: -/// -/// - Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively. -/// - Single-quote, double-quote and backslash chars are backslash-escaped. -/// - Any other chars in the range [0x20,0x7e] are not escaped. -/// - Any other chars are given hex escapes. -/// - Unicode escapes are never generated by this function. -#[unstable = "needs to be updated to use an iterator"] -pub fn escape_default(c: u8, f: |u8|) { unimplemented!() } - -static ASCII_LOWER_MAP: [u8, ..0] = [ -]; - -static ASCII_UPPER_MAP: [u8, ..0] = [ -]; diff --git a/src/libst2/bitflags.rs b/src/libst2/bitflags.rs deleted file mode 100644 index d8023dd3e4e3b..0000000000000 --- a/src/libst2/bitflags.rs +++ /dev/null @@ -1,463 +0,0 @@ -// 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. - -#![experimental] -#![macro_escape] - -//! A typesafe bitmask flag generator. - -/// The `bitflags!` macro generates a `struct` that holds a set of C-style -/// bitmask flags. It is useful for creating typesafe wrappers for C APIs. -/// -/// The flags should only be defined for integer types, otherwise unexpected -/// type errors may occur at compile time. -/// -/// # Example -/// -/// ```{.rust} -/// bitflags! { -/// flags Flags: u32 { -/// const FLAG_A = 0x00000001, -/// const FLAG_B = 0x00000010, -/// const FLAG_C = 0x00000100, -/// const FLAG_ABC = FLAG_A.bits -/// | FLAG_B.bits -/// | FLAG_C.bits, -/// } -/// } -/// -/// fn main() { -/// let e1 = FLAG_A | FLAG_C; -/// let e2 = FLAG_B | FLAG_C; -/// assert!((e1 | e2) == FLAG_ABC); // union -/// assert!((e1 & e2) == FLAG_C); // intersection -/// assert!((e1 - e2) == FLAG_A); // set difference -/// assert!(!e2 == FLAG_A); // set complement -/// } -/// ``` -/// -/// The generated `struct`s can also be extended with type and trait implementations: -/// -/// ```{.rust} -/// use std::fmt; -/// -/// bitflags! { -/// flags Flags: u32 { -/// const FLAG_A = 0x00000001, -/// const FLAG_B = 0x00000010, -/// } -/// } -/// -/// impl Flags { -/// pub fn clear(&mut self) { -/// self.bits = 0; // The `bits` field can be accessed from within the -/// // same module where the `bitflags!` macro was invoked. -/// } -/// } -/// -/// impl fmt::Show for Flags { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -/// write!(f, "hi!") -/// } -/// } -/// -/// fn main() { -/// let mut flags = FLAG_A | FLAG_B; -/// flags.clear(); -/// assert!(flags.is_empty()); -/// assert_eq!(format!("{}", flags).as_slice(), "hi!"); -/// } -/// ``` -/// -/// # Attributes -/// -/// Attributes can be attached to the generated `struct` by placing them -/// before the `flags` keyword. -/// -/// # Derived traits -/// -/// The `PartialEq` and `Clone` traits are automatically derived for the `struct` using -/// the `deriving` attribute. Additional traits can be derived by providing an -/// explicit `deriving` attribute on `flags`. -/// -/// # Operators -/// -/// The following operator traits are implemented for the generated `struct`: -/// -/// - `BitOr`: union -/// - `BitAnd`: intersection -/// - `BitXor`: toggle -/// - `Sub`: set difference -/// - `Not`: set complement -/// -/// # Methods -/// -/// The following methods are defined for the generated `struct`: -/// -/// - `empty`: an empty set of flags -/// - `all`: the set of all flags -/// - `bits`: the raw value of the flags currently stored -/// - `is_empty`: `true` if no flags are currently stored -/// - `is_all`: `true` if all flags are currently set -/// - `intersects`: `true` if there are flags common to both `self` and `other` -/// - `contains`: `true` all of the flags in `other` are contained within `self` -/// - `insert`: inserts the specified flags in-place -/// - `remove`: removes the specified flags in-place -/// - `toggle`: the specified flags will be inserted if not present, and removed -/// if they are. -#[macro_export] -macro_rules! bitflags { - ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { - $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+ - }) => { - #[deriving(PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] - $(#[$attr])* - pub struct $BitFlags { - bits: $T, - } - - $($(#[$Flag_attr])* pub const $Flag: $BitFlags = $BitFlags { bits: $value };)+ - - impl $BitFlags { - /// Returns an empty set of flags. - #[inline] - pub fn empty() -> $BitFlags { - $BitFlags { bits: 0 } - } - - /// Returns the set containing all flags. - #[inline] - pub fn all() -> $BitFlags { - $BitFlags { bits: $($value)|+ } - } - - /// Returns the raw value of the flags currently stored. - #[inline] - pub fn bits(&self) -> $T { - self.bits - } - - /// Convert from underlying bit representation, unless that - /// representation contains bits that do not correspond to a flag. - #[inline] - pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { - if (bits & !$BitFlags::all().bits()) != 0 { - ::std::option::None - } else { - ::std::option::Some($BitFlags { bits: bits }) - } - } - - /// Convert from underlying bit representation, dropping any bits - /// that do not correspond to flags. - #[inline] - pub fn from_bits_truncate(bits: $T) -> $BitFlags { - $BitFlags { bits: bits } & $BitFlags::all() - } - - /// Returns `true` if no flags are currently stored. - #[inline] - pub fn is_empty(&self) -> bool { - *self == $BitFlags::empty() - } - - /// Returns `true` if all flags are currently set. - #[inline] - pub fn is_all(&self) -> bool { - *self == $BitFlags::all() - } - - /// Returns `true` if there are flags common to both `self` and `other`. - #[inline] - pub fn intersects(&self, other: $BitFlags) -> bool { - !(*self & other).is_empty() - } - - /// Returns `true` all of the flags in `other` are contained within `self`. - #[inline] - pub fn contains(&self, other: $BitFlags) -> bool { - (*self & other) == other - } - - /// Inserts the specified flags in-place. - #[inline] - pub fn insert(&mut self, other: $BitFlags) { - self.bits |= other.bits; - } - - /// Removes the specified flags in-place. - #[inline] - pub fn remove(&mut self, other: $BitFlags) { - self.bits &= !other.bits; - } - - /// Toggles the specified flags in-place. - #[inline] - pub fn toggle(&mut self, other: $BitFlags) { - self.bits ^= other.bits; - } - } - - impl BitOr<$BitFlags, $BitFlags> for $BitFlags { - /// Returns the union of the two sets of flags. - #[inline] - fn bitor(&self, other: &$BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits | other.bits } - } - } - - impl BitXor<$BitFlags, $BitFlags> for $BitFlags { - /// Returns the left flags, but with all the right flags toggled. - #[inline] - fn bitxor(&self, other: &$BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits ^ other.bits } - } - } - - impl BitAnd<$BitFlags, $BitFlags> for $BitFlags { - /// Returns the intersection between the two sets of flags. - #[inline] - fn bitand(&self, other: &$BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits & other.bits } - } - } - - impl Sub<$BitFlags, $BitFlags> for $BitFlags { - /// Returns the set difference of the two sets of flags. - #[inline] - fn sub(&self, other: &$BitFlags) -> $BitFlags { - $BitFlags { bits: self.bits & !other.bits } - } - } - - impl Not<$BitFlags> for $BitFlags { - /// Returns the complement of this set of flags. - #[inline] - fn not(&self) -> $BitFlags { - $BitFlags { bits: !self.bits } & $BitFlags::all() - } - } - }; - ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty { - $($(#[$Flag_attr:meta])* const $Flag:ident = $value:expr),+, - }) => { - bitflags! { - $(#[$attr])* - flags $BitFlags: $T { - $($(#[$Flag_attr])* const $Flag = $value),+ - } - } - }; -} - -#[cfg(test)] -#[allow(non_upper_case_globals)] -mod tests { - use hash; - use option::{Some, None}; - use ops::{BitOr, BitAnd, BitXor, Sub, Not}; - - bitflags! { - #[doc = "> The first principle is that you must not fool yourself — and"] - #[doc = "> you are the easiest person to fool."] - #[doc = "> "] - #[doc = "> - Richard Feynman"] - flags Flags: u32 { - const FlagA = 0x00000001, - #[doc = " macros are way better at generating code than trans is"] - const FlagB = 0x00000010, - const FlagC = 0x00000100, - #[doc = "* cmr bed"] - #[doc = "* strcat table"] - #[doc = " wait what?"] - const FlagABC = FlagA.bits - | FlagB.bits - | FlagC.bits, - } - } - - bitflags! { - flags AnotherSetOfFlags: i8 { - const AnotherFlag = -1_i8, - } - } - - #[test] - fn test_bits(){ - assert_eq!(Flags::empty().bits(), 0x00000000); - assert_eq!(FlagA.bits(), 0x00000001); - assert_eq!(FlagABC.bits(), 0x00000111); - - assert_eq!(AnotherSetOfFlags::empty().bits(), 0x00); - assert_eq!(AnotherFlag.bits(), !0_i8); - } - - #[test] - fn test_from_bits() { - assert!(Flags::from_bits(0) == Some(Flags::empty())); - assert!(Flags::from_bits(0x1) == Some(FlagA)); - assert!(Flags::from_bits(0x10) == Some(FlagB)); - assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB)); - assert!(Flags::from_bits(0x1000) == None); - - assert!(AnotherSetOfFlags::from_bits(!0_i8) == Some(AnotherFlag)); - } - - #[test] - fn test_from_bits_truncate() { - assert!(Flags::from_bits_truncate(0) == Flags::empty()); - assert!(Flags::from_bits_truncate(0x1) == FlagA); - assert!(Flags::from_bits_truncate(0x10) == FlagB); - assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB)); - assert!(Flags::from_bits_truncate(0x1000) == Flags::empty()); - assert!(Flags::from_bits_truncate(0x1001) == FlagA); - - assert!(AnotherSetOfFlags::from_bits_truncate(0_i8) == AnotherSetOfFlags::empty()); - } - - #[test] - fn test_is_empty(){ - assert!(Flags::empty().is_empty()); - assert!(!FlagA.is_empty()); - assert!(!FlagABC.is_empty()); - - assert!(!AnotherFlag.is_empty()); - } - - #[test] - fn test_is_all() { - assert!(Flags::all().is_all()); - assert!(!FlagA.is_all()); - assert!(FlagABC.is_all()); - - assert!(AnotherFlag.is_all()); - } - - #[test] - fn test_two_empties_do_not_intersect() { - let e1 = Flags::empty(); - let e2 = Flags::empty(); - assert!(!e1.intersects(e2)); - - assert!(AnotherFlag.intersects(AnotherFlag)); - } - - #[test] - fn test_empty_does_not_intersect_with_full() { - let e1 = Flags::empty(); - let e2 = FlagABC; - assert!(!e1.intersects(e2)); - } - - #[test] - fn test_disjoint_intersects() { - let e1 = FlagA; - let e2 = FlagB; - assert!(!e1.intersects(e2)); - } - - #[test] - fn test_overlapping_intersects() { - let e1 = FlagA; - let e2 = FlagA | FlagB; - assert!(e1.intersects(e2)); - } - - #[test] - fn test_contains() { - let e1 = FlagA; - let e2 = FlagA | FlagB; - assert!(!e1.contains(e2)); - assert!(e2.contains(e1)); - assert!(FlagABC.contains(e2)); - - assert!(AnotherFlag.contains(AnotherFlag)); - } - - #[test] - fn test_insert(){ - let mut e1 = FlagA; - let e2 = FlagA | FlagB; - e1.insert(e2); - assert!(e1 == e2); - - let mut e3 = AnotherSetOfFlags::empty(); - e3.insert(AnotherFlag); - assert!(e3 == AnotherFlag); - } - - #[test] - fn test_remove(){ - let mut e1 = FlagA | FlagB; - let e2 = FlagA | FlagC; - e1.remove(e2); - assert!(e1 == FlagB); - - let mut e3 = AnotherFlag; - e3.remove(AnotherFlag); - assert!(e3 == AnotherSetOfFlags::empty()); - } - - #[test] - fn test_operators() { - let e1 = FlagA | FlagC; - let e2 = FlagB | FlagC; - assert!((e1 | e2) == FlagABC); // union - assert!((e1 & e2) == FlagC); // intersection - assert!((e1 - e2) == FlagA); // set difference - assert!(!e2 == FlagA); // set complement - assert!(e1 ^ e2 == FlagA | FlagB); // toggle - let mut e3 = e1; - e3.toggle(e2); - assert!(e3 == FlagA | FlagB); - - let mut m4 = AnotherSetOfFlags::empty(); - m4.toggle(AnotherSetOfFlags::empty()); - assert!(m4 == AnotherSetOfFlags::empty()); - } - - #[test] - fn test_lt() { - let mut a = Flags::empty(); - let mut b = Flags::empty(); - - assert!(!(a < b) && !(b < a)); - b = FlagB; - assert!(a < b); - a = FlagC; - assert!(!(a < b) && b < a); - b = FlagC | FlagB; - assert!(a < b); - } - - #[test] - fn test_ord() { - let mut a = Flags::empty(); - let mut b = Flags::empty(); - - assert!(a <= b && a >= b); - a = FlagA; - assert!(a > b && a >= b); - assert!(b < a && b <= a); - b = FlagB; - assert!(b > a && b >= a); - assert!(a < b && a <= b); - } - - #[test] - fn test_hash() { - let mut x = Flags::empty(); - let mut y = Flags::empty(); - assert!(hash::hash(&x) == hash::hash(&y)); - x = Flags::all(); - y = FlagABC; - assert!(hash::hash(&x) == hash::hash(&y)); - } -} diff --git a/src/libst2/c_vec.rs b/src/libst2/c_vec.rs deleted file mode 100644 index 6e817956476e2..0000000000000 --- a/src/libst2/c_vec.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Library to interface with chunks of memory allocated in C. -//! -//! It is often desirable to safely interface with memory allocated from C, -//! encapsulating the unsafety into allocation and destruction time. Indeed, -//! allocating memory externally is currently the only way to give Rust shared -//! mut state with C programs that keep their own references; vectors are -//! unsuitable because they could be reallocated or moved at any time, and -//! importing C memory into a vector takes a one-time snapshot of the memory. -//! -//! This module simplifies the usage of such external blocks of memory. Memory -//! is encapsulated into an opaque object after creation; the lifecycle of the -//! memory can be optionally managed by Rust, if an appropriate destructor -//! closure is provided. Safety is ensured by bounds-checking accesses, which -//! are marshalled through get and set functions. -//! -//! There are three unsafe functions: the two constructors, and the -//! unwrap method. The constructors are unsafe for the -//! obvious reason (they act on a pointer that cannot be checked inside the -//! method), but `unwrap()` is somewhat more subtle in its unsafety. -//! It returns the contained pointer, but at the same time destroys the CVec -//! without running its destructor. This can be used to pass memory back to -//! C, but care must be taken that the ownership of underlying resources are -//! handled correctly, i.e. that allocated memory is eventually freed -//! if necessary. - -#![experimental] - -use kinds::Send; -use mem; -use ops::Drop; -use option::{Option, Some, None}; -use ptr::RawPtr; -use ptr; -use raw; -use slice::AsSlice; - -/// The type representing a foreign chunk of memory -pub struct CVec { - base: *mut T, - len: uint, - dtor: Option, -} - -#[unsafe_destructor] -impl Drop for CVec { - fn drop(&mut self) { unimplemented!() } -} - -impl CVec { - /// Create a `CVec` from a raw pointer to a buffer with a given length. - /// - /// Panics if the given pointer is null. The returned vector will not attempt - /// to deallocate the vector when dropped. - /// - /// # Arguments - /// - /// * base - A raw pointer to a buffer - /// * len - The number of elements in the buffer - pub unsafe fn new(base: *mut T, len: uint) -> CVec { unimplemented!() } - - /// Create a `CVec` from a foreign buffer, with a given length, - /// and a function to run upon destruction. - /// - /// Panics if the given pointer is null. - /// - /// # Arguments - /// - /// * base - A foreign pointer to a buffer - /// * len - The number of elements in the buffer - /// * dtor - A proc to run when the value is destructed, useful - /// for freeing the buffer, etc. - pub unsafe fn new_with_dtor(base: *mut T, len: uint, - dtor: proc():Send) -> CVec { unimplemented!() } - - /// View the stored data as a mutable slice. - pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { unimplemented!() } - - /// Retrieves an element at a given index, returning `None` if the requested - /// index is greater than the length of the vector. - pub fn get<'a>(&'a self, ofs: uint) -> Option<&'a T> { unimplemented!() } - - /// Retrieves a mutable element at a given index, returning `None` if the - /// requested index is greater than the length of the vector. - pub fn get_mut<'a>(&'a mut self, ofs: uint) -> Option<&'a mut T> { unimplemented!() } - - /// Unwrap the pointer without running the destructor - /// - /// This method retrieves the underlying pointer, and in the process - /// destroys the CVec but without running the destructor. A use case - /// would be transferring ownership of the buffer to a C function, as - /// in this case you would not want to run the destructor. - /// - /// Note that if you want to access the underlying pointer without - /// cancelling the destructor, you can simply call `transmute` on the return - /// value of `get(0)`. - pub unsafe fn unwrap(mut self) -> *mut T { unimplemented!() } - - /// Returns the number of items in this vector. - pub fn len(&self) -> uint { unimplemented!() } - - /// Returns whether this vector is empty. - pub fn is_empty(&self) -> bool { unimplemented!() } -} - -impl AsSlice for CVec { - /// View the stored data as a slice. - fn as_slice<'a>(&'a self) -> &'a [T] { unimplemented!() } -} diff --git a/src/libst2/collections/hash/bench.rs b/src/libst2/collections/hash/bench.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/libst2/collections/hash/map.rs b/src/libst2/collections/hash/map.rs deleted file mode 100644 index 3c5d703a22e12..0000000000000 --- a/src/libst2/collections/hash/map.rs +++ /dev/null @@ -1,880 +0,0 @@ -// 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. -// -// ignore-lexer-test FIXME #15883 - -pub use self::Entry::*; -use self::SearchResult::*; -use self::VacantEntryState::*; - -use borrow::BorrowFrom; -use clone::Clone; -use cmp::{max, Eq, Equiv, PartialEq}; -use default::Default; -use fmt::{mod, Show}; -use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{mod, Iterator, FromIterator, Extend}; -use kinds::Sized; -use mem::{mod, replace}; -use num::UnsignedInt; -use ops::{Deref, Index, IndexMut}; -use option::{Some, None, Option}; -use result::{Result, Ok, Err}; - -use super::table; -use super::table::{ - Bucket, - Empty, - EmptyBucket, - Full, - FullBucket, - FullBucketImm, - FullBucketMut, - RawTable, - SafeHash -}; - -// FIXME(conventions): update capacity management to match other collections (no auto-shrink) - -const INITIAL_LOG2_CAP: uint = 5; -pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5 - -/// The default behavior of HashMap implements a load factor of 90.9%. -/// This behavior is characterized by the following conditions: -/// -/// - if size > 0.909 * capacity: grow -/// - if size < 0.25 * capacity: shrink (if this won't bring capacity lower -/// than the minimum) -#[deriving(Clone)] -struct DefaultResizePolicy { - /// Doubled minimal capacity. The capacity must never drop below - /// the minimum capacity. (The check happens before the capacity - /// is potentially halved.) - minimum_capacity2: uint -} - -impl DefaultResizePolicy { - fn new(new_capacity: uint) -> DefaultResizePolicy { unimplemented!() } - - #[inline] - fn capacity_range(&self, new_size: uint) -> (uint, uint) { unimplemented!() } - - #[inline] - fn reserve(&mut self, new_capacity: uint) { unimplemented!() } -} - -// The main performance trick in this hashmap is called Robin Hood Hashing. -// It gains its excellent performance from one essential operation: -// -// If an insertion collides with an existing element, and that element's -// "probe distance" (how far away the element is from its ideal location) -// is higher than how far we've already probed, swap the elements. -// -// This massively lowers variance in probe distance, and allows us to get very -// high load factors with good performance. The 90% load factor I use is rather -// conservative. -// -// > Why a load factor of approximately 90%? -// -// In general, all the distances to initial buckets will converge on the mean. -// At a load factor of α, the odds of finding the target bucket after k -// probes is approximately 1-α^k. If we set this equal to 50% (since we converge -// on the mean) and set k=8 (64-byte cache line / 8-byte hash), α=0.92. I round -// this down to make the math easier on the CPU and avoid its FPU. -// Since on average we start the probing in the middle of a cache line, this -// strategy pulls in two cache lines of hashes on every lookup. I think that's -// pretty good, but if you want to trade off some space, it could go down to one -// cache line on average with an α of 0.84. -// -// > Wait, what? Where did you get 1-α^k from? -// -// On the first probe, your odds of a collision with an existing element is α. -// The odds of doing this twice in a row is approximately α^2. For three times, -// α^3, etc. Therefore, the odds of colliding k times is α^k. The odds of NOT -// colliding after k tries is 1-α^k. -// -// The paper from 1986 cited below mentions an implementation which keeps track -// of the distance-to-initial-bucket histogram. This approach is not suitable -// for modern architectures because it requires maintaining an internal data -// structure. This allows very good first guesses, but we are most concerned -// with guessing entire cache lines, not individual indexes. Furthermore, array -// accesses are no longer linear and in one direction, as we have now. There -// is also memory and cache pressure that this would entail that would be very -// difficult to properly see in a microbenchmark. -// -// ## Future Improvements (FIXME!) -// -// Allow the load factor to be changed dynamically and/or at initialization. -// -// Also, would it be possible for us to reuse storage when growing the -// underlying table? This is exactly the use case for 'realloc', and may -// be worth exploring. -// -// ## Future Optimizations (FIXME!) -// -// Another possible design choice that I made without any real reason is -// parameterizing the raw table over keys and values. Technically, all we need -// is the size and alignment of keys and values, and the code should be just as -// efficient (well, we might need one for power-of-two size and one for not...). -// This has the potential to reduce code bloat in rust executables, without -// really losing anything except 4 words (key size, key alignment, val size, -// val alignment) which can be passed in to every call of a `RawTable` function. -// This would definitely be an avenue worth exploring if people start complaining -// about the size of rust executables. -// -// Annotate exceedingly likely branches in `table::make_hash` -// and `search_hashed` to reduce instruction cache pressure -// and mispredictions once it becomes possible (blocked on issue #11092). -// -// Shrinking the table could simply reallocate in place after moving buckets -// to the first half. -// -// The growth algorithm (fragment of the Proof of Correctness) -// -------------------- -// -// The growth algorithm is basically a fast path of the naive reinsertion- -// during-resize algorithm. Other paths should never be taken. -// -// Consider growing a robin hood hashtable of capacity n. Normally, we do this -// by allocating a new table of capacity `2n`, and then individually reinsert -// each element in the old table into the new one. This guarantees that the -// new table is a valid robin hood hashtable with all the desired statistical -// properties. Remark that the order we reinsert the elements in should not -// matter. For simplicity and efficiency, we will consider only linear -// reinsertions, which consist of reinserting all elements in the old table -// into the new one by increasing order of index. However we will not be -// starting our reinsertions from index 0 in general. If we start from index -// i, for the purpose of reinsertion we will consider all elements with real -// index j < i to have virtual index n + j. -// -// Our hash generation scheme consists of generating a 64-bit hash and -// truncating the most significant bits. When moving to the new table, we -// simply introduce a new bit to the front of the hash. Therefore, if an -// elements has ideal index i in the old table, it can have one of two ideal -// locations in the new table. If the new bit is 0, then the new ideal index -// is i. If the new bit is 1, then the new ideal index is n + i. Intutively, -// we are producing two independent tables of size n, and for each element we -// independently choose which table to insert it into with equal probability. -// However the rather than wrapping around themselves on overflowing their -// indexes, the first table overflows into the first, and the first into the -// second. Visually, our new table will look something like: -// -// [yy_xxx_xxxx_xxx|xx_yyy_yyyy_yyy] -// -// Where x's are elements inserted into the first table, y's are elements -// inserted into the second, and _'s are empty sections. We now define a few -// key concepts that we will use later. Note that this is a very abstract -// perspective of the table. A real resized table would be at least half -// empty. -// -// Theorem: A linear robin hood reinsertion from the first ideal element -// produces identical results to a linear naive reinsertion from the same -// element. -// -// FIXME(Gankro, pczarn): review the proof and put it all in a separate doc.rs - -/// A hash map implementation which uses linear probing with Robin -/// Hood bucket stealing. -/// -/// The hashes are all keyed by the task-local random number generator -/// on creation by default. This means that the ordering of the keys is -/// randomized, but makes the tables more resistant to -/// denial-of-service attacks (Hash DoS). This behaviour can be -/// overridden with one of the constructors. -/// -/// It is required that the keys implement the `Eq` and `Hash` traits, although -/// this can frequently be achieved by using `#[deriving(Eq, Hash)]`. -/// -/// Relevant papers/articles: -/// -/// 1. Pedro Celis. ["Robin Hood Hashing"](https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf) -/// 2. Emmanuel Goossaert. ["Robin Hood -/// hashing"](http://codecapsule.com/2013/11/11/robin-hood-hashing/) -/// 3. Emmanuel Goossaert. ["Robin Hood hashing: backward shift -/// deletion"](http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/) -/// -/// # Example -/// -/// ``` -/// use std::collections::HashMap; -/// -/// // type inference lets us omit an explicit type signature (which -/// // would be `HashMap<&str, &str>` in this example). -/// let mut book_reviews = HashMap::new(); -/// -/// // review some books. -/// book_reviews.insert("Adventures of Huckleberry Finn", "My favorite book."); -/// book_reviews.insert("Grimms' Fairy Tales", "Masterpiece."); -/// book_reviews.insert("Pride and Prejudice", "Very enjoyable."); -/// book_reviews.insert("The Adventures of Sherlock Holmes", "Eye lyked it alot."); -/// -/// // check for a specific one. -/// if !book_reviews.contains_key(&("Les Misérables")) { -/// println!("We've got {} reviews, but Les Misérables ain't one.", -/// book_reviews.len()); -/// } -/// -/// // oops, this review has a lot of spelling mistakes, let's delete it. -/// book_reviews.remove(&("The Adventures of Sherlock Holmes")); -/// -/// // look up the values associated with some keys. -/// let to_find = ["Pride and Prejudice", "Alice's Adventure in Wonderland"]; -/// for book in to_find.iter() { -/// match book_reviews.get(book) { -/// Some(review) => println!("{}: {}", *book, *review), -/// None => println!("{} is unreviewed.", *book) -/// } -/// } -/// -/// // iterate over everything. -/// for (book, review) in book_reviews.iter() { -/// println!("{}: \"{}\"", *book, *review); -/// } -/// ``` -/// -/// The easiest way to use `HashMap` with a custom type is to derive `Eq` and `Hash`. -/// We must also derive `PartialEq`. -/// -/// ``` -/// use std::collections::HashMap; -/// -/// #[deriving(Hash, Eq, PartialEq, Show)] -/// struct Viking<'a> { -/// name: &'a str, -/// power: uint, -/// } -/// -/// let mut vikings = HashMap::new(); -/// -/// vikings.insert("Norway", Viking { name: "Einar", power: 9u }); -/// vikings.insert("Denmark", Viking { name: "Olaf", power: 4u }); -/// vikings.insert("Iceland", Viking { name: "Harald", power: 8u }); -/// -/// // Use derived implementation to print the vikings. -/// for (land, viking) in vikings.iter() { -/// println!("{} at {}", viking, land); -/// } -/// ``` -#[deriving(Clone)] -pub struct HashMap { - // All hashes are keyed on these values, to prevent hash collision attacks. - hasher: H, - - table: RawTable, - - // We keep this at the end since it might as well have tail padding. - resize_policy: DefaultResizePolicy, -} - -/// Search for a pre-hashed key. -fn search_hashed>>(table: M, - hash: &SafeHash, - is_match: |&K| -> bool) - -> SearchResult { unimplemented!() } - -fn pop_internal(starting_bucket: FullBucketMut) -> (K, V) { unimplemented!() } - -/// Perform robin hood bucket stealing at the given `bucket`. You must -/// also pass the position of that bucket's initial bucket so we don't have -/// to recalculate it. -/// -/// `hash`, `k`, and `v` are the elements to "robin hood" into the hashtable. -fn robin_hood<'a, K: 'a, V: 'a>(mut bucket: FullBucketMut<'a, K, V>, - mut ib: uint, - mut hash: SafeHash, - mut k: K, - mut v: V) - -> &'a mut V { unimplemented!() } - -/// A result that works like Option> but preserves -/// the reference that grants us access to the table in any case. -enum SearchResult { - // This is an entry that holds the given key: - FoundExisting(FullBucket), - - // There was no such entry. The reference is given back: - TableRef(M) -} - -impl SearchResult { - fn into_option(self) -> Option> { unimplemented!() } -} - -impl, V, S, H: Hasher> HashMap { - fn make_hash>(&self, x: &X) -> SafeHash { unimplemented!() } - - fn search_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, q: &Q) - -> Option> { unimplemented!() } - - fn search_equiv_mut<'a, Sized? Q: Hash + Equiv>(&'a mut self, q: &Q) - -> Option> { unimplemented!() } - - /// Search for a key, yielding the index if it's found in the hashtable. - /// If you already have the hash for the key lying around, use - /// search_hashed. - fn search<'a, Sized? Q>(&'a self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash - { unimplemented!() } - - fn search_mut<'a, Sized? Q>(&'a mut self, q: &Q) -> Option> - where Q: BorrowFrom + Eq + Hash - { unimplemented!() } - - // The caller should ensure that invariants by Robin Hood Hashing hold. - fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) { unimplemented!() } -} - -impl HashMap { - /// Create an empty HashMap. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, int> = HashMap::new(); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new() -> HashMap { unimplemented!() } - - /// Creates an empty hash map with the given initial capacity. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, int> = HashMap::with_capacity(10); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn with_capacity(capacity: uint) -> HashMap { unimplemented!() } -} - -impl, V, S, H: Hasher> HashMap { - /// Creates an empty hashmap which will use the given hasher to hash keys. - /// - /// The creates map has the default initial capacity. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; - /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_hasher(h); - /// map.insert(1i, 2u); - /// ``` - #[inline] - pub fn with_hasher(hasher: H) -> HashMap { unimplemented!() } - - /// Create an empty HashMap with space for at least `capacity` - /// elements, using `hasher` to hash the keys. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow HashMaps to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// use std::hash::sip::SipHasher; - /// - /// let h = SipHasher::new(); - /// let mut map = HashMap::with_capacity_and_hasher(10, h); - /// map.insert(1i, 2u); - /// ``` - #[inline] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashMap { unimplemented!() } - - /// The hashtable will never try to shrink below this size. You can use - /// this function to reduce reallocations if your hashtable frequently - /// grows and shrinks by large amounts. - /// - /// This function has no effect on the operational semantics of the - /// hashtable, only on performance. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// let mut map: HashMap<&str, int> = HashMap::new(); - /// map.reserve(10); - /// ``` - pub fn reserve(&mut self, new_minimum_capacity: uint) { unimplemented!() } - - /// Resizes the internal vectors to a new capacity. It's your responsibility to: - /// 1) Make sure the new capacity is enough for all the elements, accounting - /// for the load factor. - /// 2) Ensure new_capacity is a power of two. - fn resize(&mut self, new_capacity: uint) { unimplemented!() } - - /// Performs any necessary resize operations, such that there's space for - /// new_size elements. - fn make_some_room(&mut self, new_size: uint) { unimplemented!() } - - /// Insert a pre-hashed key-value pair, without first checking - /// that there's enough room in the buckets. Returns a reference to the - /// newly insert value. - /// - /// If the key already exists, the hashtable will be returned untouched - /// and a reference to the existing element will be returned. - fn insert_hashed_nocheck(&mut self, hash: SafeHash, k: K, v: V) -> &mut V { unimplemented!() } - - fn insert_or_replace_with<'a>(&'a mut self, - hash: SafeHash, - k: K, - v: V, - found_existing: |&mut K, &mut V, V|) - -> &'a mut V { unimplemented!() } - - /// Deprecated: use `contains_key` and `BorrowFrom` instead. - #[deprecated = "use contains_key and BorrowFrom instead"] - pub fn contains_key_equiv + Equiv>(&self, key: &Q) -> bool { unimplemented!() } - - /// Deprecated: use `get` and `BorrowFrom` instead. - #[deprecated = "use get and BorrowFrom instead"] - pub fn find_equiv<'a, Sized? Q: Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { unimplemented!() } - - /// Deprecated: use `remove` and `BorrowFrom` instead. - #[deprecated = "use remove and BorrowFrom instead"] - pub fn pop_equiv + Equiv>(&mut self, k: &Q) -> Option { unimplemented!() } - - /// An iterator visiting all keys in arbitrary order. - /// Iterator element type is `&'a K`. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1i); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for key in map.keys() { - /// println!("{}", key); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn keys(&self) -> Keys { unimplemented!() } - - /// An iterator visiting all values in arbitrary order. - /// Iterator element type is `&'a V`. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1i); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for key in map.values() { - /// println!("{}", key); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn values(&self) -> Values { unimplemented!() } - - /// An iterator visiting all key-value pairs in arbitrary order. - /// Iterator element type is `(&'a K, &'a V)`. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1i); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// for (key, val) in map.iter() { - /// println!("key: {} val: {}", key, val); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn iter(&self) -> Entries { unimplemented!() } - - /// An iterator visiting all key-value pairs in arbitrary order, - /// with mutable references to the values. - /// Iterator element type is `(&'a K, &'a mut V)`. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1i); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // Update all values - /// for (_, val) in map.iter_mut() { - /// *val *= 2; - /// } - /// - /// for (key, val) in map.iter() { - /// println!("key: {} val: {}", key, val); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn iter_mut(&mut self) -> MutEntries { unimplemented!() } - - /// Creates a consuming iterator, that is, one that moves each key-value - /// pair out of the map in arbitrary order. The map cannot be used after - /// calling this. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert("a", 1i); - /// map.insert("b", 2); - /// map.insert("c", 3); - /// - /// // Not possible with .iter() - /// let vec: Vec<(&str, int)> = map.into_iter().collect(); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn into_iter(self) -> MoveEntries { unimplemented!() } - - /// Gets the given key's corresponding entry in the map for in-place manipulation - pub fn entry<'a>(&'a mut self, key: K) -> Entry<'a, K, V> { unimplemented!() } - - /// Return the number of elements in the map. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// assert_eq!(a.len(), 0); - /// a.insert(1u, "a"); - /// assert_eq!(a.len(), 1); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn len(&self) -> uint { unimplemented!() } - - /// Return true if the map contains no elements. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// assert!(a.is_empty()); - /// a.insert(1u, "a"); - /// assert!(!a.is_empty()); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_empty(&self) -> bool { unimplemented!() } - - /// Clears the map, removing all key-value pairs. Keeps the allocated memory - /// for reuse. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut a = HashMap::new(); - /// a.insert(1u, "a"); - /// a.clear(); - /// assert!(a.is_empty()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn clear(&mut self) { unimplemented!() } - - /// Deprecated: Renamed to `get`. - #[deprecated = "Renamed to `get`"] - pub fn find(&self, k: &K) -> Option<&V> { unimplemented!() } - - /// Returns a reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the key type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1u, "a"); - /// assert_eq!(map.get(&1), Some(&"a")); - /// assert_eq!(map.get(&2), None); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn get(&self, k: &Q) -> Option<&V> - where Q: Hash + Eq + BorrowFrom - { unimplemented!() } - - /// Returns true if the map contains a value for the specified key. - /// - /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the key type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1u, "a"); - /// assert_eq!(map.contains_key(&1), true); - /// assert_eq!(map.contains_key(&2), false); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn contains_key(&self, k: &Q) -> bool - where Q: Hash + Eq + BorrowFrom - { unimplemented!() } - - /// Deprecated: Renamed to `get_mut`. - #[deprecated = "Renamed to `get_mut`"] - pub fn find_mut(&mut self, k: &K) -> Option<&mut V> { unimplemented!() } - - /// Returns a mutable reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the key type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1u, "a"); - /// match map.get_mut(&1) { - /// Some(x) => *x = "b", - /// None => (), - /// } - /// assert_eq!(map[1], "b"); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn get_mut(&mut self, k: &Q) -> Option<&mut V> - where Q: Hash + Eq + BorrowFrom - { unimplemented!() } - - /// Deprecated: Renamed to `insert`. - #[deprecated = "Renamed to `insert`"] - pub fn swap(&mut self, k: K, v: V) -> Option { unimplemented!() } - - /// Inserts a key-value pair from the map. If the key already had a value - /// present in the map, that value is returned. Otherwise, `None` is returned. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// assert_eq!(map.insert(37u, "a"), None); - /// assert_eq!(map.is_empty(), false); - /// - /// map.insert(37, "b"); - /// assert_eq!(map.insert(37, "c"), Some("b")); - /// assert_eq!(map[37], "c"); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn insert(&mut self, k: K, v: V) -> Option { unimplemented!() } - - /// Deprecated: Renamed to `remove`. - #[deprecated = "Renamed to `remove`"] - pub fn pop(&mut self, k: &K) -> Option { unimplemented!() } - - /// Removes a key from the map, returning the value at the key if the key - /// was previously in the map. - /// - /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the key type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashMap; - /// - /// let mut map = HashMap::new(); - /// map.insert(1u, "a"); - /// assert_eq!(map.remove(&1), Some("a")); - /// assert_eq!(map.remove(&1), None); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn remove(&mut self, k: &Q) -> Option - where Q: Hash + Eq + BorrowFrom - { unimplemented!() } -} - -fn search_entry_hashed<'a, K: Eq, V>(table: &'a mut RawTable, hash: SafeHash, k: K) - -> Entry<'a, K, V> { unimplemented!() } - -impl, V: Clone, S, H: Hasher> HashMap { - /// Deprecated: Use `map.get(k).cloned()`. - /// - /// Return a copy of the value corresponding to the key. - #[deprecated = "Use `map.get(k).cloned()`"] - pub fn find_copy(&self, k: &K) -> Option { unimplemented!() } - - /// Deprecated: Use `map[k].clone()`. - /// - /// Return a copy of the value corresponding to the key. - #[deprecated = "Use `map[k].clone()`"] - pub fn get_copy(&self, k: &K) -> V { unimplemented!() } -} - -impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap { - fn eq(&self, other: &HashMap) -> bool { unimplemented!() } -} - -impl, V: Eq, S, H: Hasher> Eq for HashMap {} - -impl + Show, V: Show, S, H: Hasher> Show for HashMap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl, V, S, H: Hasher + Default> Default for HashMap { - fn default() -> HashMap { unimplemented!() } -} - -impl + Eq, Sized? Q, V, S, H: Hasher> Index for HashMap - where Q: BorrowFrom + Hash + Eq -{ - #[inline] - fn index<'a>(&'a self, index: &Q) -> &'a V { unimplemented!() } -} - -impl + Eq, Sized? Q, V, S, H: Hasher> IndexMut for HashMap - where Q: BorrowFrom + Hash + Eq -{ - #[inline] - fn index_mut<'a>(&'a mut self, index: &Q) -> &'a mut V { unimplemented!() } -} - -/// HashMap iterator -pub struct Entries<'a, K: 'a, V: 'a> { - inner: table::Entries<'a, K, V> -} - -/// HashMap mutable values iterator -pub struct MutEntries<'a, K: 'a, V: 'a> { - inner: table::MutEntries<'a, K, V> -} - -/// HashMap move iterator -pub struct MoveEntries { - inner: iter::Map<'static, (SafeHash, K, V), (K, V), table::MoveEntries> -} - -/// A view into a single occupied location in a HashMap -pub struct OccupiedEntry<'a, K:'a, V:'a> { - elem: FullBucket>, -} - -/// A view into a single empty location in a HashMap -pub struct VacantEntry<'a, K:'a, V:'a> { - hash: SafeHash, - key: K, - elem: VacantEntryState>, -} - -/// A view into a single location in a map, which may be vacant or occupied -pub enum Entry<'a, K:'a, V:'a> { - /// An occupied Entry - Occupied(OccupiedEntry<'a, K, V>), - /// A vacant Entry - Vacant(VacantEntry<'a, K, V>), -} - -/// Possible states of a VacantEntry -enum VacantEntryState { - /// The index is occupied, but the key to insert has precedence, - /// and will kick the current one out on insertion - NeqElem(FullBucket, uint), - /// The index is genuinely vacant - NoElem(EmptyBucket), -} - -impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a V)> { unimplemented!() } - #[inline] - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { - #[inline] - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { unimplemented!() } - #[inline] - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl Iterator<(K, V)> for MoveEntries { - #[inline] - fn next(&mut self) -> Option<(K, V)> { unimplemented!() } - #[inline] - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl<'a, K, V> OccupiedEntry<'a, K, V> { - /// Gets a reference to the value in the entry - pub fn get(&self) -> &V { unimplemented!() } - - /// Gets a mutable reference to the value in the entry - pub fn get_mut(&mut self) -> &mut V { unimplemented!() } - - /// Converts the OccupiedEntry into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself - pub fn into_mut(self) -> &'a mut V { unimplemented!() } - - /// Sets the value of the entry, and returns the entry's old value - pub fn set(&mut self, mut value: V) -> V { unimplemented!() } - - /// Takes the value out of the entry, and returns it - pub fn take(self) -> V { unimplemented!() } -} - -impl<'a, K, V> VacantEntry<'a, K, V> { - /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it - pub fn set(self, value: V) -> &'a mut V { unimplemented!() } -} - -/// HashMap keys iterator -pub type Keys<'a, K, V> = - iter::Map<'static, (&'a K, &'a V), &'a K, Entries<'a, K, V>>; - -/// HashMap values iterator -pub type Values<'a, K, V> = - iter::Map<'static, (&'a K, &'a V), &'a V, Entries<'a, K, V>>; - -impl, V, S, H: Hasher + Default> FromIterator<(K, V)> for HashMap { - fn from_iter>(iter: T) -> HashMap { unimplemented!() } -} - -impl, V, S, H: Hasher + Default> Extend<(K, V)> for HashMap { - fn extend>(&mut self, mut iter: T) { unimplemented!() } -} diff --git a/src/libst2/collections/hash/mod.rs b/src/libst2/collections/hash/mod.rs deleted file mode 100644 index fa3f2d15d9dc3..0000000000000 --- a/src/libst2/collections/hash/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -// 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. - -//! Unordered containers, implemented as hash-tables - -pub mod map; -pub mod set; -mod table; diff --git a/src/libst2/collections/hash/set.rs b/src/libst2/collections/hash/set.rs deleted file mode 100644 index 262e0f46ab25e..0000000000000 --- a/src/libst2/collections/hash/set.rs +++ /dev/null @@ -1,519 +0,0 @@ -// 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. -// -// ignore-lexer-test FIXME #15883 - -use borrow::BorrowFrom; -use cmp::{Eq, Equiv, PartialEq}; -use core::kinds::Sized; -use default::Default; -use fmt::Show; -use fmt; -use hash::{Hash, Hasher, RandomSipHasher}; -use iter::{Iterator, FromIterator, FilterMap, Chain, Repeat, Zip, Extend}; -use iter; -use option::{Some, None}; -use result::{Ok, Err}; - -use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY}; - -// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub -// FIXME(conventions): update capacity management to match other collections (no auto-shrink) - - -// Future Optimization (FIXME!) -// ============================= -// -// Iteration over zero sized values is a noop. There is no need -// for `bucket.val` in the case of HashSet. I suppose we would need HKT -// to get rid of it properly. - -/// An implementation of a hash set using the underlying representation of a -/// HashMap where the value is (). As with the `HashMap` type, a `HashSet` -/// requires that the elements implement the `Eq` and `Hash` traits. -/// -/// # Example -/// -/// ``` -/// use std::collections::HashSet; -/// // Type inference lets us omit an explicit type signature (which -/// // would be `HashSet<&str>` in this example). -/// let mut books = HashSet::new(); -/// -/// // Add some books. -/// books.insert("A Dance With Dragons"); -/// books.insert("To Kill a Mockingbird"); -/// books.insert("The Odyssey"); -/// books.insert("The Great Gatsby"); -/// -/// // Check for a specific one. -/// if !books.contains(&("The Winds of Winter")) { -/// println!("We have {} books, but The Winds of Winter ain't one.", -/// books.len()); -/// } -/// -/// // Remove a book. -/// books.remove(&"The Odyssey"); -/// -/// // Iterate over everything. -/// for book in books.iter() { -/// println!("{}", *book); -/// } -/// ``` -/// -/// The easiest way to use `HashSet` with a custom type is to derive -/// `Eq` and `Hash`. We must also derive `PartialEq`, this will in the -/// future be implied by `Eq`. -/// -/// ``` -/// use std::collections::HashSet; -/// #[deriving(Hash, Eq, PartialEq, Show)] -/// struct Viking<'a> { -/// name: &'a str, -/// power: uint, -/// } -/// -/// let mut vikings = HashSet::new(); -/// -/// vikings.insert(Viking { name: "Einar", power: 9u }); -/// vikings.insert(Viking { name: "Einar", power: 9u }); -/// vikings.insert(Viking { name: "Olaf", power: 4u }); -/// vikings.insert(Viking { name: "Harald", power: 8u }); -/// -/// // Use derived implementation to print the vikings. -/// for x in vikings.iter() { -/// println!("{}", x); -/// } -/// ``` -#[deriving(Clone)] -pub struct HashSet { - map: HashMap -} - -impl HashSet { - /// Create an empty HashSet. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::new(); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new() -> HashSet { unimplemented!() } - - /// Create an empty HashSet with space for at least `n` elements in - /// the hash table. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::with_capacity(10); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn with_capacity(capacity: uint) -> HashSet { unimplemented!() } -} - -impl, S, H: Hasher> HashSet { - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; - /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_hasher(h); - /// set.insert(2u); - /// ``` - #[inline] - pub fn with_hasher(hasher: H) -> HashSet { unimplemented!() } - - /// Create an empty HashSet with space for at least `capacity` - /// elements in the hash table, using `hasher` to hash the keys. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// use std::hash::sip::SipHasher; - /// - /// let h = SipHasher::new(); - /// let mut set = HashSet::with_capacity_and_hasher(10u, h); - /// set.insert(1i); - /// ``` - #[inline] - pub fn with_capacity_and_hasher(capacity: uint, hasher: H) -> HashSet { unimplemented!() } - - /// Reserve space for at least `n` elements in the hash table. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set: HashSet = HashSet::new(); - /// set.reserve(10); - /// ``` - pub fn reserve(&mut self, n: uint) { unimplemented!() } - - /// Deprecated: use `contains` and `BorrowFrom`. - #[deprecated = "use contains and BorrowFrom"] - #[allow(deprecated)] - pub fn contains_equiv + Equiv>(&self, value: &Q) -> bool { unimplemented!() } - - /// An iterator visiting all elements in arbitrary order. - /// Iterator element type is &'a T. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a"); - /// set.insert("b"); - /// - /// // Will print in an arbitrary order. - /// for x in set.iter() { - /// println!("{}", x); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn iter<'a>(&'a self) -> SetItems<'a, T> { unimplemented!() } - - /// Creates a consuming iterator, that is, one that moves each value out - /// of the set in arbitrary order. The set cannot be used after calling - /// this. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let mut set = HashSet::new(); - /// set.insert("a".to_string()); - /// set.insert("b".to_string()); - /// - /// // Not possible to collect to a Vec with a regular `.iter()`. - /// let v: Vec = set.into_iter().collect(); - /// - /// // Will print in an arbitrary order. - /// for x in v.iter() { - /// println!("{}", x); - /// } - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn into_iter(self) -> SetMoveItems { unimplemented!() } - - /// Visit the values representing the difference. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); - /// - /// // Can be seen as `a - b`. - /// for x in a.difference(&b) { - /// println!("{}", x); // Print 1 - /// } - /// - /// let diff: HashSet = a.difference(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [1i].iter().map(|&x| x).collect()); - /// - /// // Note that difference is not symmetric, - /// // and `b - a` means something else: - /// let diff: HashSet = b.difference(&a).map(|&x| x).collect(); - /// assert_eq!(diff, [4i].iter().map(|&x| x).collect()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn difference<'a>(&'a self, other: &'a HashSet) -> SetAlgebraItems<'a, T, H> { unimplemented!() } - - /// Visit the values representing the symmetric difference. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); - /// - /// // Print 1, 4 in arbitrary order. - /// for x in a.symmetric_difference(&b) { - /// println!("{}", x); - /// } - /// - /// let diff1: HashSet = a.symmetric_difference(&b).map(|&x| x).collect(); - /// let diff2: HashSet = b.symmetric_difference(&a).map(|&x| x).collect(); - /// - /// assert_eq!(diff1, diff2); - /// assert_eq!(diff1, [1i, 4].iter().map(|&x| x).collect()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn symmetric_difference<'a>(&'a self, other: &'a HashSet) - -> Chain, SetAlgebraItems<'a, T, H>> { unimplemented!() } - - /// Visit the values representing the intersection. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); - /// - /// // Print 2, 3 in arbitrary order. - /// for x in a.intersection(&b) { - /// println!("{}", x); - /// } - /// - /// let diff: HashSet = a.intersection(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [2i, 3].iter().map(|&x| x).collect()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn intersection<'a>(&'a self, other: &'a HashSet) - -> SetAlgebraItems<'a, T, H> { unimplemented!() } - - /// Visit the values representing the union. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// let a: HashSet = [1i, 2, 3].iter().map(|&x| x).collect(); - /// let b: HashSet = [4i, 2, 3, 4].iter().map(|&x| x).collect(); - /// - /// // Print 1, 2, 3, 4 in arbitrary order. - /// for x in a.union(&b) { - /// println!("{}", x); - /// } - /// - /// let diff: HashSet = a.union(&b).map(|&x| x).collect(); - /// assert_eq!(diff, [1i, 2, 3, 4].iter().map(|&x| x).collect()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn union<'a>(&'a self, other: &'a HashSet) - -> Chain, SetAlgebraItems<'a, T, H>> { unimplemented!() } - - /// Return the number of elements in the set - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert_eq!(v.len(), 0); - /// v.insert(1u); - /// assert_eq!(v.len(), 1); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn len(&self) -> uint { unimplemented!() } - - /// Returns true if the set contains no elements - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// assert!(v.is_empty()); - /// v.insert(1u); - /// assert!(!v.is_empty()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_empty(&self) -> bool { unimplemented!() } - - /// Clears the set, removing all values. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut v = HashSet::new(); - /// v.insert(1u); - /// v.clear(); - /// assert!(v.is_empty()); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn clear(&mut self) { unimplemented!() } - - /// Returns `true` if the set contains a value. - /// - /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the value type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let set: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); - /// assert_eq!(set.contains(&1), true); - /// assert_eq!(set.contains(&4), false); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn contains(&self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq - { unimplemented!() } - - /// Returns `true` if the set has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let a: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); - /// let mut b: HashSet = HashSet::new(); - /// - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(4); - /// assert_eq!(a.is_disjoint(&b), true); - /// b.insert(1); - /// assert_eq!(a.is_disjoint(&b), false); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_disjoint(&self, other: &HashSet) -> bool { unimplemented!() } - - /// Returns `true` if the set is a subset of another. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let sup: HashSet = [1, 2, 3].iter().map(|&x| x).collect(); - /// let mut set: HashSet = HashSet::new(); - /// - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(2); - /// assert_eq!(set.is_subset(&sup), true); - /// set.insert(4); - /// assert_eq!(set.is_subset(&sup), false); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_subset(&self, other: &HashSet) -> bool { unimplemented!() } - - /// Returns `true` if the set is a superset of another. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let sub: HashSet = [1, 2].iter().map(|&x| x).collect(); - /// let mut set: HashSet = HashSet::new(); - /// - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(0); - /// set.insert(1); - /// assert_eq!(set.is_superset(&sub), false); - /// - /// set.insert(2); - /// assert_eq!(set.is_superset(&sub), true); - /// ``` - #[inline] - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_superset(&self, other: &HashSet) -> bool { unimplemented!() } - - /// Adds a value to the set. Returns `true` if the value was not already - /// present in the set. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::new(); - /// - /// assert_eq!(set.insert(2u), true); - /// assert_eq!(set.insert(2), false); - /// assert_eq!(set.len(), 1); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn insert(&mut self, value: T) -> bool { unimplemented!() } - - /// Removes a value from the set. Returns `true` if the value was - /// present in the set. - /// - /// The value may be any borrowed form of the set's value type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for - /// the value type. - /// - /// # Example - /// - /// ``` - /// use std::collections::HashSet; - /// - /// let mut set = HashSet::new(); - /// - /// set.insert(2u); - /// assert_eq!(set.remove(&2), true); - /// assert_eq!(set.remove(&2), false); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn remove(&mut self, value: &Q) -> bool - where Q: BorrowFrom + Hash + Eq - { unimplemented!() } -} - -impl, S, H: Hasher> PartialEq for HashSet { - fn eq(&self, other: &HashSet) -> bool { unimplemented!() } -} - -impl, S, H: Hasher> Eq for HashSet {} - -impl + fmt::Show, S, H: Hasher> fmt::Show for HashSet { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl, S, H: Hasher + Default> FromIterator for HashSet { - fn from_iter>(iter: I) -> HashSet { unimplemented!() } -} - -impl, S, H: Hasher + Default> Extend for HashSet { - fn extend>(&mut self, mut iter: I) { unimplemented!() } -} - -impl, S, H: Hasher + Default> Default for HashSet { - fn default() -> HashSet { unimplemented!() } -} - -/// HashSet iterator -pub type SetItems<'a, K> = - iter::Map<'static, (&'a K, &'a ()), &'a K, Entries<'a, K, ()>>; - -/// HashSet move iterator -pub type SetMoveItems = - iter::Map<'static, (K, ()), K, MoveEntries>; - -// `Repeat` is used to feed the filter closure an explicit capture -// of a reference to the other set -/// Set operations iterator -pub type SetAlgebraItems<'a, T, H> = - FilterMap<'static, (&'a HashSet, &'a T), &'a T, - Zip>, SetItems<'a, T>>>; diff --git a/src/libst2/collections/hash/table.rs b/src/libst2/collections/hash/table.rs deleted file mode 100644 index 00bb6ce775a89..0000000000000 --- a/src/libst2/collections/hash/table.rs +++ /dev/null @@ -1,408 +0,0 @@ -// 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. -// -// ignore-lexer-test FIXME #15883 - -pub use self::BucketState::*; - -use clone::Clone; -use cmp; -use hash::{Hash, Hasher}; -use iter::{Iterator, count}; -use kinds::{Sized, marker}; -use mem::{min_align_of, size_of}; -use mem; -use num::{Int, UnsignedInt}; -use ops::{Deref, DerefMut, Drop}; -use option::{Some, None, Option}; -use ptr::{RawPtr, copy_nonoverlapping_memory, zero_memory}; -use ptr; -use rt::heap::{allocate, deallocate}; - -const EMPTY_BUCKET: u64 = 0u64; - -/// The raw hashtable, providing safe-ish access to the unzipped and highly -/// optimized arrays of hashes, keys, and values. -/// -/// This design uses less memory and is a lot faster than the naive -/// `Vec>`, because we don't pay for the overhead of an -/// option on every element, and we get a generally more cache-aware design. -/// -/// Essential invariants of this structure: -/// -/// - if t.hashes[i] == EMPTY_BUCKET, then `Bucket::at_index(&t, i).raw` -/// points to 'undefined' contents. Don't read from it. This invariant is -/// enforced outside this module with the `EmptyBucket`, `FullBucket`, -/// and `SafeHash` types. -/// -/// - An `EmptyBucket` is only constructed at an index with -/// a hash of EMPTY_BUCKET. -/// -/// - A `FullBucket` is only constructed at an index with a -/// non-EMPTY_BUCKET hash. -/// -/// - A `SafeHash` is only constructed for non-`EMPTY_BUCKET` hash. We get -/// around hashes of zero by changing them to 0x8000_0000_0000_0000, -/// which will likely map to the same bucket, while not being confused -/// with "empty". -/// -/// - All three "arrays represented by pointers" are the same length: -/// `capacity`. This is set at creation and never changes. The arrays -/// are unzipped to save space (we don't have to pay for the padding -/// between odd sized elements, such as in a map from u64 to u8), and -/// be more cache aware (scanning through 8 hashes brings in at most -/// 2 cache lines, since they're all right beside each other). -/// -/// You can kind of think of this module/data structure as a safe wrapper -/// around just the "table" part of the hashtable. It enforces some -/// invariants at the type level and employs some performance trickery, -/// but in general is just a tricked out `Vec>`. -#[unsafe_no_drop_flag] -pub struct RawTable { - capacity: uint, - size: uint, - hashes: *mut u64, - // Because K/V do not appear directly in any of the types in the struct, - // inform rustc that in fact instances of K and V are reachable from here. - marker: marker::CovariantType<(K,V)>, -} - -struct RawBucket { - hash: *mut u64, - key: *mut K, - val: *mut V -} - -pub struct Bucket { - raw: RawBucket, - idx: uint, - table: M -} - -pub struct EmptyBucket { - raw: RawBucket, - idx: uint, - table: M -} - -pub struct FullBucket { - raw: RawBucket, - idx: uint, - table: M -} - -pub type EmptyBucketImm<'table, K, V> = EmptyBucket>; -pub type FullBucketImm<'table, K, V> = FullBucket>; - -pub type EmptyBucketMut<'table, K, V> = EmptyBucket>; -pub type FullBucketMut<'table, K, V> = FullBucket>; - -pub enum BucketState { - Empty(EmptyBucket), - Full(FullBucket), -} - -// A GapThenFull encapsulates the state of two consecutive buckets at once. -// The first bucket, called the gap, is known to be empty. -// The second bucket is full. -struct GapThenFull { - gap: EmptyBucket, - full: FullBucket, -} - -/// A hash that is not zero, since we use a hash of zero to represent empty -/// buckets. -#[deriving(PartialEq)] -pub struct SafeHash { - hash: u64, -} - -impl SafeHash { - /// Peek at the hash value, which is guaranteed to be non-zero. - #[inline(always)] - pub fn inspect(&self) -> u64 { unimplemented!() } -} - -/// We need to remove hashes of 0. That's reserved for empty buckets. -/// This function wraps up `hash_keyed` to be the only way outside this -/// module to generate a SafeHash. -pub fn make_hash, S, H: Hasher>(hasher: &H, t: &T) -> SafeHash { unimplemented!() } - -// `replace` casts a `*u64` to a `*SafeHash`. Since we statically -// ensure that a `FullBucket` points to an index with a non-zero hash, -// and a `SafeHash` is just a `u64` with a different name, this is -// safe. -// -// This test ensures that a `SafeHash` really IS the same size as a -// `u64`. If you need to change the size of `SafeHash` (and -// consequently made this test fail), `replace` needs to be -// modified to no longer assume this. -#[test] -fn can_alias_safehash_as_u64() { unimplemented!() } - -impl RawBucket { - unsafe fn offset(self, count: int) -> RawBucket { unimplemented!() } -} - -// Buckets hold references to the table. -impl FullBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { unimplemented!() } - /// Move out the reference to the table. - pub fn into_table(self) -> M { unimplemented!() } - /// Get the raw index. - pub fn index(&self) -> uint { unimplemented!() } -} - -impl EmptyBucket { - /// Borrow a reference to the table. - pub fn table(&self) -> &M { unimplemented!() } - /// Move out the reference to the table. - pub fn into_table(self) -> M { unimplemented!() } -} - -impl Bucket { - /// Move out the reference to the table. - pub fn into_table(self) -> M { unimplemented!() } - /// Get the raw index. - pub fn index(&self) -> uint { unimplemented!() } -} - -impl>> Bucket { - pub fn new(table: M, hash: &SafeHash) -> Bucket { unimplemented!() } - - pub fn at_index(table: M, ib_index: uint) -> Bucket { unimplemented!() } - - pub fn first(table: M) -> Bucket { unimplemented!() } - - /// Reads a bucket at a given index, returning an enum indicating whether - /// it's initialized or not. You need to match on this enum to get - /// the appropriate types to call most of the other functions in - /// this module. - pub fn peek(self) -> BucketState { unimplemented!() } - - /// Modifies the bucket pointer in place to make it point to the next slot. - pub fn next(&mut self) { unimplemented!() } -} - -impl>> EmptyBucket { - #[inline] - pub fn next(self) -> Bucket { unimplemented!() } - - #[inline] - pub fn into_bucket(self) -> Bucket { unimplemented!() } - - pub fn gap_peek(self) -> Option> { unimplemented!() } -} - -impl>> EmptyBucket { - /// Puts given key and value pair, along with the key's hash, - /// into this bucket in the hashtable. Note how `self` is 'moved' into - /// this function, because this slot will no longer be empty when - /// we return! A `FullBucket` is returned for later use, pointing to - /// the newly-filled slot in the hashtable. - /// - /// Use `make_hash` to construct a `SafeHash` to pass to this function. - pub fn put(mut self, hash: SafeHash, key: K, value: V) - -> FullBucket { unimplemented!() } -} - -impl>> FullBucket { - #[inline] - pub fn next(self) -> Bucket { unimplemented!() } - - #[inline] - pub fn into_bucket(self) -> Bucket { unimplemented!() } - - /// Get the distance between this bucket and the 'ideal' location - /// as determined by the key's hash stored in it. - /// - /// In the cited blog posts above, this is called the "distance to - /// initial bucket", or DIB. Also known as "probe count". - pub fn distance(&self) -> uint { unimplemented!() } - - #[inline] - pub fn hash(&self) -> SafeHash { unimplemented!() } - - /// Gets references to the key and value at a given index. - pub fn read(&self) -> (&K, &V) { unimplemented!() } -} - -impl>> FullBucket { - /// Removes this bucket's key and value from the hashtable. - /// - /// This works similarly to `put`, building an `EmptyBucket` out of the - /// taken bucket. - pub fn take(mut self) -> (EmptyBucket, K, V) { unimplemented!() } - - pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) { unimplemented!() } - - /// Gets mutable references to the key and value at a given index. - pub fn read_mut(&mut self) -> (&mut K, &mut V) { unimplemented!() } -} - -impl<'t, K, V, M: Deref> + 't> FullBucket { - /// Exchange a bucket state for immutable references into the table. - /// Because the underlying reference to the table is also consumed, - /// no further changes to the structure of the table are possible; - /// in exchange for this, the returned references have a longer lifetime - /// than the references returned by `read()`. - pub fn into_refs(self) -> (&'t K, &'t V) { unimplemented!() } -} - -impl<'t, K, V, M: DerefMut> + 't> FullBucket { - /// This works similarly to `into_refs`, exchanging a bucket state - /// for mutable references into the table. - pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) { unimplemented!() } -} - -impl BucketState { - // For convenience. - pub fn expect_full(self) -> FullBucket { unimplemented!() } -} - -impl>> GapThenFull { - #[inline] - pub fn full(&self) -> &FullBucket { unimplemented!() } - - pub fn shift(mut self) -> Option> { unimplemented!() } -} - - -/// Rounds up to a multiple of a power of two. Returns the closest multiple -/// of `target_alignment` that is higher or equal to `unrounded`. -/// -/// # Panics -/// -/// Panics if `target_alignment` is not a power of two. -fn round_up_to_next(unrounded: uint, target_alignment: uint) -> uint { unimplemented!() } - -#[test] -fn test_rounding() { unimplemented!() } - -// Returns a tuple of (key_offset, val_offset), -// from the start of a mallocated array. -fn calculate_offsets(hashes_size: uint, - keys_size: uint, keys_align: uint, - vals_align: uint) - -> (uint, uint) { unimplemented!() } - -// Returns a tuple of (minimum required malloc alignment, hash_offset, -// array_size), from the start of a mallocated array. -fn calculate_allocation(hash_size: uint, hash_align: uint, - keys_size: uint, keys_align: uint, - vals_size: uint, vals_align: uint) - -> (uint, uint, uint) { unimplemented!() } - -#[test] -fn test_offset_calculation() { unimplemented!() } - -impl RawTable { - /// Does not initialize the buckets. The caller should ensure they, - /// at the very least, set every hash to EMPTY_BUCKET. - unsafe fn new_uninitialized(capacity: uint) -> RawTable { unimplemented!() } - - fn first_bucket_raw(&self) -> RawBucket { unimplemented!() } - - /// Creates a new raw table from a given capacity. All buckets are - /// initially empty. - #[allow(experimental)] - pub fn new(capacity: uint) -> RawTable { unimplemented!() } - - /// The hashtable's capacity, similar to a vector's. - pub fn capacity(&self) -> uint { unimplemented!() } - - /// The number of elements ever `put` in the hashtable, minus the number - /// of elements ever `take`n. - pub fn size(&self) -> uint { unimplemented!() } - - fn raw_buckets(&self) -> RawBuckets { unimplemented!() } - - pub fn iter(&self) -> Entries { unimplemented!() } - - pub fn iter_mut(&mut self) -> MutEntries { unimplemented!() } - - pub fn into_iter(self) -> MoveEntries { unimplemented!() } - - /// Returns an iterator that copies out each entry. Used while the table - /// is being dropped. - unsafe fn rev_move_buckets(&mut self) -> RevMoveBuckets { unimplemented!() } -} - -/// A raw iterator. The basis for some other iterators in this module. Although -/// this interface is safe, it's not used outside this module. -struct RawBuckets<'a, K, V> { - raw: RawBucket, - hashes_end: *mut u64, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a, K, V> Iterator> for RawBuckets<'a, K, V> { - fn next(&mut self) -> Option> { unimplemented!() } -} - -/// An iterator that moves out buckets in reverse order. It leaves the table -/// in an inconsistent state and should only be used for dropping -/// the table's remaining entries. It's used in the implementation of Drop. -struct RevMoveBuckets<'a, K, V> { - raw: RawBucket, - hashes_end: *mut u64, - elems_left: uint, - marker: marker::ContravariantLifetime<'a>, -} - -impl<'a, K, V> Iterator<(K, V)> for RevMoveBuckets<'a, K, V> { - fn next(&mut self) -> Option<(K, V)> { unimplemented!() } -} - -/// Iterator over shared references to entries in a table. -pub struct Entries<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, - elems_left: uint, -} - -/// Iterator over mutable references to entries in a table. -pub struct MutEntries<'a, K: 'a, V: 'a> { - iter: RawBuckets<'a, K, V>, - elems_left: uint, -} - -/// Iterator over the entries in a table, consuming the table. -pub struct MoveEntries { - table: RawTable, - iter: RawBuckets<'static, K, V> -} - -impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { - fn next(&mut self) -> Option<(&'a K, &'a V)> { unimplemented!() } - - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { - fn next(&mut self) -> Option<(&'a K, &'a mut V)> { unimplemented!() } - - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl Iterator<(SafeHash, K, V)> for MoveEntries { - fn next(&mut self) -> Option<(SafeHash, K, V)> { unimplemented!() } - - fn size_hint(&self) -> (uint, Option) { unimplemented!() } -} - -impl Clone for RawTable { - fn clone(&self) -> RawTable { unimplemented!() } -} - -#[unsafe_destructor] -impl Drop for RawTable { - fn drop(&mut self) { unimplemented!() } -} diff --git a/src/libst2/collections/lru_cache.rs b/src/libst2/collections/lru_cache.rs deleted file mode 100644 index 29535c0941e22..0000000000000 --- a/src/libst2/collections/lru_cache.rs +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright 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. - - -//! A cache that holds a limited number of key-value pairs. When the -//! capacity of the cache is exceeded, the least-recently-used -//! (where "used" means a look-up or putting the pair into the cache) -//! pair is automatically removed. -//! -//! # Example -//! -//! ```rust -//! use std::collections::LruCache; -//! -//! let mut cache: LruCache = LruCache::new(2); -//! cache.insert(1, 10); -//! cache.insert(2, 20); -//! cache.insert(3, 30); -//! assert!(cache.get(&1).is_none()); -//! assert_eq!(*cache.get(&2).unwrap(), 20); -//! assert_eq!(*cache.get(&3).unwrap(), 30); -//! -//! cache.insert(2, 22); -//! assert_eq!(*cache.get(&2).unwrap(), 22); -//! -//! cache.insert(6, 60); -//! assert!(cache.get(&3).is_none()); -//! -//! cache.set_capacity(1); -//! assert!(cache.get(&2).is_none()); -//! ``` - -use cmp::{PartialEq, Eq}; -use collections::HashMap; -use fmt; -use hash::Hash; -use iter::{range, Iterator, Extend}; -use mem; -use ops::Drop; -use option::{Some, None, Option}; -use boxed::Box; -use ptr; -use result::{Ok, Err}; - -// FIXME(conventions): implement iterators? -// FIXME(conventions): implement indexing? - -struct KeyRef { k: *const K } - -struct LruEntry { - next: *mut LruEntry, - prev: *mut LruEntry, - key: K, - value: V, -} - -/// An LRU Cache. -pub struct LruCache { - map: HashMap, Box>>, - max_size: uint, - head: *mut LruEntry, -} - -impl> Hash for KeyRef { - fn hash(&self, state: &mut S) { unimplemented!() } -} - -impl PartialEq for KeyRef { - fn eq(&self, other: &KeyRef) -> bool { unimplemented!() } -} - -impl Eq for KeyRef {} - -impl LruEntry { - fn new(k: K, v: V) -> LruEntry { unimplemented!() } -} - -impl LruCache { - /// Create an LRU Cache that holds at most `capacity` items. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache: LruCache = LruCache::new(10); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new(capacity: uint) -> LruCache { unimplemented!() } - - /// Deprecated: Replaced with `insert`. - #[deprecated = "Replaced with `insert`"] - pub fn put(&mut self, k: K, v: V) { unimplemented!() } - - /// Inserts a key-value pair into the cache. If the key already existed, the old value is - /// returned. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache = LruCache::new(2); - /// - /// cache.insert(1i, "a"); - /// cache.insert(2, "b"); - /// assert_eq!(cache.get(&1), Some(&"a")); - /// assert_eq!(cache.get(&2), Some(&"b")); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn insert(&mut self, k: K, v: V) -> Option { unimplemented!() } - - /// Return a value corresponding to the key in the cache. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache = LruCache::new(2); - /// - /// cache.insert(1i, "a"); - /// cache.insert(2, "b"); - /// cache.insert(2, "c"); - /// cache.insert(3, "d"); - /// - /// assert_eq!(cache.get(&1), None); - /// assert_eq!(cache.get(&2), Some(&"c")); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn get(&mut self, k: &K) -> Option<&V> { unimplemented!() } - - /// Deprecated: Renamed to `remove`. - #[deprecated = "Renamed to `remove`"] - pub fn pop(&mut self, k: &K) -> Option { unimplemented!() } - - /// Remove and return a value corresponding to the key from the cache. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache = LruCache::new(2); - /// - /// cache.insert(2i, "a"); - /// - /// assert_eq!(cache.remove(&1), None); - /// assert_eq!(cache.remove(&2), Some("a")); - /// assert_eq!(cache.remove(&2), None); - /// assert_eq!(cache.len(), 0); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn remove(&mut self, k: &K) -> Option { unimplemented!() } - - /// Return the maximum number of key-value pairs the cache can hold. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache: LruCache = LruCache::new(2); - /// assert_eq!(cache.capacity(), 2); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn capacity(&self) -> uint { unimplemented!() } - - /// Deprecated: Renamed to `set_capacity`. - #[deprecated = "Renamed to `set_capacity`"] - pub fn change_capacity(&mut self, capacity: uint) { unimplemented!() } - - /// Change the number of key-value pairs the cache can hold. Remove - /// least-recently-used key-value pairs if necessary. - /// - /// # Example - /// - /// ``` - /// use std::collections::LruCache; - /// let mut cache = LruCache::new(2); - /// - /// cache.insert(1i, "a"); - /// cache.insert(2, "b"); - /// cache.insert(3, "c"); - /// - /// assert_eq!(cache.get(&1), None); - /// assert_eq!(cache.get(&2), Some(&"b")); - /// assert_eq!(cache.get(&3), Some(&"c")); - /// - /// cache.set_capacity(3); - /// cache.insert(1i, "a"); - /// cache.insert(2, "b"); - /// - /// assert_eq!(cache.get(&1), Some(&"a")); - /// assert_eq!(cache.get(&2), Some(&"b")); - /// assert_eq!(cache.get(&3), Some(&"c")); - /// - /// cache.set_capacity(1); - /// - /// assert_eq!(cache.get(&1), None); - /// assert_eq!(cache.get(&2), None); - /// assert_eq!(cache.get(&3), Some(&"c")); - /// ``` - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn set_capacity(&mut self, capacity: uint) { unimplemented!() } - - #[inline] - fn remove_lru(&mut self) { unimplemented!() } - - #[inline] - fn detach(&mut self, node: *mut LruEntry) { unimplemented!() } - - #[inline] - fn attach(&mut self, node: *mut LruEntry) { unimplemented!() } - - /// Return the number of key-value pairs in the cache. - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn len(&self) -> uint { unimplemented!() } - - /// Returns whether the cache is currently empty. - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn is_empty(&self) -> bool { unimplemented!() } - - /// Clear the cache of all key-value pairs. - #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn clear(&mut self) { unimplemented!() } - -} - -impl Extend<(K, V)> for LruCache { - fn extend>(&mut self, mut iter: T) { unimplemented!() } -} - -impl fmt::Show for LruCache { - /// Return a string that lists the key-value pairs from most-recently - /// used to least-recently used. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -#[unsafe_destructor] -impl Drop for LruCache { - fn drop(&mut self) { unimplemented!() } -} diff --git a/src/libst2/collections/mod.rs b/src/libst2/collections/mod.rs deleted file mode 100644 index 3419a3d98a154..0000000000000 --- a/src/libst2/collections/mod.rs +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright 2013-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. - -//! Collection types. -//! -//! Rust's standard collection library provides efficient implementations of the most common -//! general purpose programming data structures. By using the standard implementations, -//! it should be possible for two libraries to communicate without significant data conversion. -//! -//! To get this out of the way: you should probably just use `Vec` or `HashMap`. These two -//! collections cover most use cases for generic data storage and processing. They are -//! exceptionally good at doing what they do. All the other collections in the standard -//! library have specific use cases where they are the optimal choice, but these cases are -//! borderline *niche* in comparison. Even when `Vec` and `HashMap` are technically suboptimal, -//! they're probably a good enough choice to get started. -//! -//! Rust's collections can be grouped into four major categories: -//! -//! * Sequences: `Vec`, `RingBuf`, `DList`, `BitV` -//! * Maps: `HashMap`, `BTreeMap`, `TreeMap`, `TrieMap`, `VecMap`, `LruCache` -//! * Sets: `HashSet`, `BTreeSet`, `TreeSet`, `TrieSet`, `BitVSet`, `EnumSet` -//! * Misc: `BinaryHeap` -//! -//! # When Should You Use Which Collection? -//! -//! These are fairly high-level and quick break-downs of when each collection should be -//! considered. Detailed discussions of strengths and weaknesses of individual collections -//! can be found on their own documentation pages. -//! -//! ### Use a `Vec` when: -//! * You want to collect items up to be processed or sent elsewhere later, and don't care about -//! any properties of the actual values being stored. -//! * You want a sequence of elements in a particular order, and will only be appending to -//! (or near) the end. -//! * You want a stack. -//! * You want a resizable array. -//! * You want a heap-allocated array. -//! -//! ### Use a `RingBuf` when: -//! * You want a `Vec` that supports efficient insertion at both ends of the sequence. -//! * You want a queue. -//! * You want a double-ended queue (deque). -//! -//! ### Use a `DList` when: -//! * You want a `Vec` or `RingBuf` of unknown size, and can't tolerate inconsistent -//! performance during insertions. -//! * You are *absolutely* certain you *really*, *truly*, want a doubly linked list. -//! -//! ### Use a `HashMap` when: -//! * You want to associate arbitrary keys with an arbitrary value. -//! * You want a cache. -//! * You want a map, with no extra functionality. -//! -//! ### Use a `BTreeMap` when: -//! * You're interested in what the smallest or largest key-value pair is. -//! * You want to find the largest or smallest key that is smaller or larger than something -//! * You want to be able to get all of the entries in order on-demand. -//! * You want a sorted map. -//! -//! ### Use a `TreeMap` when: -//! * You want a `BTreeMap`, but can't tolerate inconsistent performance. -//! * You want a `BTreeMap`, but have *very large* keys or values. -//! * You want a `BTreeMap`, but have keys that are expensive to compare. -//! * You want a `BTreeMap`, but you accept arbitrary untrusted inputs. -//! -//! ### Use a `TrieMap` when: -//! * You want a `HashMap`, but with many potentially large `uint` keys. -//! * You want a `BTreeMap`, but with potentially large `uint` keys. -//! -//! ### Use a `VecMap` when: -//! * You want a `HashMap` but with known to be small `uint` keys. -//! * You want a `BTreeMap`, but with known to be small `uint` keys. -//! -//! ### Use the `Set` variant of any of these `Map`s when: -//! * You just want to remember which keys you've seen. -//! * There is no meaningful value to associate with your keys. -//! * You just want a set. -//! -//! ### Use a `BitV` when: -//! * You want to store an unbounded number of booleans in a small space. -//! * You want a bitvector. -//! -//! ### Use a `BitVSet` when: -//! * You want a `VecSet`. -//! -//! ### Use an `EnumSet` when: -//! * You want a C-like enum, stored in a single `uint`. -//! -//! ### Use a `BinaryHeap` when: -//! * You want to store a bunch of elements, but only ever want to process the "biggest" -//! or "most important" one at any given time. -//! * You want a priority queue. -//! -//! ### Use an `LruCache` when: -//! * You want a cache that discards infrequently used items when it becomes full. -//! * You want a least-recently-used cache. -//! -//! # Correct and Efficient Usage of Collections -//! -//! Of course, knowing which collection is the right one for the job doesn't instantly -//! permit you to use it correctly. Here are some quick tips for efficient and correct -//! usage of the standard collections in general. If you're interested in how to use a -//! specific collection in particular, consult its documentation for detailed discussion -//! and code examples. -//! -//! ## Capacity Management -//! -//! Many collections provide several constructors and methods that refer to "capacity". -//! These collections are generally built on top of an array. Optimally, this array would be -//! exactly the right size to fit only the elements stored in the collection, but for the -//! collection to do this would be very inefficient. If the backing array was exactly the -//! right size at all times, then every time an element is inserted, the collection would -//! have to grow the array to fit it. Due to the way memory is allocated and managed on most -//! computers, this would almost surely require allocating an entirely new array and -//! copying every single element from the old one into the new one. Hopefully you can -//! see that this wouldn't be very efficient to do on every operation. -//! -//! Most collections therefore use an *amortized* allocation strategy. They generally let -//! themselves have a fair amount of unoccupied space so that they only have to grow -//! on occasion. When they do grow, they allocate a substantially larger array to move -//! the elements into so that it will take a while for another grow to be required. While -//! this strategy is great in general, it would be even better if the collection *never* -//! had to resize its backing array. Unfortunately, the collection itself doesn't have -//! enough information to do this itself. Therefore, it is up to us programmers to give it -//! hints. -//! -//! Any `with_capacity` constructor will instruct the collection to allocate enough space -//! for the specified number of elements. Ideally this will be for exactly that many -//! elements, but some implementation details may prevent this. `Vec` and `RingBuf` can -//! be relied on to allocate exactly the requested amount, though. Use `with_capacity` -//! when you know exactly how many elements will be inserted, or at least have a -//! reasonable upper-bound on that number. -//! -//! When anticipating a large influx of elements, the `reserve` family of methods can -//! be used to hint to the collection how much room it should make for the coming items. -//! As with `with_capacity`, the precise behavior of these methods will be specific to -//! the collection of interest. -//! -//! For optimal performance, collections will generally avoid shrinking themselves. -//! If you believe that a collection will not soon contain any more elements, or -//! just really need the memory, the `shrink_to_fit` method prompts the collection -//! to shrink the backing array to the minimum size capable of holding its elements. -//! -//! Finally, if ever you're interested in what the actual capacity of the collection is, -//! most collections provide a `capacity` method to query this information on demand. -//! This can be useful for debugging purposes, or for use with the `reserve` methods. -//! -//! ## Iterators -//! -//! Iterators are a powerful and robust mechanism used throughout Rust's standard -//! libraries. Iterators provide a sequence of values in a generic, safe, efficient -//! and convenient way. The contents of an iterator are usually *lazily* evaluated, -//! so that only the values that are actually needed are ever actually produced, and -//! no allocation need be done to temporarily store them. Iterators are primarily -//! consumed using a `for` loop, although many functions also take iterators where -//! a collection or sequence of values is desired. -//! -//! All of the standard collections provide several iterators for performing bulk -//! manipulation of their contents. The three primary iterators almost every collection -//! should provide are `iter`, `iter_mut`, and `into_iter`. Some of these are not -//! provided on collections where it would be unsound or unreasonable to provide them. -//! -//! `iter` provides an iterator of immutable references to all the contents of a -//! collection in the most "natural" order. For sequence collections like `Vec`, this -//! means the items will be yielded in increasing order of index starting at 0. For ordered -//! collections like `BTreeMap`, this means that the items will be yielded in sorted order. -//! For unordered collections like `HashMap`, the items will be yielded in whatever order -//! the internal representation made most convenient. This is great for reading through -//! all the contents of the collection. -//! -//! ``` -//! let vec = vec![1u, 2, 3, 4]; -//! for x in vec.iter() { -//! println!("vec contained {}", x); -//! } -//! ``` -//! -//! `iter_mut` provides an iterator of *mutable* references in the same order as `iter`. -//! This is great for mutating all the contents of the collection. -//! -//! ``` -//! let mut vec = vec![1u, 2, 3, 4]; -//! for x in vec.iter_mut() { -//! *x += 1; -//! } -//! ``` -//! -//! `into_iter` transforms the actual collection into an iterator over its contents -//! by-value. This is great when the collection itself is no longer needed, and the -//! values are needed elsewhere. Using `extend` with `into_iter` is the main way that -//! contents of one collection are moved into another. Calling `collect` on an iterator -//! itself is also a great way to convert one collection into another. Both of these -//! methods should internally use the capacity management tools discussed in the -//! previous section to do this as efficiently as possible. -//! -//! ``` -//! let mut vec1 = vec![1u, 2, 3, 4]; -//! let vec2 = vec![10u, 20, 30, 40]; -//! vec1.extend(vec2.into_iter()); -//! ``` -//! -//! ``` -//! use std::collections::RingBuf; -//! -//! let vec = vec![1u, 2, 3, 4]; -//! let buf: RingBuf = vec.into_iter().collect(); -//! ``` -//! -//! Iterators also provide a series of *adapter* methods for performing common tasks to -//! sequences. Among the adapters are functional favorites like `map`, `fold`, `skip`, -//! and `take`. Of particular interest to collections is the `rev` adapter, that -//! reverses any iterator that supports this operation. Most collections provide reversible -//! iterators as the way to iterate over them in reverse order. -//! -//! ``` -//! let vec = vec![1u, 2, 3, 4]; -//! for x in vec.iter().rev() { -//! println!("vec contained {}", x); -//! } -//! ``` -//! -//! Several other collection methods also return iterators to yield a sequence of results -//! but avoid allocating an entire collection to store the result in. This provides maximum -//! flexibility as `collect` or `extend` can be called to "pipe" the sequence into any -//! collection if desired. Otherwise, the sequence can be looped over with a `for` loop. The -//! iterator can also be discarded after partial use, preventing the computation of the unused -//! items. -//! -//! ## Entries -//! -//! The `entry` API is intended to provide an efficient mechanism for manipulating -//! the contents of a map conditionally on the presence of a key or not. The primary -//! motivating use case for this is to provide efficient accumulator maps. For instance, -//! if one wishes to maintain a count of the number of times each key has been seen, -//! they will have to perform some conditional logic on whether this is the first time -//! the key has been seen or not. Normally, this would require a `find` followed by an -//! `insert`, effectively duplicating the search effort on each insertion. -//! -//! When a user calls `map.entry(key)`, the map will search for the key and then yield -//! a variant of the `Entry` enum. -//! -//! If a `Vacant(entry)` is yielded, then the key *was not* found. In this case the -//! only valid operation is to `set` the value of the entry. When this is done, -//! the vacant entry is consumed and converted into a mutable reference to the -//! the value that was inserted. This allows for further manipulation of the value -//! beyond the lifetime of the search itself. This is useful if complex logic needs to -//! be performed on the value regardless of whether the value was just inserted. -//! -//! If an `Occupied(entry)` is yielded, then the key *was* found. In this case, the user -//! has several options: they can `get`, `set`, or `take` the value of the occupied -//! entry. Additionally, they can convert the occupied entry into a mutable reference -//! to its value, providing symmetry to the vacant `set` case. -//! -//! ### Examples -//! -//! Here are the two primary ways in which `entry` is used. First, a simple example -//! where the logic performed on the values is trivial. -//! -//! #### Counting the number of times each character in a string occurs -//! -//! ``` -//! use std::collections::btree_map::{BTreeMap, Occupied, Vacant}; -//! -//! let mut count = BTreeMap::new(); -//! let message = "she sells sea shells by the sea shore"; -//! -//! for c in message.chars() { -//! match count.entry(c) { -//! Vacant(entry) => { entry.set(1u); }, -//! Occupied(mut entry) => *entry.get_mut() += 1, -//! } -//! } -//! -//! assert_eq!(count.get(&'s'), Some(&8)); -//! -//! println!("Number of occurences of each character"); -//! for (char, count) in count.iter() { -//! println!("{}: {}", char, count); -//! } -//! ``` -//! -//! When the logic to be performed on the value is more complex, we may simply use -//! the `entry` API to ensure that the value is initialized, and perform the logic -//! afterwards. -//! -//! #### Tracking the inebriation of customers at a bar -//! -//! ``` -//! use std::collections::btree_map::{BTreeMap, Occupied, Vacant}; -//! -//! // A client of the bar. They have an id and a blood alcohol level. -//! struct Person { id: u32, blood_alcohol: f32 }; -//! -//! // All the orders made to the bar, by client id. -//! let orders = vec![1,2,1,2,3,4,1,2,2,3,4,1,1,1]; -//! -//! // Our clients. -//! let mut blood_alcohol = BTreeMap::new(); -//! -//! for id in orders.into_iter() { -//! // If this is the first time we've seen this customer, initialize them -//! // with no blood alcohol. Otherwise, just retrieve them. -//! let person = match blood_alcohol.entry(id) { -//! Vacant(entry) => entry.set(Person{id: id, blood_alcohol: 0.0}), -//! Occupied(entry) => entry.into_mut(), -//! }; -//! -//! // Reduce their blood alcohol level. It takes time to order and drink a beer! -//! person.blood_alcohol *= 0.9; -//! -//! // Check if they're sober enough to have another beer. -//! if person.blood_alcohol > 0.3 { -//! // Too drunk... for now. -//! println!("Sorry {}, I have to cut you off", person.id); -//! } else { -//! // Have another! -//! person.blood_alcohol += 0.1; -//! } -//! } -//! ``` - -#![experimental] - -pub use core_collections::{BinaryHeap, Bitv, BitvSet, BTreeMap, BTreeSet}; -pub use core_collections::{DList, EnumSet, RingBuf}; -pub use core_collections::{TreeMap, TreeSet, TrieMap, TrieSet, VecMap}; - -pub use core_collections::{binary_heap, bitv, bitv_set, btree_map, btree_set, dlist, enum_set}; -pub use core_collections::{ring_buf, tree_map, tree_set, trie_map, trie_set, vec_map}; - -pub use self::hash_map::HashMap; -pub use self::hash_set::HashSet; -pub use self::lru_cache::LruCache; - -mod hash; - -pub mod hash_map { - //! A hashmap - pub use super::hash::map::*; -} - -pub mod hash_set { - //! A hashset - pub use super::hash::set::*; -} - -pub mod lru_cache; diff --git a/src/libst2/dynamic_lib.rs b/src/libst2/dynamic_lib.rs deleted file mode 100644 index f84bedaabba0e..0000000000000 --- a/src/libst2/dynamic_lib.rs +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright 2013-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. - -/*! - -Dynamic library facilities. - -A simple wrapper over the platform's dynamic library facilities - -*/ - -#![experimental] -#![allow(missing_docs)] - -use clone::Clone; -use c_str::ToCStr; -use iter::Iterator; -use mem; -use ops::*; -use option::*; -use os; -use path::{Path,GenericPath}; -use result::*; -use slice::{AsSlice,SlicePrelude}; -use str; -use string::String; -use vec::Vec; - -pub struct DynamicLibrary { handle: *mut u8 } - -impl Drop for DynamicLibrary { - fn drop(&mut self) { unimplemented!() } -} - -impl DynamicLibrary { - // FIXME (#12938): Until DST lands, we cannot decompose &str into - // & and str, so we cannot usefully take ToCStr arguments by - // reference (without forcing an additional & around &str). So we - // are instead temporarily adding an instance for &Path, so that - // we can take ToCStr as owned. When DST lands, the &Path instance - // should be removed, and arguments bound by ToCStr should be - // passed by reference. (Here: in the `open` method.) - - /// Lazily open a dynamic library. When passed None it gives a - /// handle to the calling process - pub fn open(filename: Option) - -> Result { unimplemented!() } - - /// Prepends a path to this process's search path for dynamic libraries - pub fn prepend_search_path(path: &Path) { unimplemented!() } - - /// From a slice of paths, create a new vector which is suitable to be an - /// environment variable for this platforms dylib search path. - pub fn create_path(path: &[Path]) -> Vec { unimplemented!() } - - /// Returns the environment variable for this process's dynamic library - /// search path - pub fn envvar() -> &'static str { unimplemented!() } - - fn separator() -> u8 { unimplemented!() } - - /// Returns the current search path for dynamic libraries being used by this - /// process - pub fn search_path() -> Vec { unimplemented!() } - - /// Access the value at the symbol of the dynamic library - pub unsafe fn symbol(&self, symbol: &str) -> Result<*mut T, String> { unimplemented!() } -} - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub mod dl { - pub use self::Rtld::*; - - use c_str::{CString, ToCStr}; - use libc; - use ptr; - use result::*; - use string::String; - - pub unsafe fn open_external(filename: T) -> *mut u8 { unimplemented!() } - - pub unsafe fn open_internal() -> *mut u8 { unimplemented!() } - - pub fn check_for_errors_in(f: || -> T) -> Result { unimplemented!() } - - pub unsafe fn symbol(handle: *mut u8, - symbol: *const libc::c_char) -> *mut u8 { unimplemented!() } - pub unsafe fn close(handle: *mut u8) { unimplemented!() } - - pub enum Rtld { - Lazy = 1, - Now = 2, - Global = 256, - Local = 0, - } - - #[link_name = "dl"] - extern { - fn dlopen(filename: *const libc::c_char, - flag: libc::c_int) -> *mut libc::c_void; - fn dlerror() -> *mut libc::c_char; - fn dlsym(handle: *mut libc::c_void, - symbol: *const libc::c_char) -> *mut libc::c_void; - fn dlclose(handle: *mut libc::c_void) -> libc::c_int; - } -} - -#[cfg(target_os = "windows")] -pub mod dl { - use c_str::ToCStr; - use iter::Iterator; - use libc; - use os; - use ptr; - use result::{Ok, Err, Result}; - use slice::SlicePrelude; - use str::StrPrelude; - use str; - use string::String; - use vec::Vec; - - pub unsafe fn open_external(filename: T) -> *mut u8 { unimplemented!() } - - pub unsafe fn open_internal() -> *mut u8 { unimplemented!() } - - pub fn check_for_errors_in(f: || -> T) -> Result { unimplemented!() } - - pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 { unimplemented!() } - pub unsafe fn close(handle: *mut u8) { unimplemented!() } - - #[allow(non_snake_case)] - extern "system" { - fn SetLastError(error: libc::size_t); - fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void; - fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16, - handle: *mut *mut libc::c_void) - -> *mut libc::c_void; - fn GetProcAddress(handle: *mut libc::c_void, - name: *const libc::c_char) -> *mut libc::c_void; - fn FreeLibrary(handle: *mut libc::c_void); - } -} diff --git a/src/libst2/error.rs b/src/libst2/error.rs deleted file mode 100644 index 8c224c479a18e..0000000000000 --- a/src/libst2/error.rs +++ /dev/null @@ -1,106 +0,0 @@ -// 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. - -//! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail and cause -//! chain information: -//! -//! ``` -//! trait Error: Send { -//! fn description(&self) -> &str; -//! -//! fn detail(&self) -> Option { None } -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The `cause` method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. -//! -//! # The `FromError` trait -//! -//! `FromError` is a simple trait that expresses conversions between different -//! error types. To provide maximum flexibility, it does not require either of -//! the types to actually implement the `Error` trait, although this will be the -//! common case. -//! -//! The main use of this trait is in the `try!` macro, which uses it to -//! automatically convert a given error to the error specified in a function's -//! return type. -//! -//! For example, -//! -//! ``` -//! use std::error::FromError; -//! use std::io::{File, IoError}; -//! use std::os::{MemoryMap, MapError}; -//! use std::path::Path; -//! -//! enum MyError { -//! Io(IoError), -//! Map(MapError) -//! } -//! -//! impl FromError for MyError { -//! fn from_error(err: IoError) -> MyError { -//! MyError::Io(err) -//! } -//! } -//! -//! impl FromError for MyError { -//! fn from_error(err: MapError) -> MyError { -//! MyError::Map(err) -//! } -//! } -//! -//! #[allow(unused_variables)] -//! fn open_and_map() -> Result<(), MyError> { -//! let f = try!(File::open(&Path::new("foo.txt"))); -//! let m = try!(MemoryMap::new(0, &[])); -//! // do something interesting here... -//! Ok(()) -//! } -//! ``` - -use option::{Option, None}; -use kinds::Send; -use string::String; - -/// Base functionality for all errors in Rust. -pub trait Error: Send { - /// A short description of the error; usually a static string. - fn description(&self) -> &str; - - /// A detailed description of the error, usually including dynamic information. - fn detail(&self) -> Option { unimplemented!() } - - /// The lower-level cause of this error, if any. - fn cause(&self) -> Option<&Error> { unimplemented!() } -} - -/// A trait for types that can be converted from a given error type `E`. -pub trait FromError { - /// Perform the conversion. - fn from_error(err: E) -> Self; -} - -// Any type is convertable from itself -impl FromError for E { - fn from_error(err: E) -> E { unimplemented!() } -} diff --git a/src/libst2/failure.rs b/src/libst2/failure.rs deleted file mode 100644 index 9dad72266db27..0000000000000 --- a/src/libst2/failure.rs +++ /dev/null @@ -1,37 +0,0 @@ -// 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. - -#![experimental] - -use alloc::boxed::Box; -use any::{Any, AnyRefExt}; -use cell::RefCell; -use fmt; -use io::{Writer, IoResult}; -use kinds::Send; -use option::{Some, None, Option}; -use result::Ok; -use rt::backtrace; -use rustrt::{Stderr, Stdio}; -use rustrt::local::Local; -use rustrt::task::Task; -use str::Str; -use string::String; - -// Defined in this module instead of io::stdio so that the unwinding -thread_local!(pub static LOCAL_STDERR: RefCell>> = { - RefCell::new(None) -}) - -impl Writer for Stdio { - fn write(&mut self, bytes: &[u8]) -> IoResult<()> { unimplemented!() } -} - -pub fn on_fail(obj: &Any + Send, file: &'static str, line: uint) { unimplemented!() } diff --git a/src/libst2/fmt.rs b/src/libst2/fmt.rs deleted file mode 100644 index 0c4d2b24558a3..0000000000000 --- a/src/libst2/fmt.rs +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15679 - -/*! - -Utilities for formatting and printing strings - -This module contains the runtime support for the `format!` syntax extension. -This macro is implemented in the compiler to emit calls to this module in order -to format arguments at runtime into strings and streams. - -The functions contained in this module should not normally be used in everyday -use cases of `format!`. The assumptions made by these functions are unsafe for -all inputs, and the compiler performs a large amount of validation on the -arguments to `format!` in order to ensure safety at runtime. While it is -possible to call these functions directly, it is not recommended to do so in the -general case. - -## Usage - -The `format!` macro is intended to be familiar to those coming from C's -printf/fprintf functions or Python's `str.format` function. In its current -revision, the `format!` macro returns a `String` type which is the result of -the formatting. In the future it will also be able to pass in a stream to -format arguments directly while performing minimal allocations. - -Some examples of the `format!` extension are: - -```rust -# fn main() { -format!("Hello"); // => "Hello" -format!("Hello, {}!", "world"); // => "Hello, world!" -format!("The number is {}", 1i); // => "The number is 1" -format!("{}", (3i, 4i)); // => "(3, 4)" -format!("{value}", value=4i); // => "4" -format!("{} {}", 1i, 2u); // => "1 2" -# } -``` - -From these, you can see that the first argument is a format string. It is -required by the compiler for this to be a string literal; it cannot be a -variable passed in (in order to perform validity checking). The compiler will -then parse the format string and determine if the list of arguments provided is -suitable to pass to this format string. - -### Positional parameters - -Each formatting argument is allowed to specify which value argument it's -referencing, and if omitted it is assumed to be "the next argument". For -example, the format string `{} {} {}` would take three parameters, and they -would be formatted in the same order as they're given. The format string -`{2} {1} {0}`, however, would format arguments in reverse order. - -Things can get a little tricky once you start intermingling the two types of -positional specifiers. The "next argument" specifier can be thought of as an -iterator over the argument. Each time a "next argument" specifier is seen, the -iterator advances. This leads to behavior like this: - -```rust -format!("{1} {} {0} {}", 1i, 2i); // => "2 1 1 2" -``` - -The internal iterator over the argument has not been advanced by the time the -first `{}` is seen, so it prints the first argument. Then upon reaching the -second `{}`, the iterator has advanced forward to the second argument. -Essentially, parameters which explicitly name their argument do not affect -parameters which do not name an argument in terms of positional specifiers. - -A format string is required to use all of its arguments, otherwise it is a -compile-time error. You may refer to the same argument more than once in the -format string, although it must always be referred to with the same type. - -### Named parameters - -Rust itself does not have a Python-like equivalent of named parameters to a -function, but the `format!` macro is a syntax extension which allows it to -leverage named parameters. Named parameters are listed at the end of the -argument list and have the syntax: - -```text -identifier '=' expression -``` - -For example, the following `format!` expressions all use named argument: - -```rust -# fn main() { -format!("{argument}", argument = "test"); // => "test" -format!("{name} {}", 1i, name = 2i); // => "2 1" -format!("{a} {c} {b}", a="a", b=(), c=3i); // => "a 3 ()" -# } -``` - -It is illegal to put positional parameters (those without names) after arguments -which have names. Like with positional parameters, it is illegal to provide -named parameters that are unused by the format string. - -### Argument types - -Each argument's type is dictated by the format string. It is a requirement that -every argument is only ever referred to by one type. For example, this is an -invalid format string: - -```text -{0:d} {0:s} -``` - -This is invalid because the first argument is both referred to as an integer as -well as a string. - -Because formatting is done via traits, there is no requirement that the -`d` format actually takes an `int`, but rather it simply requires a type which -ascribes to the `Signed` formatting trait. There are various parameters which do -require a particular type, however. Namely if the syntax `{:.*s}` is used, then -the number of characters to print from the string precedes the actual string and -must have the type `uint`. Although a `uint` can be printed with `{:u}`, it is -illegal to reference an argument as such. For example, this is another invalid -format string: - -```text -{:.*s} {0:u} -``` - -### Formatting traits - -When requesting that an argument be formatted with a particular type, you are -actually requesting that an argument ascribes to a particular trait. This allows -multiple actual types to be formatted via `{:d}` (like `i8` as well as `int`). -The current mapping of types to traits is: - -* *nothing* ⇒ `Show` -* `o` ⇒ `Octal` -* `x` ⇒ `LowerHex` -* `X` ⇒ `UpperHex` -* `p` ⇒ `Pointer` -* `b` ⇒ `Binary` -* `e` ⇒ `LowerExp` -* `E` ⇒ `UpperExp` - -What this means is that any type of argument which implements the -`std::fmt::Binary` trait can then be formatted with `{:b}`. Implementations are -provided for these traits for a number of primitive types by the standard -library as well. If no format is specified (as in `{}` or `{:6}`), then the -format trait used is the `Show` trait. This is one of the more commonly -implemented traits when formatting a custom type. - -When implementing a format trait for your own type, you will have to implement a -method of the signature: - -```rust -# use std; -# mod fmt { pub type Result = (); } -# struct T; -# trait SomeName { -fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result; -# } -``` - -Your type will be passed as `self` by-reference, and then the function should -emit output into the `f.buf` stream. It is up to each format trait -implementation to correctly adhere to the requested formatting parameters. The -values of these parameters will be listed in the fields of the `Formatter` -struct. In order to help with this, the `Formatter` struct also provides some -helper methods. - -Additionally, the return value of this function is `fmt::Result` which is a -typedef to `Result<(), IoError>` (also known as `IoResult<()>`). Formatting -implementations should ensure that they return errors from `write!` correctly -(propagating errors upward). - -An example of implementing the formatting traits would look -like: - -```rust -use std::fmt; -use std::f64; -use std::num::Float; - -struct Vector2D { - x: int, - y: int, -} - -impl fmt::Show for Vector2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // The `f` value implements the `Writer` trait, which is what the - // write! macro is expecting. Note that this formatting ignores the - // various flags provided to format strings. - write!(f, "({}, {})", self.x, self.y) - } -} - -// Different traits allow different forms of output of a type. The meaning of -// this format is to print the magnitude of a vector. -impl fmt::Binary for Vector2D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let magnitude = (self.x * self.x + self.y * self.y) as f64; - let magnitude = magnitude.sqrt(); - - // Respect the formatting flags by using the helper method - // `pad_integral` on the Formatter object. See the method documentation - // for details, and the function `pad` can be used to pad strings. - let decimals = f.precision().unwrap_or(3); - let string = f64::to_str_exact(magnitude, decimals); - f.pad_integral(true, "", string.as_bytes()) - } -} - -fn main() { - let myvector = Vector2D { x: 3, y: 4 }; - - println!("{}", myvector); // => "(3, 4)" - println!("{:10.3b}", myvector); // => " 5.000" -} -``` - -### Related macros - -There are a number of related macros in the `format!` family. The ones that are -currently implemented are: - -```ignore -format! // described above -write! // first argument is a &mut io::Writer, the destination -writeln! // same as write but appends a newline -print! // the format string is printed to the standard output -println! // same as print but appends a newline -format_args! // described below. -``` - - -#### `write!` - -This and `writeln` are two macros which are used to emit the format string to a -specified stream. This is used to prevent intermediate allocations of format -strings and instead directly write the output. Under the hood, this function is -actually invoking the `write` function defined in this module. Example usage is: - -```rust -# #![allow(unused_must_use)] -use std::io; - -let mut w = Vec::new(); -write!(&mut w as &mut io::Writer, "Hello {}!", "world"); -``` - -#### `print!` - -This and `println` emit their output to stdout. Similarly to the `write!` macro, -the goal of these macros is to avoid intermediate allocations when printing -output. Example usage is: - -```rust -print!("Hello {}!", "world"); -println!("I have a newline {}", "character at the end"); -``` - -#### `format_args!` -This is a curious macro which is used to safely pass around -an opaque object describing the format string. This object -does not require any heap allocations to create, and it only -references information on the stack. Under the hood, all of -the related macros are implemented in terms of this. First -off, some example usage is: - -``` -use std::fmt; -use std::io; - -# #[allow(unused_must_use)] -# fn main() { -format_args!(fmt::format, "this returns {}", "String"); - -let some_writer: &mut io::Writer = &mut io::stdout(); -format_args!(|args| { write!(some_writer, "{}", args) }, "print with a {}", "closure"); - -fn my_fmt_fn(args: &fmt::Arguments) { - write!(&mut io::stdout(), "{}", args); -} -format_args!(my_fmt_fn, "or a {} too", "function"); -# } -``` - -The first argument of the `format_args!` macro is a function (or closure) which -takes one argument of type `&fmt::Arguments`. This structure can then be -passed to the `write` and `format` functions inside this module in order to -process the format string. The goal of this macro is to even further prevent -intermediate allocations when dealing formatting strings. - -For example, a logging library could use the standard formatting syntax, but it -would internally pass around this structure until it has been determined where -output should go to. - -It is unsafe to programmatically create an instance of `fmt::Arguments` because -the operations performed when executing a format string require the compile-time -checks provided by the compiler. The `format_args!` macro is the only method of -safely creating these structures, but they can be unsafely created with the -constructor provided. - -## Syntax - -The syntax for the formatting language used is drawn from other languages, so it -should not be too alien. Arguments are formatted with python-like syntax, -meaning that arguments are surrounded by `{}` instead of the C-like `%`. The -actual grammar for the formatting syntax is: - -```text -format_string := [ format ] * -format := '{' [ argument ] [ ':' format_spec ] '}' -argument := integer | identifier - -format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type] -fill := character -align := '<' | '^' | '>' -sign := '+' | '-' -width := count -precision := count | '*' -type := identifier | '' -count := parameter | integer -parameter := integer '$' -``` - -## Formatting Parameters - -Each argument being formatted can be transformed by a number of formatting -parameters (corresponding to `format_spec` in the syntax above). These -parameters affect the string representation of what's being formatted. This -syntax draws heavily from Python's, so it may seem a bit familiar. - -### Fill/Alignment - -The fill character is provided normally in conjunction with the `width` -parameter. This indicates that if the value being formatted is smaller than -`width` some extra characters will be printed around it. The extra characters -are specified by `fill`, and the alignment can be one of two options: - -* `<` - the argument is left-aligned in `width` columns -* `^` - the argument is center-aligned in `width` columns -* `>` - the argument is right-aligned in `width` columns - -### Sign/#/0 - -These can all be interpreted as flags for a particular formatter. - -* '+' - This is intended for numeric types and indicates that the sign should - always be printed. Positive signs are never printed by default, and the - negative sign is only printed by default for the `Signed` trait. This - flag indicates that the correct sign (+ or -) should always be printed. -* '-' - Currently not used -* '#' - This flag is indicates that the "alternate" form of printing should be - used. By default, this only applies to the integer formatting traits and - performs like: - * `x` - precedes the argument with a "0x" - * `X` - precedes the argument with a "0x" - * `t` - precedes the argument with a "0b" - * `o` - precedes the argument with a "0o" -* '0' - This is used to indicate for integer formats that the padding should - both be done with a `0` character as well as be sign-aware. A format - like `{:08d}` would yield `00000001` for the integer `1`, while the same - format would yield `-0000001` for the integer `-1`. Notice that the - negative version has one fewer zero than the positive version. - -### Width - -This is a parameter for the "minimum width" that the format should take up. If -the value's string does not fill up this many characters, then the padding -specified by fill/alignment will be used to take up the required space. - -The default fill/alignment for non-numerics is a space and left-aligned. The -defaults for numeric formatters is also a space but with right-alignment. If the -'0' flag is specified for numerics, then the implicit fill character is '0'. - -The value for the width can also be provided as a `uint` in the list of -parameters by using the `2$` syntax indicating that the second argument is a -`uint` specifying the width. - -### Precision - -For non-numeric types, this can be considered a "maximum width". If the -resulting string is longer than this width, then it is truncated down to this -many characters and only those are emitted. - -For integral types, this has no meaning currently. - -For floating-point types, this indicates how many digits after the decimal point -should be printed. - -## Escaping - -The literal characters `{` and `}` may be included in a string by preceding them -with the same character. For example, the `{` character is escaped with `{{` and -the `}` character is escaped with `}}`. - -*/ - -#![experimental] - -use io::Writer; -use io; -use result::{Ok, Err}; -use string; -use vec::Vec; - -pub use core::fmt::{Formatter, Result, FormatWriter, rt}; -pub use core::fmt::{Show, Octal, Binary}; -pub use core::fmt::{LowerHex, UpperHex, Pointer}; -pub use core::fmt::{LowerExp, UpperExp}; -pub use core::fmt::Error; -pub use core::fmt::{Argument, Arguments, write, radix, Radix, RadixFmt}; - -#[doc(hidden)] -pub use core::fmt::{argument, argumentstr, argumentuint}; - -/// The format function takes a precompiled format string and a list of -/// arguments, to return the resulting formatted string. -/// -/// # Arguments -/// -/// * args - a structure of arguments generated via the `format_args!` macro. -/// Because this structure can only be safely generated at -/// compile-time, this function is safe. -/// -/// # Example -/// -/// ```rust -/// use std::fmt; -/// -/// let s = format_args!(fmt::format, "Hello, {}!", "world"); -/// assert_eq!(s, "Hello, world!".to_string()); -/// ``` -#[experimental = "this is an implementation detail of format! and should not \ - be called directly"] -pub fn format(args: &Arguments) -> string::String { unimplemented!() } - -impl<'a> Writer for Formatter<'a> { - fn write(&mut self, b: &[u8]) -> io::IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/hash.rs b/src/libst2/hash.rs deleted file mode 100644 index 23f9ee827da85..0000000000000 --- a/src/libst2/hash.rs +++ /dev/null @@ -1,94 +0,0 @@ -// 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. - -/*! - * Generic hashing support. - * - * This module provides a generic way to compute the hash of a value. The - * simplest way to make a type hashable is to use `#[deriving(Hash)]`: - * - * # Example - * - * ```rust - * use std::hash; - * use std::hash::Hash; - * - * #[deriving(Hash)] - * struct Person { - * id: uint, - * name: String, - * phone: u64, - * } - * - * let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; - * let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; - * - * assert!(hash::hash(&person1) != hash::hash(&person2)); - * ``` - * - * If you need more control over how a value is hashed, you need to implement - * the trait `Hash`: - * - * ```rust - * use std::hash; - * use std::hash::Hash; - * use std::hash::sip::SipState; - * - * struct Person { - * id: uint, - * name: String, - * phone: u64, - * } - * - * impl Hash for Person { - * fn hash(&self, state: &mut SipState) { - * self.id.hash(state); - * self.phone.hash(state); - * } - * } - * - * let person1 = Person { id: 5, name: "Janet".to_string(), phone: 555_666_7777 }; - * let person2 = Person { id: 5, name: "Bob".to_string(), phone: 555_666_7777 }; - * - * assert!(hash::hash(&person1) == hash::hash(&person2)); - * ``` - */ - -#![experimental] - -pub use core_collections::hash::{Hash, Hasher, Writer, hash, sip}; - -use core::kinds::Sized; -use default::Default; -use rand::Rng; -use rand; - -/// `RandomSipHasher` computes the SipHash algorithm from a stream of bytes -/// initialized with random keys. -#[deriving(Clone)] -pub struct RandomSipHasher { - hasher: sip::SipHasher, -} - -impl RandomSipHasher { - /// Construct a new `RandomSipHasher` that is initialized with random keys. - #[inline] - pub fn new() -> RandomSipHasher { unimplemented!() } -} - -impl Hasher for RandomSipHasher { - #[inline] - fn hash>(&self, value: &T) -> u64 { unimplemented!() } -} - -impl Default for RandomSipHasher { - #[inline] - fn default() -> RandomSipHasher { unimplemented!() } -} diff --git a/src/libst2/io/buffered.rs b/src/libst2/io/buffered.rs deleted file mode 100644 index 1a9900ee9892d..0000000000000 --- a/src/libst2/io/buffered.rs +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 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. -// -// ignore-lexer-test FIXME #15883 - -//! Buffering wrappers for I/O traits - -use cmp; -use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; -use iter::ExactSize; -use ops::Drop; -use option::{Some, None, Option}; -use result::{Ok, Err}; -use slice::{SlicePrelude}; -use slice; -use vec::Vec; - -/// Wraps a Reader and buffers input from it -/// -/// It can be excessively inefficient to work directly with a `Reader`. For -/// example, every call to `read` on `TcpStream` results in a system call. A -/// `BufferedReader` performs large, infrequent reads on the underlying -/// `Reader` and maintains an in-memory buffer of the results. -/// -/// # Example -/// -/// ```rust -/// use std::io::{BufferedReader, File}; -/// -/// let file = File::open(&Path::new("message.txt")); -/// let mut reader = BufferedReader::new(file); -/// -/// let mut buf = [0, ..100]; -/// match reader.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("error reading: {}", e) -/// } -/// ``` -pub struct BufferedReader { - inner: R, - buf: Vec, - pos: uint, - cap: uint, -} - -impl BufferedReader { - /// Creates a new `BufferedReader` with the specified buffer capacity - pub fn with_capacity(cap: uint, inner: R) -> BufferedReader { unimplemented!() } - - /// Creates a new `BufferedReader` with a default buffer capacity - pub fn new(inner: R) -> BufferedReader { unimplemented!() } - - /// Gets a reference to the underlying reader. - /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a R { unimplemented!() } - - /// Unwraps this `BufferedReader`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. - pub fn unwrap(self) -> R { unimplemented!() } -} - -impl Buffer for BufferedReader { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - - fn consume(&mut self, amt: uint) { unimplemented!() } -} - -impl Reader for BufferedReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -/// Wraps a Writer and buffers output to it -/// -/// It can be excessively inefficient to work directly with a `Writer`. For -/// example, every call to `write` on `TcpStream` results in a system call. A -/// `BufferedWriter` keeps an in memory buffer of data and writes it to the -/// underlying `Writer` in large, infrequent batches. -/// -/// This writer will be flushed when it is dropped. -/// -/// # Example -/// -/// ```rust -/// use std::io::{BufferedWriter, File}; -/// -/// let file = File::create(&Path::new("message.txt")).unwrap(); -/// let mut writer = BufferedWriter::new(file); -/// -/// writer.write_str("hello, world").unwrap(); -/// writer.flush().unwrap(); -/// ``` -pub struct BufferedWriter { - inner: Option, - buf: Vec, - pos: uint -} - -impl BufferedWriter { - /// Creates a new `BufferedWriter` with the specified buffer capacity - pub fn with_capacity(cap: uint, inner: W) -> BufferedWriter { unimplemented!() } - - /// Creates a new `BufferedWriter` with a default buffer capacity - pub fn new(inner: W) -> BufferedWriter { unimplemented!() } - - fn flush_buf(&mut self) -> IoResult<()> { unimplemented!() } - - /// Gets a reference to the underlying writer. - /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a W { unimplemented!() } - - /// Unwraps this `BufferedWriter`, returning the underlying writer. - /// - /// The buffer is flushed before returning the writer. - pub fn unwrap(mut self) -> W { unimplemented!() } -} - -impl Writer for BufferedWriter { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - -#[unsafe_destructor] -impl Drop for BufferedWriter { - fn drop(&mut self) { unimplemented!() } -} - -/// Wraps a Writer and buffers output to it, flushing whenever a newline (`0x0a`, -/// `'\n'`) is detected. -/// -/// This writer will be flushed when it is dropped. -pub struct LineBufferedWriter { - inner: BufferedWriter, -} - -impl LineBufferedWriter { - /// Creates a new `LineBufferedWriter` - pub fn new(inner: W) -> LineBufferedWriter { unimplemented!() } - - /// Gets a reference to the underlying writer. - /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a W { unimplemented!() } - - /// Unwraps this `LineBufferedWriter`, returning the underlying writer. - /// - /// The internal buffer is flushed before returning the writer. - pub fn unwrap(self) -> W { unimplemented!() } -} - -impl Writer for LineBufferedWriter { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - -struct InternalBufferedWriter(BufferedWriter); - -impl InternalBufferedWriter { - fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter { unimplemented!() } -} - -impl Reader for InternalBufferedWriter { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -/// Wraps a Stream and buffers input and output to and from it. -/// -/// It can be excessively inefficient to work directly with a `Stream`. For -/// example, every call to `read` or `write` on `TcpStream` results in a system -/// call. A `BufferedStream` keeps in memory buffers of data, making large, -/// infrequent calls to `read` and `write` on the underlying `Stream`. -/// -/// The output half will be flushed when this stream is dropped. -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::{BufferedStream, File}; -/// -/// let file = File::open(&Path::new("message.txt")); -/// let mut stream = BufferedStream::new(file); -/// -/// stream.write("hello, world".as_bytes()); -/// stream.flush(); -/// -/// let mut buf = [0, ..100]; -/// match stream.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("error reading: {}", e) -/// } -/// ``` -pub struct BufferedStream { - inner: BufferedReader> -} - -impl BufferedStream { - /// Creates a new buffered stream with explicitly listed capacities for the - /// reader/writer buffer. - pub fn with_capacities(reader_cap: uint, writer_cap: uint, inner: S) - -> BufferedStream { unimplemented!() } - - /// Creates a new buffered stream with the default reader/writer buffer - /// capacities. - pub fn new(inner: S) -> BufferedStream { unimplemented!() } - - /// Gets a reference to the underlying stream. - /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a S { unimplemented!() } - - /// Unwraps this `BufferedStream`, returning the underlying stream. - /// - /// The internal buffer is flushed before returning the stream. Any leftover - /// data in the read buffer is lost. - pub fn unwrap(self) -> S { unimplemented!() } -} - -impl Buffer for BufferedStream { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - fn consume(&mut self, amt: uint) { unimplemented!() } -} - -impl Reader for BufferedStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for BufferedStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/io/comm_adapters.rs b/src/libst2/io/comm_adapters.rs deleted file mode 100644 index 5dff2143c7740..0000000000000 --- a/src/libst2/io/comm_adapters.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 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. - -use clone::Clone; -use cmp; -use comm::{Sender, Receiver}; -use io; -use option::{None, Some}; -use result::{Ok, Err}; -use slice::{bytes, CloneSliceAllocPrelude, SlicePrelude}; -use super::{Buffer, Reader, Writer, IoResult}; -use vec::Vec; - -/// Allows reading from a rx. -/// -/// # Example -/// -/// ``` -/// use std::io::ChanReader; -/// -/// let (tx, rx) = channel(); -/// # drop(tx); -/// let mut reader = ChanReader::new(rx); -/// -/// let mut buf = [0u8, ..100]; -/// match reader.read(&mut buf) { -/// Ok(nread) => println!("Read {} bytes", nread), -/// Err(e) => println!("read error: {}", e), -/// } -/// ``` -pub struct ChanReader { - buf: Vec, // A buffer of bytes received but not consumed. - pos: uint, // How many of the buffered bytes have already be consumed. - rx: Receiver>, // The Receiver to pull data from. - closed: bool, // Whether the channel this Receiver connects to has been closed. -} - -impl ChanReader { - /// Wraps a `Port` in a `ChanReader` structure - pub fn new(rx: Receiver>) -> ChanReader { unimplemented!() } -} - -impl Buffer for ChanReader { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - - fn consume(&mut self, amt: uint) { unimplemented!() } -} - -impl Reader for ChanReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -/// Allows writing to a tx. -/// -/// # Example -/// -/// ``` -/// # #![allow(unused_must_use)] -/// use std::io::ChanWriter; -/// -/// let (tx, rx) = channel(); -/// # drop(rx); -/// let mut writer = ChanWriter::new(tx); -/// writer.write("hello, world".as_bytes()); -/// ``` -pub struct ChanWriter { - tx: Sender>, -} - -impl ChanWriter { - /// Wraps a channel in a `ChanWriter` structure - pub fn new(tx: Sender>) -> ChanWriter { unimplemented!() } -} - -impl Clone for ChanWriter { - fn clone(&self) -> ChanWriter { unimplemented!() } -} - -impl Writer for ChanWriter { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/io/extensions.rs b/src/libst2/io/extensions.rs deleted file mode 100644 index 5b59ba6fdfa8d..0000000000000 --- a/src/libst2/io/extensions.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013-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. - -//! Utility mixins that apply to all Readers and Writers - -#![allow(missing_docs)] - -// FIXME: Not sure how this should be structured -// FIXME: Iteration should probably be considered separately - -use io::{IoError, IoResult, Reader}; -use io; -use iter::Iterator; -use num::Int; -use option::{Option, Some, None}; -use ptr::RawPtr; -use result::{Ok, Err}; -use slice::{SlicePrelude, AsSlice}; - -/// An iterator that reads a single byte on each iteration, -/// until `.read_byte()` returns `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Bytes` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Bytes<'r, T:'r> { - reader: &'r mut T, -} - -impl<'r, R: Reader> Bytes<'r, R> { - /// Constructs a new byte iterator from the given Reader instance. - pub fn new(r: &'r mut R) -> Bytes<'r, R> { unimplemented!() } -} - -impl<'r, R: Reader> Iterator> for Bytes<'r, R> { - #[inline] - fn next(&mut self) -> Option> { unimplemented!() } -} - -/// Converts an 8-bit to 64-bit unsigned value to a little-endian byte -/// representation of the given size. If the size is not big enough to -/// represent the value, then the high-order bytes are truncated. -/// -/// Arguments: -/// -/// * `n`: The value to convert. -/// * `size`: The size of the value, in bytes. This must be 8 or less, or task -/// panic occurs. If this is less than 8, then a value of that -/// many bytes is produced. For example, if `size` is 4, then a -/// 32-bit byte representation is produced. -/// * `f`: A callback that receives the value. -/// -/// This function returns the value returned by the callback, for convenience. -pub fn u64_to_le_bytes(n: u64, size: uint, f: |v: &[u8]| -> T) -> T { unimplemented!() } - -/// Converts an 8-bit to 64-bit unsigned value to a big-endian byte -/// representation of the given size. If the size is not big enough to -/// represent the value, then the high-order bytes are truncated. -/// -/// Arguments: -/// -/// * `n`: The value to convert. -/// * `size`: The size of the value, in bytes. This must be 8 or less, or task -/// panic occurs. If this is less than 8, then a value of that -/// many bytes is produced. For example, if `size` is 4, then a -/// 32-bit byte representation is produced. -/// * `f`: A callback that receives the value. -/// -/// This function returns the value returned by the callback, for convenience. -pub fn u64_to_be_bytes(n: u64, size: uint, f: |v: &[u8]| -> T) -> T { unimplemented!() } - -/// Extracts an 8-bit to 64-bit unsigned big-endian value from the given byte -/// buffer and returns it as a 64-bit value. -/// -/// Arguments: -/// -/// * `data`: The buffer in which to extract the value. -/// * `start`: The offset at which to extract the value. -/// * `size`: The size of the value in bytes to extract. This must be 8 or -/// less, or task panic occurs. If this is less than 8, then only -/// that many bytes are parsed. For example, if `size` is 4, then a -/// 32-bit value is parsed. -pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 { unimplemented!() } diff --git a/src/libst2/io/fs.rs b/src/libst2/io/fs.rs deleted file mode 100644 index 097c228bc3b19..0000000000000 --- a/src/libst2/io/fs.rs +++ /dev/null @@ -1,530 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15679 - -/*! Synchronous File I/O - -This module provides a set of functions and traits for working -with regular files & directories on a filesystem. - -At the top-level of the module are a set of freestanding functions, associated -with various filesystem operations. They all operate on `Path` objects. - -All operations in this module, including those as part of `File` et al -block the task during execution. In the event of failure, all functions/methods -will return an `IoResult` type with an `Err` value. - -Also included in this module is an implementation block on the `Path` object -defined in `std::path::Path`. The impl adds useful methods about inspecting the -metadata of a file. This includes getting the `stat` information, reading off -particular bits of it, etc. - -# Example - -```rust -# #![allow(unused_must_use)] -use std::io::fs::PathExtensions; -use std::io::{File, fs}; - -let path = Path::new("foo.txt"); - -// create the file, whether it exists or not -let mut file = File::create(&path); -file.write(b"foobar"); -# drop(file); - -// open the file in read-only mode -let mut file = File::open(&path); -file.read_to_end(); - -println!("{}", path.stat().unwrap().size); -# drop(file); -fs::unlink(&path); -``` - -*/ - -use clone::Clone; -use io::standard_error; -use io::{FilePermission, Write, Open, FileAccess, FileMode}; -use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; -use io::{Read, Truncate, ReadWrite, Append}; -use io::UpdateIoError; -use io; -use iter::{Iterator, Extend}; -use option::{Some, None, Option}; -use path::{Path, GenericPath}; -use path; -use result::{Err, Ok}; -use slice::SlicePrelude; -use string::String; -use vec::Vec; - -use sys::fs as fs_imp; -use sys_common; - -/// Unconstrained file access type that exposes read and write operations -/// -/// Can be constructed via `File::open()`, `File::create()`, and -/// `File::open_mode()`. -/// -/// # Error -/// -/// This type will return errors as an `IoResult` if operations are -/// attempted against it for which its underlying file descriptor was not -/// configured at creation time, via the `FileAccess` parameter to -/// `File::open_mode()`. -pub struct File { - fd: fs_imp::FileDesc, - path: Path, - last_nread: int, -} - -impl sys_common::AsFileDesc for File { - fn as_fd(&self) -> &fs_imp::FileDesc { unimplemented!() } -} - -impl File { - /// Open a file at `path` in the mode specified by the `mode` and `access` - /// arguments - /// - /// # Example - /// - /// ```rust,should_fail - /// use std::io::{File, Open, ReadWrite}; - /// - /// let p = Path::new("/some/file/path.txt"); - /// - /// let file = match File::open_mode(&p, Open, ReadWrite) { - /// Ok(f) => f, - /// Err(e) => panic!("file error: {}", e), - /// }; - /// // do some stuff with that file - /// - /// // the file will be closed at the end of this block - /// ``` - /// - /// `FileMode` and `FileAccess` provide information about the permissions - /// context in which a given stream is created. More information about them - /// can be found in `std::io`'s docs. If a file is opened with `Write` - /// or `ReadWrite` access, then it will be created if it does not already - /// exist. - /// - /// Note that, with this function, a `File` is returned regardless of the - /// access-limitations indicated by `FileAccess` (e.g. calling `write` on a - /// `File` opened as `Read` will return an error at runtime). - /// - /// # Error - /// - /// This function will return an error under a number of different - /// circumstances, to include but not limited to: - /// - /// * Opening a file that does not exist with `Read` access. - /// * Attempting to open a file with a `FileAccess` that the user lacks - /// permissions for - /// * Filesystem-level errors (full disk, etc) - pub fn open_mode(path: &Path, - mode: FileMode, - access: FileAccess) -> IoResult { unimplemented!() } - - /// Attempts to open a file in read-only mode. This function is equivalent to - /// `File::open_mode(path, Open, Read)`, and will raise all of the same - /// errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Example - /// - /// ```rust - /// use std::io::File; - /// - /// let contents = File::open(&Path::new("foo.txt")).read_to_end(); - /// ``` - pub fn open(path: &Path) -> IoResult { unimplemented!() } - - /// Attempts to create a file in write-only mode. This function is - /// equivalent to `File::open_mode(path, Truncate, Write)`, and will - /// raise all of the same errors that `File::open_mode` does. - /// - /// For more information, see the `File::open_mode` function. - /// - /// # Example - /// - /// ```rust - /// # #![allow(unused_must_use)] - /// use std::io::File; - /// - /// let mut f = File::create(&Path::new("foo.txt")); - /// f.write(b"This is a sample file"); - /// # drop(f); - /// # ::std::io::fs::unlink(&Path::new("foo.txt")); - /// ``` - pub fn create(path: &Path) -> IoResult { unimplemented!() } - - /// Returns the original path which was used to open this file. - pub fn path<'a>(&'a self) -> &'a Path { unimplemented!() } - - /// Synchronizes all modifications to this file to its permanent storage - /// device. This will flush any internal buffers necessary to perform this - /// operation. - pub fn fsync(&mut self) -> IoResult<()> { unimplemented!() } - - /// This function is similar to `fsync`, except that it may not synchronize - /// file metadata to the filesystem. This is intended for use case which - /// must synchronize content, but don't need the metadata on disk. The goal - /// of this method is to reduce disk operations. - pub fn datasync(&mut self) -> IoResult<()> { unimplemented!() } - - /// Either truncates or extends the underlying file, updating the size of - /// this file to become `size`. This is equivalent to unix's `truncate` - /// function. - /// - /// If the `size` is less than the current file's size, then the file will - /// be shrunk. If it is greater than the current file's size, then the file - /// will be extended to `size` and have all of the intermediate data filled - /// in with 0s. - pub fn truncate(&mut self, size: i64) -> IoResult<()> { unimplemented!() } - - /// Returns true if the stream has reached the end of the file. - /// - /// If true, then this file will no longer continue to return data via - /// `read`. - /// - /// Note that the operating system will not return an `EOF` indicator - /// until you have attempted to read past the end of the file, so if - /// you've read _exactly_ the number of bytes in the file, this will - /// return `false`, not `true`. - pub fn eof(&self) -> bool { unimplemented!() } - - /// Queries information about the underlying file. - pub fn stat(&mut self) -> IoResult { unimplemented!() } -} - -/// Unlink a file from the underlying filesystem. -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::fs; -/// -/// let p = Path::new("/some/file/path.txt"); -/// fs::unlink(&p); -/// ``` -/// -/// Note that, just because an unlink call was successful, it is not -/// guaranteed that a file is immediately deleted (e.g. depending on -/// platform, other open file descriptors may prevent immediate removal) -/// -/// # Error -/// -/// This function will return an error if `path` points to a directory, if the -/// user lacks permissions to remove the file, or if some other filesystem-level -/// error occurs. -pub fn unlink(path: &Path) -> IoResult<()> { unimplemented!() } - -/// Given a path, query the file system to get information about a file, -/// directory, etc. This function will traverse symlinks to query -/// information about the destination file. -/// -/// # Example -/// -/// ```rust -/// use std::io::fs; -/// -/// let p = Path::new("/some/file/path.txt"); -/// match fs::stat(&p) { -/// Ok(stat) => { /* ... */ } -/// Err(e) => { /* handle error */ } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks the requisite permissions -/// to perform a `stat` call on the given `path` or if there is no entry in the -/// filesystem at the provided path. -pub fn stat(path: &Path) -> IoResult { unimplemented!() } - -/// Perform the same operation as the `stat` function, except that this -/// function does not traverse through symlinks. This will return -/// information about the symlink file instead of the file that it points -/// to. -/// -/// # Error -/// -/// See `stat` -pub fn lstat(path: &Path) -> IoResult { unimplemented!() } - -/// Rename a file or directory to a new name. -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::fs; -/// -/// fs::rename(&Path::new("foo"), &Path::new("bar")); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `from` doesn't exist, if -/// the process lacks permissions to view the contents, or if some other -/// intermittent I/O error occurs. -pub fn rename(from: &Path, to: &Path) -> IoResult<()> { unimplemented!() } - -/// Copies the contents of one file to another. This function will also -/// copy the permission bits of the original file to the destination file. -/// -/// Note that if `from` and `to` both point to the same file, then the file -/// will likely get truncated by this operation. -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::fs; -/// -/// fs::copy(&Path::new("foo.txt"), &Path::new("bar.txt")); -/// ``` -/// -/// # Error -/// -/// This function will return an error in the following situations, but is not -/// limited to just these cases: -/// -/// * The `from` path is not a file -/// * The `from` file does not exist -/// * The current process does not have the permission rights to access -/// `from` or write `to` -/// -/// Note that this copy is not atomic in that once the destination is -/// ensured to not exist, there is nothing preventing the destination from -/// being created and then destroyed by this operation. -pub fn copy(from: &Path, to: &Path) -> IoResult<()> { unimplemented!() } - -/// Changes the permission mode bits found on a file or a directory. This -/// function takes a mask from the `io` module -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io; -/// use std::io::fs; -/// -/// fs::chmod(&Path::new("file.txt"), io::USER_FILE); -/// fs::chmod(&Path::new("file.txt"), io::USER_READ | io::USER_WRITE); -/// fs::chmod(&Path::new("dir"), io::USER_DIR); -/// fs::chmod(&Path::new("file.exe"), io::USER_EXEC); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to change the attributes of the file, or if -/// some other I/O error is encountered. -pub fn chmod(path: &Path, mode: io::FilePermission) -> IoResult<()> { unimplemented!() } - -/// Change the user and group owners of a file at the specified path. -pub fn chown(path: &Path, uid: int, gid: int) -> IoResult<()> { - fs_imp::chown(path, uid, gid) - .update_err("couldn't chown path", |e| - format!("{}; path={}; uid={}; gid={}", e, path.display(), uid, gid)) -} - -/// Creates a new hard link on the filesystem. The `dst` path will be a -/// link pointing to the `src` path. Note that systems often require these -/// two paths to both be located on the same filesystem. -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } - -/// Creates a new symbolic link on the filesystem. The `dst` path will be a -/// symlink pointing to the `src` path. -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } - -/// Reads a symlink, returning the file that the symlink points to. -/// -/// # Error -/// -/// This function will return an error on failure. Failure conditions include -/// reading a file that does not exist or reading a file which is not a symlink. -pub fn readlink(path: &Path) -> IoResult { unimplemented!() } - -/// Create a new, empty directory at the provided path -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io; -/// use std::io::fs; -/// -/// let p = Path::new("/some/dir"); -/// fs::mkdir(&p, io::USER_RWX); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to make a -/// new directory at the provided `path`, or if the directory already exists. -pub fn mkdir(path: &Path, mode: FilePermission) -> IoResult<()> { unimplemented!() } - -/// Remove an existing, empty directory -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::fs; -/// -/// let p = Path::new("/some/dir"); -/// fs::rmdir(&p); -/// ``` -/// -/// # Error -/// -/// This function will return an error if the user lacks permissions to remove -/// the directory at the provided `path`, or if the directory isn't empty. -pub fn rmdir(path: &Path) -> IoResult<()> { unimplemented!() } - -/// Retrieve a vector containing all entries within a provided directory -/// -/// # Example -/// -/// ```rust -/// use std::io::fs::PathExtensions; -/// use std::io::fs; -/// use std::io; -/// -/// // one possible implementation of fs::walk_dir only visiting files -/// fn visit_dirs(dir: &Path, cb: |&Path|) -> io::IoResult<()> { -/// if dir.is_dir() { -/// let contents = try!(fs::readdir(dir)); -/// for entry in contents.iter() { -/// if entry.is_dir() { -/// try!(visit_dirs(entry, |p| cb(p))); -/// } else { -/// cb(entry); -/// } -/// } -/// Ok(()) -/// } else { -/// Err(io::standard_error(io::InvalidInput)) -/// } -/// } -/// ``` -/// -/// # Error -/// -/// This function will return an error if the provided `path` doesn't exist, if -/// the process lacks permissions to view the contents or if the `path` points -/// at a non-directory file -pub fn readdir(path: &Path) -> IoResult> { unimplemented!() } - -/// Returns an iterator which will recursively walk the directory structure -/// rooted at `path`. The path given will not be iterated over, and this will -/// perform iteration in some top-down order. The contents of unreadable -/// subdirectories are ignored. -pub fn walk_dir(path: &Path) -> IoResult { unimplemented!() } - -/// An iterator which walks over a directory -pub struct Directories { - stack: Vec, -} - -impl Iterator for Directories { - fn next(&mut self) -> Option { unimplemented!() } -} - -/// Recursively create a directory and all of its parent components if they -/// are missing. -/// -/// # Error -/// -/// See `fs::mkdir`. -pub fn mkdir_recursive(path: &Path, mode: FilePermission) -> IoResult<()> { unimplemented!() } - -/// Removes a directory at this path, after removing all its contents. Use -/// carefully! -/// -/// # Error -/// -/// See `file::unlink` and `fs::readdir` -pub fn rmdir_recursive(path: &Path) -> IoResult<()> { unimplemented!() } - -/// Changes the timestamps for a file's last modification and access time. -/// The file at the path specified will have its last access time set to -/// `atime` and its modification time set to `mtime`. The times specified should -/// be in milliseconds. -// FIXME(#10301) these arguments should not be u64 -pub fn change_file_times(path: &Path, atime: u64, mtime: u64) -> IoResult<()> { unimplemented!() } - -impl Reader for File { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for File { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -impl Seek for File { - fn tell(&self) -> IoResult { unimplemented!() } - - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } -} - -/// Utility methods for paths. -pub trait PathExtensions { - /// Get information on the file, directory, etc at this path. - /// - /// Consult the `fs::stat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::stat`. - fn stat(&self) -> IoResult; - - /// Get information on the file, directory, etc at this path, not following - /// symlinks. - /// - /// Consult the `fs::lstat` documentation for more info. - /// - /// This call preserves identical runtime/error semantics with `file::lstat`. - fn lstat(&self) -> IoResult; - - /// Boolean value indicator whether the underlying file exists on the local - /// filesystem. Returns false in exactly the cases where `fs::stat` fails. - fn exists(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) points at a "regular file" on the FS. Will return false for paths - /// to non-existent locations or directories or other non-regular files - /// (named pipes, etc). Follows links when making this determination. - fn is_file(&self) -> bool; - - /// Whether the underlying implementation (be it a file path, or something - /// else) is pointing at a directory in the underlying FS. Will return - /// false for paths to non-existent locations or if the item is not a - /// directory (eg files, named pipes, etc). Follows links when making this - /// determination. - fn is_dir(&self) -> bool; -} - -impl PathExtensions for path::Path { - fn stat(&self) -> IoResult { unimplemented!() } - fn lstat(&self) -> IoResult { unimplemented!() } - fn exists(&self) -> bool { unimplemented!() } - fn is_file(&self) -> bool { unimplemented!() } - fn is_dir(&self) -> bool { unimplemented!() } -} - -fn mode_string(mode: FileMode) -> &'static str { unimplemented!() } - -fn access_string(access: FileAccess) -> &'static str { unimplemented!() } diff --git a/src/libst2/io/mem.rs b/src/libst2/io/mem.rs deleted file mode 100644 index 910161cf3570c..0000000000000 --- a/src/libst2/io/mem.rs +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 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. -// -// ignore-lexer-test FIXME #15679 - -//! Readers and Writers for in-memory buffers - -#![allow(deprecated)] - -use cmp::min; -use option::None; -use result::{Err, Ok}; -use io; -use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; -use slice::{mod, AsSlice, SlicePrelude}; -use vec::Vec; - -const BUF_CAPACITY: uint = 128; - -fn combine(seek: SeekStyle, cur: uint, end: uint, offset: i64) -> IoResult { unimplemented!() } - -impl Writer for Vec { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -/// Writes to an owned, growable byte vector -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::MemWriter; -/// -/// let mut w = MemWriter::new(); -/// w.write(&[0, 1, 2]); -/// -/// assert_eq!(w.unwrap(), vec!(0, 1, 2)); -/// ``` -#[deprecated = "use the Vec Writer implementation directly"] -#[deriving(Clone)] -pub struct MemWriter { - buf: Vec, -} - -impl MemWriter { - /// Create a new `MemWriter`. - #[inline] - pub fn new() -> MemWriter { unimplemented!() } - /// Create a new `MemWriter`, allocating at least `n` bytes for - /// the internal buffer. - #[inline] - pub fn with_capacity(n: uint) -> MemWriter { unimplemented!() } - /// Create a new `MemWriter` that will append to an existing `Vec`. - #[inline] - pub fn from_vec(buf: Vec) -> MemWriter { unimplemented!() } - - /// Acquires an immutable reference to the underlying buffer of this - /// `MemWriter`. - #[inline] - pub fn get_ref<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - /// Unwraps this `MemWriter`, returning the underlying buffer - #[inline] - pub fn unwrap(self) -> Vec { unimplemented!() } -} - -impl Writer for MemWriter { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -/// Reads from an owned byte vector -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::MemReader; -/// -/// let mut r = MemReader::new(vec!(0, 1, 2)); -/// -/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2)); -/// ``` -pub struct MemReader { - buf: Vec, - pos: uint -} - -impl MemReader { - /// Creates a new `MemReader` which will read the buffer given. The buffer - /// can be re-acquired through `unwrap` - #[inline] - pub fn new(buf: Vec) -> MemReader { unimplemented!() } - - /// Tests whether this reader has read all bytes in its buffer. - /// - /// If `true`, then this will no longer return bytes from `read`. - #[inline] - pub fn eof(&self) -> bool { unimplemented!() } - - /// Acquires an immutable reference to the underlying buffer of this - /// `MemReader`. - /// - /// No method is exposed for acquiring a mutable reference to the buffer - /// because it could corrupt the state of this `MemReader`. - #[inline] - pub fn get_ref<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - /// Unwraps this `MemReader`, returning the underlying buffer - #[inline] - pub fn unwrap(self) -> Vec { unimplemented!() } -} - -impl Reader for MemReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Seek for MemReader { - #[inline] - fn tell(&self) -> IoResult { unimplemented!() } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } -} - -impl Buffer for MemReader { - #[inline] - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - - #[inline] - fn consume(&mut self, amt: uint) { unimplemented!() } -} - -/// Writes to a fixed-size byte slice -/// -/// If a write will not fit in the buffer, it returns an error and does not -/// write any data. -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::BufWriter; -/// -/// let mut buf = [0, ..4]; -/// { -/// let mut w = BufWriter::new(&mut buf); -/// w.write(&[0, 1, 2]); -/// } -/// assert!(buf == [0, 1, 2, 0]); -/// ``` -pub struct BufWriter<'a> { - buf: &'a mut [u8], - pos: uint -} - -impl<'a> BufWriter<'a> { - /// Creates a new `BufWriter` which will wrap the specified buffer. The - /// writer initially starts at position 0. - #[inline] - pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> { unimplemented!() } -} - -impl<'a> Writer for BufWriter<'a> { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -impl<'a> Seek for BufWriter<'a> { - #[inline] - fn tell(&self) -> IoResult { unimplemented!() } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } -} - -/// Reads from a fixed-size byte slice -/// -/// # Example -/// -/// ```rust -/// # #![allow(unused_must_use)] -/// use std::io::BufReader; -/// -/// let mut buf = [0, 1, 2, 3]; -/// let mut r = BufReader::new(&mut buf); -/// -/// assert_eq!(r.read_to_end().unwrap(), vec!(0, 1, 2, 3)); -/// ``` -pub struct BufReader<'a> { - buf: &'a [u8], - pos: uint -} - -impl<'a> BufReader<'a> { - /// Creates a new buffered reader which will read the specified buffer - #[inline] - pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> { unimplemented!() } - - /// Tests whether this reader has read all bytes in its buffer. - /// - /// If `true`, then this will no longer return bytes from `read`. - #[inline] - pub fn eof(&self) -> bool { unimplemented!() } -} - -impl<'a> Reader for BufReader<'a> { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl<'a> Seek for BufReader<'a> { - #[inline] - fn tell(&self) -> IoResult { unimplemented!() } - - #[inline] - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } -} - -impl<'a> Buffer for BufReader<'a> { - #[inline] - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - - #[inline] - fn consume(&mut self, amt: uint) { unimplemented!() } -} diff --git a/src/libst2/io/mod.rs b/src/libst2/io/mod.rs deleted file mode 100644 index e957f67db0282..0000000000000 --- a/src/libst2/io/mod.rs +++ /dev/null @@ -1,1258 +0,0 @@ -#![experimental] -#![deny(unused_must_use)] - -pub use self::SeekStyle::*; -pub use self::FileMode::*; -pub use self::FileAccess::*; -pub use self::FileType::*; -pub use self::IoErrorKind::*; - -use char::Char; -use clone::Clone; -use default::Default; -use error::{FromError, Error}; -use fmt; -use int; -use iter::Iterator; -use mem::transmute; -use ops::{BitOr, BitXor, BitAnd, Sub, Not}; -use option::{Option, Some, None}; -use os; -use boxed::Box; -use result::{Ok, Err, Result}; -use sys; -use slice::{AsSlice, SlicePrelude}; -use str::{Str, StrPrelude}; -use str; -use string::String; -use uint; -use unicode::char::UnicodeChar; -use vec::Vec; - -// Reexports -pub use self::stdio::stdin; -pub use self::stdio::stdout; -pub use self::stdio::stderr; -pub use self::stdio::print; -pub use self::stdio::println; - -pub use self::fs::File; -pub use self::timer::Timer; -pub use self::net::ip::IpAddr; -pub use self::net::tcp::TcpListener; -pub use self::net::tcp::TcpStream; -pub use self::net::udp::UdpStream; -pub use self::pipe::PipeStream; -pub use self::process::{Process, Command}; -pub use self::tempfile::TempDir; - -pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter}; -pub use self::buffered::{BufferedReader, BufferedWriter, BufferedStream, - LineBufferedWriter}; -pub use self::comm_adapters::{ChanReader, ChanWriter}; - -mod buffered; -mod comm_adapters; -mod mem; -mod result; -mod tempfile; -pub mod extensions; -pub mod fs; -pub mod net; -pub mod pipe; -pub mod process; -pub mod stdio; -pub mod test; -pub mod timer; -pub mod util; - -/// The default buffer size for various I/O operations -// libuv recommends 64k buffers to maximize throughput -// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA -const DEFAULT_BUF_SIZE: uint = 1024 * 64; - -/// A convenient typedef of the return value of any I/O action. -pub type IoResult = Result; - -/// The type passed to I/O condition handlers to indicate error -/// -/// # FIXME -/// -/// Is something like this sufficient? It's kind of archaic -#[deriving(PartialEq, Eq, Clone)] -pub struct IoError { - /// An enumeration which can be matched against for determining the flavor - /// of error. - pub kind: IoErrorKind, - /// A human-readable description about the error - pub desc: &'static str, - /// Detailed information about this error, not always available - pub detail: Option -} - -impl IoError { - /// Convert an `errno` value into an `IoError`. - /// - /// If `detail` is `true`, the `detail` field of the `IoError` - /// struct is filled with an allocated string describing the error - /// in more detail, retrieved from the operating system. - pub fn from_errno(errno: uint, detail: bool) -> IoError { unimplemented!() } - - /// Retrieve the last error to occur as a (detailed) IoError. - /// - /// This uses the OS `errno`, and so there should not be any task - /// descheduling or migration (other than that performed by the - /// operating system) between the call(s) for which errors are - /// being checked and the call of this function. - pub fn last_error() -> IoError { unimplemented!() } -} - -impl fmt::Show for IoError { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl Error for IoError { - fn description(&self) -> &str { unimplemented!() } - - fn detail(&self) -> Option { unimplemented!() } -} - -impl FromError for Box { - fn from_error(err: IoError) -> Box { unimplemented!() } -} - -/// A list specifying general categories of I/O error. -#[deriving(PartialEq, Eq, Clone, Show)] -pub enum IoErrorKind { - /// Any I/O error not part of this list. - OtherIoError, - /// The operation could not complete because end of file was reached. - EndOfFile, - /// The file was not found. - FileNotFound, - /// The file permissions disallowed access to this file. - PermissionDenied, - /// A network connection failed for some reason not specified in this list. - ConnectionFailed, - /// The network operation failed because the network connection was closed. - Closed, - /// The connection was refused by the remote server. - ConnectionRefused, - /// The connection was reset by the remote server. - ConnectionReset, - /// The connection was aborted (terminated) by the remote server. - ConnectionAborted, - /// The network operation failed because it was not connected yet. - NotConnected, - /// The operation failed because a pipe was closed. - BrokenPipe, - /// A file already existed with that name. - PathAlreadyExists, - /// No file exists at that location. - PathDoesntExist, - /// The path did not specify the type of file that this operation required. For example, - /// attempting to copy a directory with the `fs::copy()` operation will fail with this error. - MismatchedFileTypeForOperation, - /// The operation temporarily failed (for example, because a signal was received), and retrying - /// may succeed. - ResourceUnavailable, - /// No I/O functionality is available for this task. - IoUnavailable, - /// A parameter was incorrect in a way that caused an I/O error not part of this list. - InvalidInput, - /// The I/O operation's timeout expired, causing it to be canceled. - TimedOut, - /// This write operation failed to write all of its data. - /// - /// Normally the write() method on a Writer guarantees that all of its data - /// has been written, but some operations may be terminated after only - /// partially writing some data. An example of this is a timed out write - /// which successfully wrote a known number of bytes, but bailed out after - /// doing so. - /// - /// The payload contained as part of this variant is the number of bytes - /// which are known to have been successfully written. - ShortWrite(uint), - /// The Reader returned 0 bytes from `read()` too many times. - NoProgress, -} - -/// A trait that lets you add a `detail` to an IoError easily -trait UpdateIoError { - /// Returns an IoError with updated description and detail - fn update_err(self, desc: &'static str, detail: |&IoError| -> String) -> Self; - - /// Returns an IoError with updated detail - fn update_detail(self, detail: |&IoError| -> String) -> Self; - - /// Returns an IoError with update description - fn update_desc(self, desc: &'static str) -> Self; -} - -impl UpdateIoError for IoResult { - fn update_err(self, desc: &'static str, detail: |&IoError| -> String) -> IoResult { unimplemented!() } - - fn update_detail(self, detail: |&IoError| -> String) -> IoResult { unimplemented!() } - - fn update_desc(self, desc: &'static str) -> IoResult { unimplemented!() } -} - -static NO_PROGRESS_LIMIT: uint = 1000; - -/// A trait for objects which are byte-oriented streams. Readers are defined by -/// one method, `read`. This function will block until data is available, -/// filling in the provided buffer with any data read. -/// -/// Readers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Reader` trait. -pub trait Reader { - - // Only method which need to get implemented for this trait - - /// Read bytes, up to the length of `buf` and place them in `buf`. - /// Returns the number of bytes read. The number of bytes read may - /// be less than the number requested, even 0. Returns `Err` on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned as - /// `Err(IoError)`. Note that end-of-file is considered an error, and can be - /// inspected for in the error's `kind` field. Also note that reading 0 - /// bytes is not considered an error in all circumstances - /// - /// # Implementation Note - /// - /// When implementing this method on a new Reader, you are strongly encouraged - /// not to return 0 if you can avoid it. - fn read(&mut self, buf: &mut [u8]) -> IoResult; - - // Convenient helper methods based on the above methods - - /// Reads at least `min` bytes and places them in `buf`. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn read_at_least(&mut self, min: uint, buf: &mut [u8]) -> IoResult { unimplemented!() } - - /// Reads a single byte. Returns `Err` on EOF. - fn read_byte(&mut self) -> IoResult { unimplemented!() } - - /// Reads up to `len` bytes and appends them to a vector. - /// Returns the number of bytes read. The number of bytes read may be - /// less than the number requested, even 0. Returns Err on EOF. - /// - /// # Error - /// - /// If an error occurs during this I/O operation, then it is returned - /// as `Err(IoError)`. See `read()` for more details. - fn push(&mut self, len: uint, buf: &mut Vec) -> IoResult { unimplemented!() } - - /// Reads at least `min` bytes, but no more than `len`, and appends them to - /// a vector. - /// Returns the number of bytes read. - /// - /// This will continue to call `read` until at least `min` bytes have been - /// read. If `read` returns 0 too many times, `NoProgress` will be - /// returned. - /// - /// # Error - /// - /// If an error occurs at any point, that error is returned, and no further - /// bytes are read. - fn push_at_least(&mut self, min: uint, len: uint, buf: &mut Vec) -> IoResult { unimplemented!() } - - /// Reads exactly `len` bytes and gives you back a new vector of length - /// `len` - /// - /// # Error - /// - /// Fails with the same conditions as `read`. Additionally returns error - /// on EOF. Note that if an error is returned, then some number of bytes may - /// have already been consumed from the underlying reader, and they are lost - /// (not returned as part of the error). If this is unacceptable, then it is - /// recommended to use the `push_at_least` or `read` methods. - fn read_exact(&mut self, len: uint) -> IoResult> { unimplemented!() } - - /// Reads all remaining bytes from the stream. - /// - /// # Error - /// - /// Returns any non-EOF error immediately. Previously read bytes are - /// discarded when an error is returned. - /// - /// When EOF is encountered, all bytes read up to that point are returned. - fn read_to_end(&mut self) -> IoResult> { unimplemented!() } - - /// Reads all of the remaining bytes of this stream, interpreting them as a - /// UTF-8 encoded stream. The corresponding string is returned. - /// - /// # Error - /// - /// This function returns all of the same errors as `read_to_end` with an - /// additional error if the reader's contents are not a valid sequence of - /// UTF-8 bytes. - fn read_to_string(&mut self) -> IoResult { unimplemented!() } - - // Byte conversion helpers - - /// Reads `n` little-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } - - /// Reads `n` little-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } - - /// Reads `n` big-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } - - /// Reads `n` big-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: uint) -> IoResult { unimplemented!() } - - /// Reads a little-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_uint(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_le_int(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian unsigned integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_uint(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian integer. - /// - /// The number of bytes returned is system-dependent. - fn read_be_int(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a big-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> IoResult { unimplemented!() } - - /// Reads a little-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> IoResult { unimplemented!() } - - /// Read a u8. - /// - /// `u8`s are 1 byte. - fn read_u8(&mut self) -> IoResult { unimplemented!() } - - /// Read an i8. - /// - /// `i8`s are 1 byte. - fn read_i8(&mut self) -> IoResult { unimplemented!() } -} - -/// A reader which can be converted to a RefReader. -#[deprecated = "use ByRefReader instead"] -pub trait AsRefReader { - /// Creates a wrapper around a mutable reference to the reader. - /// - /// This is useful to allow applying adaptors while still - /// retaining ownership of the original value. - fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; -} - -#[allow(deprecated)] -impl AsRefReader for T { - fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { unimplemented!() } -} - -/// A reader which can be converted to a RefReader. -pub trait ByRefReader { - /// Creates a wrapper around a mutable reference to the reader. - /// - /// This is useful to allow applying adaptors while still - /// retaining ownership of the original value. - fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; -} - -impl ByRefReader for T { - fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { unimplemented!() } -} - -/// A reader which can be converted to bytes. -pub trait BytesReader { - /// Create an iterator that reads a single byte on - /// each iteration, until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self>; -} - -impl BytesReader for T { - fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { unimplemented!() } -} - -impl<'a> Reader for Box { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl<'a> Reader for &'a mut Reader+'a { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -/// Returns a slice of `v` between `start` and `end`. -/// -/// Similar to `slice()` except this function only bounds the slice on the -/// capacity of `v`, not the length. -/// -/// # Panics -/// -/// Panics when `start` or `end` point outside the capacity of `v`, or when -/// `start` > `end`. -// Private function here because we aren't sure if we want to expose this as -// API yet. If so, it should be a method on Vec. -unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) -> &'a mut [T] { unimplemented!() } - -/// A `RefReader` is a struct implementing `Reader` which contains a reference -/// to another reader. This is often useful when composing streams. -/// -/// # Example -/// -/// ``` -/// # fn main() {} -/// # fn process_input(r: R) {} -/// # fn foo() { -/// use std::io; -/// use std::io::ByRefReader; -/// use std::io::util::LimitReader; -/// -/// let mut stream = io::stdin(); -/// -/// // Only allow the function to process at most one kilobyte of input -/// { -/// let stream = LimitReader::new(stream.by_ref(), 1024); -/// process_input(stream); -/// } -/// -/// // 'stream' is still available for use here -/// -/// # } -/// ``` -pub struct RefReader<'a, R:'a> { - /// The underlying reader which this is referencing - inner: &'a mut R -} - -impl<'a, R: Reader> Reader for RefReader<'a, R> { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl<'a, R: Buffer> Buffer for RefReader<'a, R> { - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]> { unimplemented!() } - fn consume(&mut self, amt: uint) { unimplemented!() } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { unimplemented!() } - -/// A trait for objects which are byte-oriented streams. Writers are defined by -/// one method, `write`. This function will block until the provided buffer of -/// bytes has been entirely written, and it will return any failures which occur. -/// -/// Another commonly overridden method is the `flush` method for writers such as -/// buffered writers. -/// -/// Writers are intended to be composable with one another. Many objects -/// throughout the I/O and related libraries take and provide types which -/// implement the `Writer` trait. -pub trait Writer { - /// Write the entirety of a given buffer - /// - /// # Errors - /// - /// If an error happens during the I/O operation, the error is returned as - /// `Err`. Note that it is considered an error if the entire buffer could - /// not be written, and if an error is returned then it is unknown how much - /// data (if any) was actually written. - fn write(&mut self, buf: &[u8]) -> IoResult<()>; - - /// Flush this output stream, ensuring that all intermediately buffered - /// contents reach their destination. - /// - /// This is by default a no-op and implementers of the `Writer` trait should - /// decide whether their stream needs to be buffered or not. - fn flush(&mut self) -> IoResult<()> { unimplemented!() } - - /// Writes a formatted string into this writer, returning any error - /// encountered. - /// - /// This method is primarily used to interface with the `format_args!` - /// macro, but it is rare that this should explicitly be called. The - /// `write!` macro should be favored to invoke this method instead. - /// - /// # Errors - /// - /// This function will return any I/O error reported while formatting. - fn write_fmt(&mut self, fmt: &fmt::Arguments) -> IoResult<()> { unimplemented!() } - - /// Write a rust string into this sink. - /// - /// The bytes written will be the UTF-8 encoded version of the input string. - /// If other encodings are desired, it is recommended to compose this stream - /// with another performing the conversion, or to use `write` with a - /// converted byte-array instead. - #[inline] - fn write_str(&mut self, s: &str) -> IoResult<()> { unimplemented!() } - - /// Writes a string into this sink, and then writes a literal newline (`\n`) - /// byte afterwards. Note that the writing of the newline is *not* atomic in - /// the sense that the call to `write` is invoked twice (once with the - /// string and once with a newline character). - /// - /// If other encodings or line ending flavors are desired, it is recommended - /// that the `write` method is used specifically instead. - #[inline] - fn write_line(&mut self, s: &str) -> IoResult<()> { unimplemented!() } - - /// Write a single char, encoded as UTF-8. - #[inline] - fn write_char(&mut self, c: char) -> IoResult<()> { unimplemented!() } - - /// Write the result of passing n through `int::to_str_bytes`. - #[inline] - fn write_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } - - /// Write the result of passing n through `uint::to_str_bytes`. - #[inline] - fn write_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian uint (number of bytes depends on system). - #[inline] - fn write_le_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian int (number of bytes depends on system). - #[inline] - fn write_le_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian uint (number of bytes depends on system). - #[inline] - fn write_be_uint(&mut self, n: uint) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian int (number of bytes depends on system). - #[inline] - fn write_be_int(&mut self, n: int) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian u64 (8 bytes). - #[inline] - fn write_be_u64(&mut self, n: u64) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian u32 (4 bytes). - #[inline] - fn write_be_u32(&mut self, n: u32) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian u16 (2 bytes). - #[inline] - fn write_be_u16(&mut self, n: u16) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian i64 (8 bytes). - #[inline] - fn write_be_i64(&mut self, n: i64) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian i32 (4 bytes). - #[inline] - fn write_be_i32(&mut self, n: i32) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian i16 (2 bytes). - #[inline] - fn write_be_i16(&mut self, n: i16) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - #[inline] - fn write_be_f64(&mut self, f: f64) -> IoResult<()> { unimplemented!() } - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - #[inline] - fn write_be_f32(&mut self, f: f32) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian u64 (8 bytes). - #[inline] - fn write_le_u64(&mut self, n: u64) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian u32 (4 bytes). - #[inline] - fn write_le_u32(&mut self, n: u32) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian u16 (2 bytes). - #[inline] - fn write_le_u16(&mut self, n: u16) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian i64 (8 bytes). - #[inline] - fn write_le_i64(&mut self, n: i64) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian i32 (4 bytes). - #[inline] - fn write_le_i32(&mut self, n: i32) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian i16 (2 bytes). - #[inline] - fn write_le_i16(&mut self, n: i16) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - #[inline] - fn write_le_f64(&mut self, f: f64) -> IoResult<()> { unimplemented!() } - - /// Write a little-endian IEEE754 single-precision floating-point - /// (4 bytes). - #[inline] - fn write_le_f32(&mut self, f: f32) -> IoResult<()> { unimplemented!() } - - /// Write a u8 (1 byte). - #[inline] - fn write_u8(&mut self, n: u8) -> IoResult<()> { unimplemented!() } - - /// Write an i8 (1 byte). - #[inline] - fn write_i8(&mut self, n: i8) -> IoResult<()> { unimplemented!() } -} - -/// A writer which can be converted to a RefWriter. -#[deprecated = "use ByRefWriter instead"] -pub trait AsRefWriter { - /// Creates a wrapper around a mutable reference to the writer. - /// - /// This is useful to allow applying wrappers while still - /// retaining ownership of the original value. - #[inline] - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; -} - -#[allow(deprecated)] -impl AsRefWriter for T { - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { unimplemented!() } -} - -/// A writer which can be converted to a RefWriter. -pub trait ByRefWriter { - /// Creates a wrapper around a mutable reference to the writer. - /// - /// This is useful to allow applying wrappers while still - /// retaining ownership of the original value. - #[inline] - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; -} - -impl ByRefWriter for T { - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { - RefWriter { inner: self } - } -} - -impl<'a> Writer for Box { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - #[inline] - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl<'a> Writer for &'a mut Writer+'a { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - #[inline] - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - -/// A `RefWriter` is a struct implementing `Writer` which contains a reference -/// to another writer. This is often useful when composing streams. -/// -/// # Example -/// -/// ``` -/// # fn main() {} -/// # fn process_input(r: R) {} -/// # fn foo () { -/// use std::io::util::TeeReader; -/// use std::io::{stdin, ByRefWriter}; -/// -/// let mut output = Vec::new(); -/// -/// { -/// // Don't give ownership of 'output' to the 'tee'. Instead we keep a -/// // handle to it in the outer scope -/// let mut tee = TeeReader::new(stdin(), output.by_ref()); -/// process_input(tee); -/// } -/// -/// println!("input processed: {}", output); -/// # } -/// ``` -pub struct RefWriter<'a, W:'a> { - /// The underlying writer which this is referencing - inner: &'a mut W -} - -impl<'a, W: Writer> Writer for RefWriter<'a, W> { - #[inline] - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - #[inline] - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - - -/// A Stream is a readable and a writable object. Data written is typically -/// received by the object which reads receive data from. -pub trait Stream: Reader + Writer { } - -impl Stream for T {} - -/// An iterator that reads a line on each iteration, -/// until `.read_line()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Lines` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Lines<'r, T:'r> { - buffer: &'r mut T, -} - -impl<'r, T: Buffer> Iterator> for Lines<'r, T> { - fn next(&mut self) -> Option> { unimplemented!() } -} - -/// An iterator that reads a utf8-encoded character on each iteration, -/// until `.read_char()` encounters `EndOfFile`. -/// -/// # Notes about the Iteration Protocol -/// -/// The `Chars` may yield `None` and thus terminate -/// an iteration, but continue to yield elements if iteration -/// is attempted again. -/// -/// # Error -/// -/// Any error other than `EndOfFile` that is produced by the underlying Reader -/// is returned by the iterator and should be handled by the caller. -pub struct Chars<'r, T:'r> { - buffer: &'r mut T -} - -impl<'r, T: Buffer> Iterator> for Chars<'r, T> { - fn next(&mut self) -> Option> { unimplemented!() } -} - -/// A Buffer is a type of reader which has some form of internal buffering to -/// allow certain kinds of reading operations to be more optimized than others. -/// This type extends the `Reader` trait with a few methods that are not -/// possible to reasonably implement with purely a read interface. -pub trait Buffer: Reader { - /// Fills the internal buffer of this object, returning the buffer contents. - /// Note that none of the contents will be "read" in the sense that later - /// calling `read` may return the same contents. - /// - /// The `consume` function must be called with the number of bytes that are - /// consumed from this buffer returned to ensure that the bytes are never - /// returned twice. - /// - /// # Error - /// - /// This function will return an I/O error if the underlying reader was - /// read, but returned an error. Note that it is not an error to return a - /// 0-length buffer. - fn fill_buf<'a>(&'a mut self) -> IoResult<&'a [u8]>; - - /// Tells this buffer that `amt` bytes have been consumed from the buffer, - /// so they should no longer be returned in calls to `read`. - fn consume(&mut self, amt: uint); - - /// Reads the next line of input, interpreted as a sequence of UTF-8 - /// encoded Unicode codepoints. If a newline is encountered, then the - /// newline is contained in the returned string. - /// - /// # Example - /// - /// ```rust - /// use std::io; - /// - /// let mut reader = io::stdin(); - /// let input = reader.read_line().ok().unwrap_or("nothing".to_string()); - /// ``` - /// - /// # Error - /// - /// This function has the same error semantics as `read_until`: - /// - /// * All non-EOF errors will be returned immediately - /// * If an error is returned previously consumed bytes are lost - /// * EOF is only returned if no bytes have been read - /// * Reach EOF may mean that the delimiter is not present in the return - /// value - /// - /// Additionally, this function can fail if the line of input read is not a - /// valid UTF-8 sequence of bytes. - fn read_line(&mut self) -> IoResult { unimplemented!() } - - /// Reads a sequence of bytes leading up to a specified delimiter. Once the - /// specified byte is encountered, reading ceases and the bytes up to and - /// including the delimiter are returned. - /// - /// # Error - /// - /// If any I/O error is encountered other than EOF, the error is immediately - /// returned. Note that this may discard bytes which have already been read, - /// and those bytes will *not* be returned. It is recommended to use other - /// methods if this case is worrying. - /// - /// If EOF is encountered, then this function will return EOF if 0 bytes - /// have been read, otherwise the pending byte buffer is returned. This - /// is the reason that the byte buffer returned may not always contain the - /// delimiter. - fn read_until(&mut self, byte: u8) -> IoResult> { unimplemented!() } - - /// Reads the next utf8-encoded character from the underlying stream. - /// - /// # Error - /// - /// If an I/O error occurs, or EOF, then this function will return `Err`. - /// This function will also return error if the stream does not contain a - /// valid utf-8 encoded codepoint as the next few bytes in the stream. - fn read_char(&mut self) -> IoResult { unimplemented!() } -} - -/// Extension methods for the Buffer trait which are included in the prelude. -pub trait BufferPrelude { - /// Create an iterator that reads a utf8-encoded character on each iteration - /// until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn chars<'r>(&'r mut self) -> Chars<'r, Self>; - - /// Create an iterator that reads a line on each iteration until EOF. - /// - /// # Error - /// - /// Any error other than `EndOfFile` that is produced by the underlying Reader - /// is returned by the iterator and should be handled by the caller. - fn lines<'r>(&'r mut self) -> Lines<'r, Self>; -} - -impl BufferPrelude for T { - fn chars<'r>(&'r mut self) -> Chars<'r, T> { unimplemented!() } - - fn lines<'r>(&'r mut self) -> Lines<'r, T> { unimplemented!() } -} - -/// When seeking, the resulting cursor is offset from a base by the offset given -/// to the `seek` function. The base used is specified by this enumeration. -pub enum SeekStyle { - /// Seek from the beginning of the stream - SeekSet, - /// Seek from the end of the stream - SeekEnd, - /// Seek from the current position - SeekCur, -} - -/// An object implementing `Seek` internally has some form of cursor which can -/// be moved within a stream of bytes. The stream typically has a fixed size, -/// allowing seeking relative to either end. -pub trait Seek { - /// Return position of file cursor in the stream - fn tell(&self) -> IoResult; - - /// Seek to an offset in a stream - /// - /// A successful seek clears the EOF indicator. Seeking beyond EOF is - /// allowed, but seeking before position 0 is not allowed. - /// - /// # Errors - /// - /// * Seeking to a negative offset is considered an error - /// * Seeking past the end of the stream does not modify the underlying - /// stream, but the next write may cause the previous data to be filled in - /// with a bit pattern. - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>; -} - -/// A listener is a value that can consume itself to start listening for -/// connections. -/// -/// Doing so produces some sort of Acceptor. -pub trait Listener> { - /// Spin up the listener and start queuing incoming connections - /// - /// # Error - /// - /// Returns `Err` if this listener could not be bound to listen for - /// connections. In all cases, this listener is consumed. - fn listen(self) -> IoResult; -} - -/// An acceptor is a value that presents incoming connections -pub trait Acceptor { - /// Wait for and accept an incoming connection - /// - /// # Error - /// - /// Returns `Err` if an I/O error is encountered. - fn accept(&mut self) -> IoResult; - - /// Create an iterator over incoming connection attempts. - /// - /// Note that I/O errors will be yielded by the iterator itself. - fn incoming<'r>(&'r mut self) -> IncomingConnections<'r, Self> { unimplemented!() } -} - -/// An infinite iterator over incoming connection attempts. -/// Calling `next` will block the task until a connection is attempted. -/// -/// Since connection attempts can continue forever, this iterator always returns -/// `Some`. The `Some` contains the `IoResult` representing whether the -/// connection attempt was successful. A successful connection will be wrapped -/// in `Ok`. A failed connection is represented as an `Err`. -pub struct IncomingConnections<'a, A:'a> { - inc: &'a mut A, -} - -impl<'a, T, A: Acceptor> Iterator> for IncomingConnections<'a, A> { - fn next(&mut self) -> Option> { unimplemented!() } -} - -/// Creates a standard error for a commonly used flavor of error. The `detail` -/// field of the returned error will always be `None`. -/// -/// # Example -/// -/// ``` -/// use std::io; -/// -/// let eof = io::standard_error(io::EndOfFile); -/// let einval = io::standard_error(io::InvalidInput); -/// ``` -pub fn standard_error(kind: IoErrorKind) -> IoError { unimplemented!() } - -/// A mode specifies how a file should be opened or created. These modes are -/// passed to `File::open_mode` and are used to control where the file is -/// positioned when it is initially opened. -pub enum FileMode { - /// Opens a file positioned at the beginning. - Open, - /// Opens a file positioned at EOF. - Append, - /// Opens a file, truncating it if it already exists. - Truncate, -} - -/// Access permissions with which the file should be opened. `File`s -/// opened with `Read` will return an error if written to. -pub enum FileAccess { - /// Read-only access, requests to write will result in an error - Read, - /// Write-only access, requests to read will result in an error - Write, - /// Read-write access, no requests are denied by default - ReadWrite, -} - -/// Different kinds of files which can be identified by a call to stat -#[deriving(PartialEq, Show, Hash, Clone)] -pub enum FileType { - /// This is a normal file, corresponding to `S_IFREG` - TypeFile, - - /// This file is a directory, corresponding to `S_IFDIR` - TypeDirectory, - - /// This file is a named pipe, corresponding to `S_IFIFO` - TypeNamedPipe, - - /// This file is a block device, corresponding to `S_IFBLK` - TypeBlockSpecial, - - /// This file is a symbolic link to another file, corresponding to `S_IFLNK` - TypeSymlink, - - /// The type of this file is not recognized as one of the other categories - TypeUnknown, -} - -/// A structure used to describe metadata information about a file. This -/// structure is created through the `stat` method on a `Path`. -/// -/// # Example -/// -/// ``` -/// # use std::io::fs::PathExtensions; -/// # fn main() {} -/// # fn foo() { -/// let info = match Path::new("foo.txt").stat() { -/// Ok(stat) => stat, -/// Err(e) => panic!("couldn't read foo.txt: {}", e), -/// }; -/// -/// println!("byte size: {}", info.size); -/// # } -/// ``` -#[deriving(Hash)] -pub struct FileStat { - /// The size of the file, in bytes - pub size: u64, - /// The kind of file this path points to (directory, file, pipe, etc.) - pub kind: FileType, - /// The file permissions currently on the file - pub perm: FilePermission, - - // FIXME(#10301): These time fields are pretty useless without an actual - // time representation, what are the milliseconds relative - // to? - - /// The time that the file was created at, in platform-dependent - /// milliseconds - pub created: u64, - /// The time that this file was last modified, in platform-dependent - /// milliseconds - pub modified: u64, - /// The time that this file was last accessed, in platform-dependent - /// milliseconds - pub accessed: u64, - - /// Information returned by stat() which is not guaranteed to be - /// platform-independent. This information may be useful on some platforms, - /// but it may have different meanings or no meaning at all on other - /// platforms. - /// - /// Usage of this field is discouraged, but if access is desired then the - /// fields are located here. - #[unstable] - pub unstable: UnstableFileStat, -} - -/// This structure represents all of the possible information which can be -/// returned from a `stat` syscall which is not contained in the `FileStat` -/// structure. This information is not necessarily platform independent, and may -/// have different meanings or no meaning at all on some platforms. -#[unstable] -#[deriving(Hash)] -pub struct UnstableFileStat { - /// The ID of the device containing the file. - pub device: u64, - /// The file serial number. - pub inode: u64, - /// The device ID. - pub rdev: u64, - /// The number of hard links to this file. - pub nlink: u64, - /// The user ID of the file. - pub uid: u64, - /// The group ID of the file. - pub gid: u64, - /// The optimal block size for I/O. - pub blksize: u64, - /// The blocks allocated for this file. - pub blocks: u64, - /// User-defined flags for the file. - pub flags: u64, - /// The file generation number. - pub gen: u64, -} - -bitflags! { - #[doc = "A set of permissions for a file or directory is represented"] - #[doc = "by a set of flags which are or'd together."] - flags FilePermission: u32 { - const USER_READ = 0o400, - const USER_WRITE = 0o200, - const USER_EXECUTE = 0o100, - const GROUP_READ = 0o040, - const GROUP_WRITE = 0o020, - const GROUP_EXECUTE = 0o010, - const OTHER_READ = 0o004, - const OTHER_WRITE = 0o002, - const OTHER_EXECUTE = 0o001, - - const USER_RWX = USER_READ.bits | USER_WRITE.bits | USER_EXECUTE.bits, - const GROUP_RWX = GROUP_READ.bits | GROUP_WRITE.bits | GROUP_EXECUTE.bits, - const OTHER_RWX = OTHER_READ.bits | OTHER_WRITE.bits | OTHER_EXECUTE.bits, - - #[doc = "Permissions for user owned files, equivalent to 0644 on"] - #[doc = "unix-like systems."] - const USER_FILE = USER_READ.bits | USER_WRITE.bits | GROUP_READ.bits | OTHER_READ.bits, - - #[doc = "Permissions for user owned directories, equivalent to 0755 on"] - #[doc = "unix-like systems."] - const USER_DIR = USER_RWX.bits | GROUP_READ.bits | GROUP_EXECUTE.bits | - OTHER_READ.bits | OTHER_EXECUTE.bits, - - #[doc = "Permissions for user owned executables, equivalent to 0755"] - #[doc = "on unix-like systems."] - const USER_EXEC = USER_DIR.bits, - - #[doc = "All possible permissions enabled."] - const ALL_PERMISSIONS = USER_RWX.bits | GROUP_RWX.bits | OTHER_RWX.bits, - - // Deprecated names - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_READ instead"] - const UserRead = USER_READ.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_WRITE instead"] - const UserWrite = USER_WRITE.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_EXECUTE instead"] - const UserExecute = USER_EXECUTE.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use GROUP_READ instead"] - const GroupRead = GROUP_READ.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use GROUP_WRITE instead"] - const GroupWrite = GROUP_WRITE.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use GROUP_EXECUTE instead"] - const GroupExecute = GROUP_EXECUTE.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use OTHER_READ instead"] - const OtherRead = OTHER_READ.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use OTHER_WRITE instead"] - const OtherWrite = OTHER_WRITE.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use OTHER_EXECUTE instead"] - const OtherExecute = OTHER_EXECUTE.bits, - - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_RWX instead"] - const UserRWX = USER_RWX.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use GROUP_RWX instead"] - const GroupRWX = GROUP_RWX.bits, - #[allow(non_upper_case_globals)] - #[deprecated = "use OTHER_RWX instead"] - const OtherRWX = OTHER_RWX.bits, - - #[doc = "Deprecated: use `USER_FILE` instead."] - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_FILE instead"] - const UserFile = USER_FILE.bits, - - #[doc = "Deprecated: use `USER_DIR` instead."] - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_DIR instead"] - const UserDir = USER_DIR.bits, - #[doc = "Deprecated: use `USER_EXEC` instead."] - #[allow(non_upper_case_globals)] - #[deprecated = "use USER_EXEC instead"] - const UserExec = USER_EXEC.bits, - - #[doc = "Deprecated: use `ALL_PERMISSIONS` instead"] - #[allow(non_upper_case_globals)] - #[deprecated = "use ALL_PERMISSIONS instead"] - const AllPermissions = ALL_PERMISSIONS.bits, - } -} - -impl Default for FilePermission { - #[inline] - fn default() -> FilePermission { unimplemented!() } -} - -impl fmt::Show for FilePermission { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} diff --git a/src/libst2/io/net/addrinfo.rs b/src/libst2/io/net/addrinfo.rs deleted file mode 100644 index ee7ede39e4a80..0000000000000 --- a/src/libst2/io/net/addrinfo.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 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. - -/*! - -Synchronous DNS Resolution - -Contains the functionality to perform DNS resolution in a style related to -getaddrinfo() - -*/ - -#![allow(missing_docs)] - -pub use self::SocketType::*; -pub use self::Flag::*; -pub use self::Protocol::*; - -use iter::Iterator; -use io::{IoResult}; -use io::net::ip::{SocketAddr, IpAddr}; -use option::{Option, Some, None}; -use sys; -use vec::Vec; - -/// Hints to the types of sockets that are desired when looking up hosts -pub enum SocketType { - Stream, Datagram, Raw -} - -/// Flags which can be or'd into the `flags` field of a `Hint`. These are used -/// to manipulate how a query is performed. -/// -/// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` -pub enum Flag { - AddrConfig, - All, - CanonName, - NumericHost, - NumericServ, - Passive, - V4Mapped, -} - -/// A transport protocol associated with either a hint or a return value of -/// `lookup` -pub enum Protocol { - TCP, UDP -} - -/// This structure is used to provide hints when fetching addresses for a -/// remote host to control how the lookup is performed. -/// -/// For details on these fields, see their corresponding definitions via -/// `man -s 3 getaddrinfo` -pub struct Hint { - pub family: uint, - pub socktype: Option, - pub protocol: Option, - pub flags: uint, -} - -pub struct Info { - pub address: SocketAddr, - pub family: uint, - pub socktype: Option, - pub protocol: Option, - pub flags: uint, -} - -/// Easy name resolution. Given a hostname, returns the list of IP addresses for -/// that hostname. -pub fn get_host_addresses(host: &str) -> IoResult> { unimplemented!() } - -/// Full-fledged resolution. This function will perform a synchronous call to -/// getaddrinfo, controlled by the parameters -/// -/// # Arguments -/// -/// * hostname - an optional hostname to lookup against -/// * servname - an optional service name, listed in the system services -/// * hint - see the hint structure, and "man -s 3 getaddrinfo", for how this -/// controls lookup -/// -/// FIXME: this is not public because the `Hint` structure is not ready for public -/// consumption just yet. -#[allow(unused_variables)] -fn lookup(hostname: Option<&str>, servname: Option<&str>, hint: Option) - -> IoResult> { unimplemented!() } diff --git a/src/libst2/io/net/ip.rs b/src/libst2/io/net/ip.rs deleted file mode 100644 index 478956b28fc1c..0000000000000 --- a/src/libst2/io/net/ip.rs +++ /dev/null @@ -1,231 +0,0 @@ -// Copyright 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. - -//! Internet Protocol (IP) addresses. -//! -//! This module contains functions useful for parsing, formatting, and -//! manipulating IP addresses. - -#![allow(missing_docs)] - -pub use self::IpAddr::*; - -use fmt; -use io::{mod, IoResult, IoError}; -use io::net; -use iter::Iterator; -use option::{Option, None, Some}; -use result::{Ok, Err}; -use str::{FromStr, StrPrelude}; -use slice::{CloneSlicePrelude, SlicePrelude}; -use vec::Vec; - -pub type Port = u16; - -#[deriving(PartialEq, Eq, Clone, Hash)] -pub enum IpAddr { - Ipv4Addr(u8, u8, u8, u8), - Ipv6Addr(u16, u16, u16, u16, u16, u16, u16, u16) -} - -impl fmt::Show for IpAddr { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -#[deriving(PartialEq, Eq, Clone, Hash)] -pub struct SocketAddr { - pub ip: IpAddr, - pub port: Port, -} - -impl fmt::Show for SocketAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -struct Parser<'a> { - // parsing as ASCII, so can use byte array - s: &'a [u8], - pos: uint, -} - -impl<'a> Parser<'a> { - fn new(s: &'a str) -> Parser<'a> { unimplemented!() } - - fn is_eof(&self) -> bool { unimplemented!() } - - // Commit only if parser returns Some - fn read_atomically(&mut self, cb: |&mut Parser| -> Option) - -> Option { unimplemented!() } - - // Commit only if parser read till EOF - fn read_till_eof(&mut self, cb: |&mut Parser| -> Option) - -> Option { unimplemented!() } - - // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [|&mut Parser| -> Option]) - -> Option { unimplemented!() } - - // Apply 3 parsers sequentially - fn read_seq_3( - &mut self, - pa: |&mut Parser| -> Option, - pb: |&mut Parser| -> Option, - pc: |&mut Parser| -> Option) - -> Option<(A, B, C)> { unimplemented!() } - - // Read next char - fn read_char(&mut self) -> Option { unimplemented!() } - - // Return char and advance iff next char is equal to requested - fn read_given_char(&mut self, c: char) -> Option { unimplemented!() } - - // Read digit - fn read_digit(&mut self, radix: u8) -> Option { unimplemented!() } - - fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { unimplemented!() } - - // Read number, failing if max_digits of number value exceeded - fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option { unimplemented!() } - - fn read_ipv4_addr_impl(&mut self) -> Option { unimplemented!() } - - // Read IPv4 address - fn read_ipv4_addr(&mut self) -> Option { unimplemented!() } - - fn read_ipv6_addr_impl(&mut self) -> Option { unimplemented!() } - - fn read_ipv6_addr(&mut self) -> Option { unimplemented!() } - - fn read_ip_addr(&mut self) -> Option { unimplemented!() } - - fn read_socket_addr(&mut self) -> Option { unimplemented!() } -} - -impl FromStr for IpAddr { - fn from_str(s: &str) -> Option { unimplemented!() } -} - -impl FromStr for SocketAddr { - fn from_str(s: &str) -> Option { unimplemented!() } -} - -/// A trait for objects which can be converted or resolved to one or more `SocketAddr` values. -/// -/// Implementing types minimally have to implement either `to_socket_addr` or `to_socket_addr_all` -/// method, and its trivial counterpart will be available automatically. -/// -/// This trait is used for generic address resolution when constructing network objects. -/// By default it is implemented for the following types: -/// -/// * `SocketAddr` - `to_socket_addr` is identity function. -/// -/// * `(IpAddr, u16)` - `to_socket_addr` constructs `SocketAddr` trivially. -/// -/// * `(&str, u16)` - the string should be either a string representation of an IP address -/// expected by `FromStr` implementation for `IpAddr` or a host name. -/// -/// For the former, `to_socket_addr_all` returns a vector with a single element corresponding -/// to that IP address joined with the given port. -/// -/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses -/// for the host name, each joined with the given port. -/// -/// * `&str` - the string should be either a string representation of a `SocketAddr` as -/// expected by its `FromStr` implementation or a string like `:` pair -/// where `` is a `u16` value. -/// -/// For the former, `to_socker_addr_all` returns a vector with a single element corresponding -/// to that socker address. -/// -/// For the latter, it tries to resolve the host name and returns a vector of all IP addresses -/// for the host name, each joined with the port. -/// -/// -/// This trait allows constructing network objects like `TcpStream` or `UdpSocket` easily with -/// values of various types for the bind/connection address. It is needed because sometimes -/// one type is more appropriate than the other: for simple uses a string like `"localhost:12345"` -/// is much nicer than manual construction of the corresponding `SocketAddr`, but sometimes -/// `SocketAddr` value is *the* main source of the address, and converting it to some other type -/// (e.g. a string) just for it to be converted back to `SocketAddr` in constructor methods -/// is pointless. -/// -/// Some examples: -/// -/// ```rust,no_run -/// # #![allow(unused_must_use)] -/// -/// use std::io::{TcpStream, TcpListener}; -/// use std::io::net::udp::UdpSocket; -/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; -/// -/// fn main() { -/// // The following lines are equivalent modulo possible "localhost" name resolution -/// // differences -/// let tcp_s = TcpStream::connect(SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 12345 }); -/// let tcp_s = TcpStream::connect((Ipv4Addr(127, 0, 0, 1), 12345u16)); -/// let tcp_s = TcpStream::connect(("127.0.0.1", 12345u16)); -/// let tcp_s = TcpStream::connect(("localhost", 12345u16)); -/// let tcp_s = TcpStream::connect("127.0.0.1:12345"); -/// let tcp_s = TcpStream::connect("localhost:12345"); -/// -/// // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to() behave similarly -/// let tcp_l = TcpListener::bind("localhost:12345"); -/// -/// let mut udp_s = UdpSocket::bind(("127.0.0.1", 23451u16)).unwrap(); -/// udp_s.send_to([7u8, 7u8, 7u8].as_slice(), (Ipv4Addr(127, 0, 0, 1), 23451u16)); -/// } -/// ``` -pub trait ToSocketAddr { - /// Converts this object to single socket address value. - /// - /// If more than one value is available, this method returns the first one. If no - /// values are available, this method returns an `IoError`. - /// - /// By default this method delegates to `to_socket_addr_all` method, taking the first - /// item from its result. - fn to_socket_addr(&self) -> IoResult { unimplemented!() } - - /// Converts this object to all available socket address values. - /// - /// Some values like host name string naturally corrrespond to multiple IP addresses. - /// This method tries to return all available addresses corresponding to this object. - /// - /// By default this method delegates to `to_socket_addr` method, creating a singleton - /// vector from its result. - #[inline] - fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } -} - -impl ToSocketAddr for SocketAddr { - #[inline] - fn to_socket_addr(&self) -> IoResult { unimplemented!() } -} - -impl ToSocketAddr for (IpAddr, u16) { - #[inline] - fn to_socket_addr(&self) -> IoResult { unimplemented!() } -} - -fn resolve_socket_addr(s: &str, p: u16) -> IoResult> { unimplemented!() } - -fn parse_and_resolve_socket_addr(s: &str) -> IoResult> { unimplemented!() } - -impl<'a> ToSocketAddr for (&'a str, u16) { - fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } -} - -// accepts strings like 'localhost:12345' -impl<'a> ToSocketAddr for &'a str { - fn to_socket_addr(&self) -> IoResult { unimplemented!() } - - fn to_socket_addr_all(&self) -> IoResult> { unimplemented!() } -} diff --git a/src/libst2/io/net/mod.rs b/src/libst2/io/net/mod.rs deleted file mode 100644 index 00d57cf317e68..0000000000000 --- a/src/libst2/io/net/mod.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 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. - -//! Networking I/O - -use io::{IoError, IoResult, InvalidInput}; -use option::None; -use result::{Ok, Err}; -use self::ip::{SocketAddr, ToSocketAddr}; - -pub use self::addrinfo::get_host_addresses; - -pub mod addrinfo; -pub mod tcp; -pub mod udp; -pub mod ip; -pub mod pipe; - -fn with_addresses(addr: A, action: |SocketAddr| -> IoResult) - -> IoResult { unimplemented!() } diff --git a/src/libst2/io/net/pipe.rs b/src/libst2/io/net/pipe.rs deleted file mode 100644 index e52462ed3fa5e..0000000000000 --- a/src/libst2/io/net/pipe.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 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. - -/*! - -Named pipes - -This module contains the ability to communicate over named pipes with -synchronous I/O. On windows, this corresponds to talking over a Named Pipe, -while on Unix it corresponds to UNIX domain sockets. - -These pipes are similar to TCP in the sense that you can have both a stream to a -server and a server itself. The server provided accepts other `UnixStream` -instances as clients. - -*/ - -#![allow(missing_docs)] - -use prelude::*; - -use io::{Listener, Acceptor, IoResult, TimedOut, standard_error}; -use time::Duration; - -use sys::pipe::UnixStream as UnixStreamImp; -use sys::pipe::UnixListener as UnixListenerImp; -use sys::pipe::UnixAcceptor as UnixAcceptorImp; - -/// A stream which communicates over a named pipe. -pub struct UnixStream { - inner: UnixStreamImp, -} - -impl UnixStream { - - /// Connect to a pipe named by `path`. This will attempt to open a - /// connection to the underlying socket. - /// - /// The returned stream will be closed when the object falls out of scope. - /// - /// # Example - /// - /// ```rust - /// # #![allow(unused_must_use)] - /// use std::io::net::pipe::UnixStream; - /// - /// let server = Path::new("path/to/my/socket"); - /// let mut stream = UnixStream::connect(&server); - /// stream.write(&[1, 2, 3]); - /// ``` - pub fn connect(path: &P) -> IoResult { unimplemented!() } - - /// Connect to a pipe named by `path`, timing out if the specified number of - /// milliseconds. - /// - /// This function is similar to `connect`, except that if `timeout` - /// elapses the function will return an error of kind `TimedOut`. - /// - /// If a `timeout` with zero or negative duration is specified then - /// the function returns `Err`, with the error kind set to `TimedOut`. - #[experimental = "the timeout argument is likely to change types"] - pub fn connect_timeout(path: &P, - timeout: Duration) -> IoResult { unimplemented!() } - - - /// Closes the reading half of this connection. - /// - /// This method will close the reading portion of this connection, causing - /// all pending and future reads to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } - - /// Closes the writing half of this connection. - /// - /// This method will close the writing portion of this connection, causing - /// all pending and future writes to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } - - /// Sets the read/write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the read timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { unimplemented!() } -} - -impl Reader for UnixStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for UnixStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -/// A value that can listen for incoming named pipe connection requests. -pub struct UnixListener { - /// The internal, opaque runtime Unix listener. - inner: UnixListenerImp, -} - -impl UnixListener { - /// Creates a new listener, ready to receive incoming connections on the - /// specified socket. The server will be named by `path`. - /// - /// This listener will be closed when it falls out of scope. - /// - /// # Example - /// - /// ``` - /// # fn main() {} - /// # fn foo() { - /// # #![allow(unused_must_use)] - /// use std::io::net::pipe::UnixListener; - /// use std::io::{Listener, Acceptor}; - /// - /// let server = Path::new("/path/to/my/socket"); - /// let stream = UnixListener::bind(&server); - /// for mut client in stream.listen().incoming() { - /// client.write(&[1, 2, 3, 4]); - /// } - /// # } - /// ``` - pub fn bind(path: &P) -> IoResult { unimplemented!() } -} - -impl Listener for UnixListener { - fn listen(self) -> IoResult { unimplemented!() } -} - -/// A value that can accept named pipe connections, returned from `listen()`. -pub struct UnixAcceptor { - /// The internal, opaque runtime Unix acceptor. - inner: UnixAcceptorImp -} - -impl UnixAcceptor { - /// Sets a timeout for this acceptor, after which accept() will no longer - /// block indefinitely. - /// - /// The argument specified is the amount of time, in milliseconds, into the - /// future after which all invocations of accept() will not block (and any - /// pending invocation will return). A value of `None` will clear any - /// existing timeout. - /// - /// When using this method, it is likely necessary to reset the timeout as - /// appropriate, the timeout specified is specific to this object, not - /// specific to the next request. - #[experimental = "the name and arguments to this function are likely \ - to change"] - pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Closes the accepting capabilities of this acceptor. - /// - /// This function has the same semantics as `TcpAcceptor::close_accept`, and - /// more information can be found in that documentation. - #[experimental] - pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Acceptor for UnixAcceptor { - fn accept(&mut self) -> IoResult { unimplemented!() } -} - -impl Clone for UnixAcceptor { - /// Creates a new handle to this unix acceptor, allowing for simultaneous - /// accepts. - /// - /// The underlying unix acceptor will not be closed until all handles to the - /// acceptor have been deallocated. Incoming connections will be received on - /// at most once acceptor, the same connection will not be accepted twice. - /// - /// The `close_accept` method will shut down *all* acceptors cloned from the - /// same original acceptor, whereas the `set_timeout` method only affects - /// the selector that it is called on. - /// - /// This function is useful for creating a handle to invoke `close_accept` - /// on to wake up any other task blocked in `accept`. - fn clone(&self) -> UnixAcceptor { unimplemented!() } -} diff --git a/src/libst2/io/net/tcp.rs b/src/libst2/io/net/tcp.rs deleted file mode 100644 index 00a3dc462bbd8..0000000000000 --- a/src/libst2/io/net/tcp.rs +++ /dev/null @@ -1,400 +0,0 @@ -// Copyright 2013-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. - -//! 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. - -use clone::Clone; -use io::IoResult; -use iter::Iterator; -use result::Err; -use io::net::ip::{SocketAddr, ToSocketAddr}; -use io::{Reader, Writer, Listener, Acceptor}; -use io::{standard_error, TimedOut}; -use option::{None, Some, Option}; -use time::Duration; - -use sys::tcp::TcpStream as TcpStreamImp; -use sys::tcp::TcpListener as TcpListenerImp; -use sys::tcp::TcpAcceptor as TcpAcceptorImp; - -/// A structure which represents a TCP stream between a local socket and a -/// remote socket. -/// -/// # Example -/// -/// ```no_run -/// # #![allow(unused_must_use)] -/// use std::io::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254"); -/// -/// stream.write(&[1]); -/// let mut buf = [0]; -/// stream.read(&mut buf); -/// drop(stream); // close the connection -/// ``` -pub struct TcpStream { - inner: TcpStreamImp, -} - -impl TcpStream { - fn new(s: TcpStreamImp) -> TcpStream { unimplemented!() } - - /// Open a TCP connection to a remote host. - /// - /// `addr` is an address of the remote host. Anything which implements `ToSocketAddr` - /// trait can be supplied for the address; see this trait documentation for - /// concrete examples. - pub fn connect(addr: A) -> IoResult { unimplemented!() } - - /// Creates a TCP connection to a remote socket address, timing out after - /// the specified duration. - /// - /// This is the same as the `connect` method, except that if the timeout - /// specified elapses before a connection is made an error will be - /// returned. The error's kind will be `TimedOut`. - /// - /// Same as the `connect` method, `addr` argument type can be anything which - /// implements `ToSocketAddr` trait. - /// - /// If a `timeout` with zero or negative duration is specified then - /// the function returns `Err`, with the error kind set to `TimedOut`. - #[experimental = "the timeout argument may eventually change types"] - pub fn connect_timeout(addr: A, - timeout: Duration) -> IoResult { unimplemented!() } - - /// Returns the socket address of the remote peer of this TCP connection. - pub fn peer_name(&mut self) -> IoResult { unimplemented!() } - - /// Returns the socket address of the local half of this TCP connection. - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } - - /// Sets the nodelay flag on this connection to the boolean specified - #[experimental] - pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { unimplemented!() } - - /// Sets the keepalive timeout to the timeout specified. - /// - /// If the value specified is `None`, then the keepalive flag is cleared on - /// this connection. Otherwise, the keepalive timeout will be set to the - /// specified time, in seconds. - #[experimental] - pub fn set_keepalive(&mut self, delay_in_seconds: Option) -> IoResult<()> { unimplemented!() } - - /// Closes the reading half of this connection. - /// - /// This method will close the reading portion of this connection, causing - /// all pending and future reads to immediately return with an error. - /// - /// # Example - /// - /// ```no_run - /// # #![allow(unused_must_use)] - /// use std::io::timer; - /// use std::io::TcpStream; - /// use std::time::Duration; - /// - /// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let stream2 = stream.clone(); - /// - /// spawn(proc() { - /// // close this stream after one second - /// timer::sleep(Duration::seconds(1)); - /// let mut stream = stream2; - /// stream.close_read(); - /// }); - /// - /// // wait for some data, will get canceled after one second - /// let mut buf = [0]; - /// stream.read(&mut buf); - /// ``` - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } - - /// Closes the writing half of this connection. - /// - /// This method will close the writing portion of this connection, causing - /// all future writes to immediately return with an error. - /// - /// Note that this method affects all cloned handles associated with this - /// stream, not just this one handle. - pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } - - /// Sets a timeout, in milliseconds, for blocking operations on this stream. - /// - /// This function will set a timeout for all blocking operations (including - /// reads and writes) on this stream. The timeout specified is a relative - /// time, in milliseconds, into the future after which point operations will - /// time out. This means that the timeout must be reset periodically to keep - /// it from expiring. Specifying a value of `None` will clear the timeout - /// for this stream. - /// - /// The timeout on this stream is local to this stream only. Setting a - /// timeout does not affect any other cloned instances of this stream, nor - /// does the timeout propagated to cloned handles of this stream. Setting - /// this timeout will override any specific read or write timeouts - /// previously set for this stream. - /// - /// For clarification on the semantics of interrupting a read and a write, - /// take a look at `set_read_timeout` and `set_write_timeout`. - #[experimental = "the timeout argument may change in type and value"] - pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the timeout for read operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this read time. - /// This will overwrite any previous read timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending read operation, no - /// action is taken. Otherwise, the read operation will be scheduled to - /// promptly return. If a timeout error is returned, then no data was read - /// during the timeout period. - #[experimental = "the timeout argument may change in type and value"] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the timeout for write operations on this stream. - /// - /// See documentation in `set_timeout` for the semantics of this write time. - /// This will overwrite any previous write timeout set through either this - /// function or `set_timeout`. - /// - /// # Errors - /// - /// When this timeout expires, if there is no pending write operation, no - /// action is taken. Otherwise, the pending write operation will be - /// scheduled to promptly return. The actual state of the underlying stream - /// is not specified. - /// - /// The write operation may return an error of type `ShortWrite` which - /// indicates that the object is known to have written an exact number of - /// bytes successfully during the timeout period, and the remaining bytes - /// were never written. - /// - /// If the write operation returns `TimedOut`, then it the timeout primitive - /// does not know how many bytes were written as part of the timeout - /// operation. It may be the case that bytes continue to be written in an - /// asynchronous fashion after the call to write returns. - #[experimental = "the timeout argument may change in type and value"] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } -} - -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 { unimplemented!() } -} - -impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} - -/// 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(dead_code)] -/// use std::io::{TcpListener, TcpStream}; -/// use std::io::{Acceptor, Listener}; -/// -/// let listener = TcpListener::bind("127.0.0.1:80"); -/// -/// // bind the listener to the specified address -/// let mut acceptor = listener.listen(); -/// -/// fn handle_client(mut stream: TcpStream) { -/// // ... -/// # &mut stream; // silence unused mutability/variable warning -/// } -/// // accept connections and process them, spawning a new tasks for each one -/// for stream in acceptor.incoming() { -/// match stream { -/// Err(e) => { /* connection failed */ } -/// Ok(stream) => spawn(proc() { -/// // connection succeeded -/// handle_client(stream) -/// }) -/// } -/// } -/// -/// // close the socket server -/// drop(acceptor); -/// # } -/// ``` -pub struct TcpListener { - inner: TcpListenerImp, -} - -impl TcpListener { - /// Creates a new `TcpListener` which will be bound to the specified 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. - /// - /// The address type can be any implementor of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn bind(addr: A) -> IoResult { unimplemented!() } - - /// Returns the local socket address of this listener. - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } -} - -impl Listener for TcpListener { - fn listen(self) -> IoResult { unimplemented!() } -} - -/// 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 { - inner: TcpAcceptorImp, -} - -impl TcpAcceptor { - /// Prevents blocking on all future accepts after `ms` milliseconds have - /// elapsed. - /// - /// This function is used to set a deadline after which this acceptor will - /// time out accepting any connections. The argument is the relative - /// distance, in milliseconds, to a point in the future after which all - /// accepts will fail. - /// - /// If the argument specified is `None`, then any previously registered - /// timeout is cleared. - /// - /// A timeout of `0` can be used to "poll" this acceptor to see if it has - /// any pending connections. All pending connections will be accepted, - /// regardless of whether the timeout has expired or not (the accept will - /// not block in this case). - /// - /// # Example - /// - /// ```no_run - /// # #![allow(experimental)] - /// use std::io::TcpListener; - /// use std::io::{Listener, Acceptor, TimedOut}; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// - /// // After 100ms have passed, all accepts will fail - /// a.set_timeout(Some(100)); - /// - /// match a.accept() { - /// Ok(..) => println!("accepted a socket"), - /// Err(ref e) if e.kind == TimedOut => { println!("timed out!"); } - /// Err(e) => println!("err: {}", e), - /// } - /// - /// // Reset the timeout and try again - /// a.set_timeout(Some(100)); - /// let socket = a.accept(); - /// - /// // Clear the timeout and block indefinitely waiting for a connection - /// a.set_timeout(None); - /// let socket = a.accept(); - /// ``` - #[experimental = "the type of the argument and name of this function are \ - subject to change"] - pub fn set_timeout(&mut self, ms: Option) { unimplemented!() } - - /// Closes the accepting capabilities of this acceptor. - /// - /// This function is similar to `TcpStream`'s `close_{read,write}` methods - /// in that it will affect *all* cloned handles of this acceptor's original - /// handle. - /// - /// Once this function succeeds, all future calls to `accept` will return - /// immediately with an error, preventing all future calls to accept. The - /// underlying socket will not be relinquished back to the OS until all - /// acceptors have been deallocated. - /// - /// This is useful for waking up a thread in an accept loop to indicate that - /// it should exit. - /// - /// # Example - /// - /// ``` - /// # #![allow(experimental)] - /// use std::io::{TcpListener, Listener, Acceptor, EndOfFile}; - /// - /// let mut a = TcpListener::bind("127.0.0.1:8482").listen().unwrap(); - /// let a2 = a.clone(); - /// - /// spawn(proc() { - /// let mut a2 = a2; - /// for socket in a2.incoming() { - /// match socket { - /// Ok(s) => { /* handle s */ } - /// Err(ref e) if e.kind == EndOfFile => break, // closed - /// Err(e) => panic!("unexpected error: {}", e), - /// } - /// } - /// }); - /// - /// # fn wait_for_sigint() {} - /// // Now that our accept loop is running, wait for the program to be - /// // requested to exit. - /// wait_for_sigint(); - /// - /// // Signal our accept loop to exit - /// assert!(a.close_accept().is_ok()); - /// ``` - #[experimental] - pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Acceptor for TcpAcceptor { - fn accept(&mut self) -> IoResult { unimplemented!() } -} - -impl Clone for TcpAcceptor { - /// Creates a new handle to this TCP acceptor, allowing for simultaneous - /// accepts. - /// - /// The underlying TCP acceptor will not be closed until all handles to the - /// acceptor have been deallocated. Incoming connections will be received on - /// at most once acceptor, the same connection will not be accepted twice. - /// - /// The `close_accept` method will shut down *all* acceptors cloned from the - /// same original acceptor, whereas the `set_timeout` method only affects - /// the selector that it is called on. - /// - /// This function is useful for creating a handle to invoke `close_accept` - /// on to wake up any other task blocked in `accept`. - fn clone(&self) -> TcpAcceptor { unimplemented!() } -} diff --git a/src/libst2/io/net/udp.rs b/src/libst2/io/net/udp.rs deleted file mode 100644 index 9a3c7544b60e0..0000000000000 --- a/src/libst2/io/net/udp.rs +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 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. - -//! UDP (User Datagram Protocol) network connections. -//! -//! This module contains the ability to open a UDP stream to a socket address. -//! The destination and binding addresses can either be an IPv4 or IPv6 -//! address. There is no corresponding notion of a server because UDP is a -//! datagram protocol. - -use clone::Clone; -use io::net::ip::{SocketAddr, IpAddr, ToSocketAddr}; -use io::{Reader, Writer, IoResult}; -use option::Option; -use result::{Ok, Err}; -use sys::udp::UdpSocket as UdpSocketImp; - -/// A User Datagram Protocol socket. -/// -/// This is an implementation of a bound UDP socket. This supports both IPv4 and -/// IPv6 addresses, and there is no corresponding notion of a server because UDP -/// is a datagram protocol. -/// -/// # Example -/// -/// ```rust,no_run -/// # #![allow(unused_must_use)] -/// #![feature(slicing_syntax)] -/// -/// use std::io::net::udp::UdpSocket; -/// use std::io::net::ip::{Ipv4Addr, SocketAddr}; -/// fn main() { -/// let addr = SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: 34254 }; -/// let mut socket = match UdpSocket::bind(addr) { -/// Ok(s) => s, -/// Err(e) => panic!("couldn't bind socket: {}", e), -/// }; -/// -/// let mut buf = [0, ..10]; -/// match socket.recv_from(&mut buf) { -/// Ok((amt, src)) => { -/// // Send a reply to the socket we received data from -/// let buf = buf[mut ..amt]; -/// buf.reverse(); -/// socket.send_to(buf, src); -/// } -/// Err(e) => println!("couldn't receive a datagram: {}", e) -/// } -/// drop(socket); // close the socket -/// } -/// ``` -pub struct UdpSocket { - inner: UdpSocketImp, -} - -impl UdpSocket { - /// Creates a UDP socket from the given address. - /// - /// Address type can be any implementor of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn bind(addr: A) -> IoResult { unimplemented!() } - - /// Receives data from the socket. On success, returns the number of bytes - /// read and the address from whence the data came. - pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { unimplemented!() } - - /// Sends data on the socket to the given address. Returns nothing on - /// success. - /// - /// Address type can be any implementor of `ToSocketAddr` trait. See its - /// documentation for concrete examples. - pub fn send_to(&mut self, buf: &[u8], addr: A) -> IoResult<()> { unimplemented!() } - - /// Creates a `UdpStream`, which allows use of the `Reader` and `Writer` - /// traits to receive and send data from the same address. This transfers - /// ownership of the socket to the stream. - /// - /// Note that this call does not perform any actual network communication, - /// because UDP is a datagram protocol. - #[deprecated = "`UdpStream` has been deprecated"] - #[allow(deprecated)] - pub fn connect(self, other: SocketAddr) -> UdpStream { unimplemented!() } - - /// Returns the socket address that this socket was created from. - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } - - /// Joins a multicast IP address (becomes a member of it) - #[experimental] - pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } - - /// Leaves a multicast IP address (drops membership from it) - #[experimental] - pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } - - /// Set the multicast loop flag to the specified value - /// - /// This lets multicast packets loop back to local sockets (if enabled) - #[experimental] - pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { unimplemented!() } - - /// Sets the multicast TTL - #[experimental] - pub fn set_multicast_ttl(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } - - /// Sets this socket's TTL - #[experimental] - pub fn set_ttl(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } - - /// Sets the broadcast flag on or off - #[experimental] - pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> { unimplemented!() } - - /// Sets the read/write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the read timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_read_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Sets the write timeout for this socket. - /// - /// For more information, see `TcpStream::set_timeout` - #[experimental = "the timeout argument may change in type and value"] - pub fn set_write_timeout(&mut self, timeout_ms: Option) { unimplemented!() } -} - -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 { unimplemented!() } -} - -/// A type that allows convenient usage of a UDP stream connected to one -/// address via the `Reader` and `Writer` traits. -/// -/// # Note -/// -/// This structure has been deprecated because `Reader` is a stream-oriented API but UDP -/// is a packet-oriented protocol. Every `Reader` method will read a whole packet and -/// throw all superfluous bytes away so that they are no longer available for further -/// method calls. -#[deprecated] -pub struct UdpStream { - socket: UdpSocket, - connected_to: SocketAddr -} - -impl UdpStream { - /// Allows access to the underlying UDP socket owned by this stream. This - /// is useful to, for example, use the socket to send data to hosts other - /// than the one that this stream is connected to. - pub fn as_socket(&mut self, f: |&mut UdpSocket| -> T) -> T { unimplemented!() } - - /// Consumes this UDP stream and returns out the underlying socket. - pub fn disconnect(self) -> UdpSocket { unimplemented!() } -} - -impl Reader for UdpStream { - /// Returns the next non-empty message from the specified address. - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for UdpStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/io/pipe.rs b/src/libst2/io/pipe.rs deleted file mode 100644 index 2103382e52bf4..0000000000000 --- a/src/libst2/io/pipe.rs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 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. - -//! Synchronous, in-memory pipes. -//! -//! Currently these aren't particularly useful, there only exists bindings -//! enough so that pipes can be created to child processes. - -#![allow(missing_docs)] - -use prelude::*; - -use io::IoResult; -use libc; -use sync::Arc; - -use sys_common; -use sys; -use sys::fs::FileDesc as FileDesc; - -/// A synchronous, in-memory pipe. -pub struct PipeStream { - inner: Arc -} - -pub struct PipePair { - pub reader: PipeStream, - pub writer: PipeStream, -} - -impl PipeStream { - /// Consumes a file descriptor to return a pipe stream that will have - /// synchronous, but non-blocking reads/writes. This is useful if the file - /// descriptor is acquired via means other than the standard methods. - /// - /// This operation consumes ownership of the file descriptor and it will be - /// closed once the object is deallocated. - /// - /// # Example - /// - /// ```{rust,no_run} - /// # #![allow(unused_must_use)] - /// extern crate libc; - /// - /// use std::io::pipe::PipeStream; - /// - /// fn main() { - /// let mut pipe = PipeStream::open(libc::STDERR_FILENO); - /// pipe.write(b"Hello, stderr!"); - /// } - /// ``` - pub fn open(fd: libc::c_int) -> IoResult { unimplemented!() } - - // FIXME: expose this some other way - /// Wrap a FileDesc directly, taking ownership. - #[doc(hidden)] - pub fn from_filedesc(fd: FileDesc) -> PipeStream { unimplemented!() } - - /// Creates a pair of in-memory OS pipes for a unidirectional communication - /// stream. - /// - /// The structure returned contains a reader and writer I/O object. Data - /// written to the writer can be read from the reader. - /// - /// # Errors - /// - /// This function can fail to succeed if the underlying OS has run out of - /// available resources to allocate a new pipe. - pub fn pair() -> IoResult { unimplemented!() } -} - -impl sys_common::AsFileDesc for PipeStream { - fn as_fd(&self) -> &sys::fs::FileDesc { unimplemented!() } -} - -impl Clone for PipeStream { - fn clone(&self) -> PipeStream { unimplemented!() } -} - -impl Reader for PipeStream { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Writer for PipeStream { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/io/process.rs b/src/libst2/io/process.rs deleted file mode 100644 index 8ba11b60a05a5..0000000000000 --- a/src/libst2/io/process.rs +++ /dev/null @@ -1,470 +0,0 @@ -// Copyright 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. - -//! Bindings for executing child processes - -#![allow(experimental)] -#![allow(non_upper_case_globals)] - -pub use self::StdioContainer::*; -pub use self::ProcessExit::*; - -use prelude::*; - -use fmt; -use os; -use io::{IoResult, IoError}; -use io; -use libc; -use c_str::CString; -use collections::HashMap; -use hash::Hash; -#[cfg(windows)] -use std::hash::sip::SipState; -use io::pipe::{PipeStream, PipePair}; -use path::BytesContainer; - -use sys; -use sys::fs::FileDesc; -use sys::process::Process as ProcessImp; - -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(windows)] pub const PleaseExitSignal: int = 15; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(windows)] pub const MustDieSignal: int = 9; -/// Signal a process to exit, without forcibly killing it. Corresponds to -/// SIGTERM on unix platforms. -#[cfg(not(windows))] pub const PleaseExitSignal: int = libc::SIGTERM as int; -/// Signal a process to exit immediately, forcibly killing it. Corresponds to -/// SIGKILL on unix platforms. -#[cfg(not(windows))] pub const MustDieSignal: int = libc::SIGKILL as int; - -/// Representation of a running or exited child process. -/// -/// This structure is used to represent and manage child processes. A child -/// process is created via the `Command` struct, which configures the spawning -/// process and can itself be constructed using a builder-style interface. -/// -/// # Example -/// -/// ```should_fail -/// use std::io::Command; -/// -/// let mut child = match Command::new("/bin/cat").arg("file.txt").spawn() { -/// Ok(child) => child, -/// Err(e) => panic!("failed to execute child: {}", e), -/// }; -/// -/// let contents = child.stdout.as_mut().unwrap().read_to_end(); -/// assert!(child.wait().unwrap().success()); -/// ``` -pub struct Process { - handle: ProcessImp, - forget: bool, - - /// None until wait() is called. - exit_code: Option, - - /// Manually delivered signal - exit_signal: Option, - - /// Deadline after which wait() will return - deadline: u64, - - /// Handle to the child's stdin, if the `stdin` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdin: Option, - - /// Handle to the child's stdout, if the `stdout` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stdout: Option, - - /// Handle to the child's stderr, if the `stderr` field of this process's - /// `ProcessConfig` was `CreatePipe`. By default, this handle is `Some`. - pub stderr: Option, -} - -/// A representation of environment variable name -/// It compares case-insensitive on Windows and case-sensitive everywhere else. -#[cfg(not(windows))] -#[deriving(PartialEq, Eq, Hash, Clone, Show)] -struct EnvKey(CString); - -#[doc(hidden)] -#[cfg(windows)] -#[deriving(Eq, Clone, Show)] -struct EnvKey(CString); - -#[cfg(windows)] -impl Hash for EnvKey { - fn hash(&self, state: &mut SipState) { unimplemented!() } -} - -#[cfg(windows)] -impl PartialEq for EnvKey { - fn eq(&self, other: &EnvKey) -> bool { unimplemented!() } -} - -impl BytesContainer for EnvKey { - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } -} - -/// A HashMap representation of environment variables. -pub type EnvMap = HashMap; - -/// The `Command` type acts as a process builder, providing fine-grained control -/// over how a new process should be spawned. A default configuration can be -/// generated using `Command::new(program)`, where `program` gives a path to the -/// program to be executed. Additional builder methods allow the configuration -/// to be changed (for example, by adding arguments) prior to spawning: -/// -/// ``` -/// use std::io::Command; -/// -/// let mut process = match Command::new("sh").arg("-c").arg("echo hello").spawn() { -/// Ok(p) => p, -/// Err(e) => panic!("failed to execute process: {}", e), -/// }; -/// -/// let output = process.stdout.as_mut().unwrap().read_to_end(); -/// ``` -#[deriving(Clone)] -pub struct Command { - // The internal data for the builder. Documented by the builder - // methods below, and serialized into rt::rtio::ProcessConfig. - program: CString, - args: Vec, - env: Option, - cwd: Option, - stdin: StdioContainer, - stdout: StdioContainer, - stderr: StdioContainer, - uid: Option, - gid: Option, - detach: bool, -} - -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. (Here: {new, arg, args, env}.) - -impl Command { - /// Constructs a new `Command` for launching the program at - /// path `program`, with the following default configuration: - /// - /// * No arguments to the program - /// * Inherit the current process's environment - /// * Inherit the current process's working directory - /// * A readable pipe for stdin (file descriptor 0) - /// * A writeable pipe for stdout and stderr (file descriptors 1 and 2) - /// - /// Builder methods are provided to change these defaults and - /// otherwise configure the process. - pub fn new(program: T) -> Command { unimplemented!() } - - /// Add an argument to pass to the program. - pub fn arg<'a, T: ToCStr>(&'a mut self, arg: T) -> &'a mut Command { unimplemented!() } - - /// Add multiple arguments to pass to the program. - pub fn args<'a, T: ToCStr>(&'a mut self, args: &[T]) -> &'a mut Command { unimplemented!() } - // Get a mutable borrow of the environment variable map for this `Command`. - fn get_env_map<'a>(&'a mut self) -> &'a mut EnvMap { unimplemented!() } - - /// Inserts or updates an environment variable mapping. - /// - /// Note that environment variable names are case-insensitive (but case-preserving) on Windows, - /// and case-sensitive on all other platforms. - pub fn env<'a, T: ToCStr, U: ToCStr>(&'a mut self, key: T, val: U) - -> &'a mut Command { unimplemented!() } - - /// Removes an environment variable mapping. - pub fn env_remove<'a, T: ToCStr>(&'a mut self, key: T) -> &'a mut Command { unimplemented!() } - - /// Sets the entire environment map for the child process. - /// - /// If the given slice contains multiple instances of an environment - /// variable, the *rightmost* instance will determine the value. - pub fn env_set_all<'a, T: ToCStr, U: ToCStr>(&'a mut self, env: &[(T,U)]) - -> &'a mut Command { unimplemented!() } - - /// Set the working directory for the child process. - pub fn cwd<'a>(&'a mut self, dir: &Path) -> &'a mut Command { unimplemented!() } - - /// Configuration for the child process's stdin handle (file descriptor 0). - /// Defaults to `CreatePipe(true, false)` so the input can be written to. - pub fn stdin<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } - - /// Configuration for the child process's stdout handle (file descriptor 1). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stdout<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } - - /// Configuration for the child process's stderr handle (file descriptor 2). - /// Defaults to `CreatePipe(false, true)` so the output can be collected. - pub fn stderr<'a>(&'a mut self, cfg: StdioContainer) -> &'a mut Command { unimplemented!() } - - /// Sets the child process's user id. This translates to a `setuid` call in - /// the child process. Setting this value on windows will cause the spawn to - /// fail. Failure in the `setuid` call on unix will also cause the spawn to - /// fail. - pub fn uid<'a>(&'a mut self, id: uint) -> &'a mut Command { unimplemented!() } - - /// Similar to `uid`, but sets the group id of the child process. This has - /// the same semantics as the `uid` field. - pub fn gid<'a>(&'a mut self, id: uint) -> &'a mut Command { unimplemented!() } - - /// Sets the child process to be spawned in a detached state. On unix, this - /// means that the child is the leader of a new process group. - pub fn detached<'a>(&'a mut self) -> &'a mut Command { unimplemented!() } - - /// Executes the command as a child process, which is returned. - pub fn spawn(&self) -> IoResult { unimplemented!() } - - /// Executes the command as a child process, waiting for it to finish and - /// collecting all of its output. - /// - /// # Example - /// - /// ``` - /// use std::io::Command; - /// - /// let output = match Command::new("cat").arg("foot.txt").output() { - /// Ok(output) => output, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("status: {}", output.status); - /// println!("stdout: {}", String::from_utf8_lossy(output.output.as_slice())); - /// println!("stderr: {}", String::from_utf8_lossy(output.error.as_slice())); - /// ``` - pub fn output(&self) -> IoResult { unimplemented!() } - - /// Executes a command as a child process, waiting for it to finish and - /// collecting its exit status. - /// - /// # Example - /// - /// ``` - /// use std::io::Command; - /// - /// let status = match Command::new("ls").status() { - /// Ok(status) => status, - /// Err(e) => panic!("failed to execute process: {}", e), - /// }; - /// - /// println!("process exited with: {}", status); - /// ``` - pub fn status(&self) -> IoResult { unimplemented!() } -} - -impl fmt::Show for Command { - /// Format the program and arguments of a Command for display. Any - /// non-utf8 data is lossily converted using the utf8 replacement - /// character. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -fn setup_io(io: StdioContainer) -> IoResult<(Option, Option)> { unimplemented!() } - -// Allow the sys module to get access to the Command state -impl sys::process::ProcessConfig for Command { - fn program(&self) -> &CString { unimplemented!() } - fn args(&self) -> &[CString] { unimplemented!() } - fn env(&self) -> Option<&EnvMap> { unimplemented!() } - fn cwd(&self) -> Option<&CString> { unimplemented!() } - fn uid(&self) -> Option { unimplemented!() } - fn gid(&self) -> Option { unimplemented!() } - fn detach(&self) -> bool { unimplemented!() } - -} - -/// The output of a finished process. -#[deriving(PartialEq, Eq, Clone)] -pub struct ProcessOutput { - /// The status (exit code) of the process. - pub status: ProcessExit, - /// The data that the process wrote to stdout. - pub output: Vec, - /// The data that the process wrote to stderr. - pub error: Vec, -} - -/// Describes what to do with a standard io stream for a child process. -#[deriving(Clone)] -pub enum StdioContainer { - /// This stream will be ignored. This is the equivalent of attaching the - /// stream to `/dev/null` - Ignored, - - /// The specified file descriptor is inherited for the stream which it is - /// specified for. Ownership of the file descriptor is *not* taken, so the - /// caller must clean it up. - InheritFd(libc::c_int), - - /// Creates a pipe for the specified file descriptor which will be created - /// when the process is spawned. - /// - /// The first boolean argument is whether the pipe is readable, and the - /// second is whether it is writable. These properties are from the view of - /// the *child* process, not the parent process. - CreatePipe(bool /* readable */, bool /* writable */), -} - -/// Describes the result of a process after it has terminated. -/// Note that Windows have no signals, so the result is usually ExitStatus. -#[deriving(PartialEq, Eq, Clone)] -pub enum ProcessExit { - /// Normal termination with an exit status. - ExitStatus(int), - - /// Termination by signal, with the signal number. - ExitSignal(int), -} - -impl fmt::Show for ProcessExit { - /// Format a ProcessExit enum, to nicely present the information. - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl ProcessExit { - /// Was termination successful? Signal termination not considered a success, - /// and success is defined as a zero exit status. - pub fn success(&self) -> bool { unimplemented!() } - - /// Checks whether this ProcessExit matches the given exit status. - /// Termination by signal will never match an exit code. - pub fn matches_exit_status(&self, wanted: int) -> bool { unimplemented!() } -} - -impl Process { - /// Sends `signal` to another process in the system identified by `id`. - /// - /// Note that windows doesn't quite have the same model as unix, so some - /// unix signals are mapped to windows signals. Notably, unix termination - /// signals (SIGTERM/SIGKILL/SIGINT) are translated to `TerminateProcess`. - /// - /// Additionally, a signal number of 0 can check for existence of the target - /// process. Note, though, that on some platforms signals will continue to - /// be successfully delivered if the child has exited, but not yet been - /// reaped. - pub fn kill(id: libc::pid_t, signal: int) -> IoResult<()> { unimplemented!() } - - /// Returns the process id of this child process - pub fn id(&self) -> libc::pid_t { unimplemented!() } - - /// Sends the specified signal to the child process, returning whether the - /// signal could be delivered or not. - /// - /// Note that signal 0 is interpreted as a poll to check whether the child - /// process is still alive or not. If an error is returned, then the child - /// process has exited. - /// - /// On some unix platforms signals will continue to be received after a - /// child has exited but not yet been reaped. In order to report the status - /// of signal delivery correctly, unix implementations may invoke - /// `waitpid()` with `WNOHANG` in order to reap the child as necessary. - /// - /// # Errors - /// - /// If the signal delivery fails, the corresponding error is returned. - pub fn signal(&mut self, signal: int) -> IoResult<()> { unimplemented!() } - - /// Sends a signal to this child requesting that it exits. This is - /// equivalent to sending a SIGTERM on unix platforms. - pub fn signal_exit(&mut self) -> IoResult<()> { unimplemented!() } - - /// Sends a signal to this child forcing it to exit. This is equivalent to - /// sending a SIGKILL on unix platforms. - pub fn signal_kill(&mut self) -> IoResult<()> { unimplemented!() } - - /// Wait for the child to exit completely, returning the status that it - /// exited with. This function will continue to have the same return value - /// after it has been called at least once. - /// - /// The stdin handle to the child process will be closed before waiting. - /// - /// # Errors - /// - /// This function can fail if a timeout was previously specified via - /// `set_timeout` and the timeout expires before the child exits. - pub fn wait(&mut self) -> IoResult { unimplemented!() } - - /// Sets a timeout, in milliseconds, for future calls to wait(). - /// - /// The argument specified is a relative distance into the future, in - /// milliseconds, after which any call to wait() will return immediately - /// with a timeout error, and all future calls to wait() will not block. - /// - /// A value of `None` will clear any previous timeout, and a value of `Some` - /// will override any previously set timeout. - /// - /// # Example - /// - /// ```no_run - /// # #![allow(experimental)] - /// use std::io::{Command, IoResult}; - /// use std::io::process::ProcessExit; - /// - /// fn run_gracefully(prog: &str) -> IoResult { - /// let mut p = try!(Command::new("long-running-process").spawn()); - /// - /// // give the process 10 seconds to finish completely - /// p.set_timeout(Some(10_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Attempt to exit gracefully, but don't wait for it too long - /// try!(p.signal_exit()); - /// p.set_timeout(Some(1_000)); - /// match p.wait() { - /// Ok(status) => return Ok(status), - /// Err(..) => {} - /// } - /// - /// // Well, we did our best, forcefully kill the process - /// try!(p.signal_kill()); - /// p.set_timeout(None); - /// p.wait() - /// } - /// ``` - #[experimental = "the type of the timeout is likely to change"] - pub fn set_timeout(&mut self, timeout_ms: Option) { unimplemented!() } - - /// Simultaneously wait for the child to exit and collect all remaining - /// output on the stdout/stderr handles, returning a `ProcessOutput` - /// instance. - /// - /// The stdin handle to the child is closed before waiting. - /// - /// # Errors - /// - /// This function can fail for any of the same reasons that `wait()` can - /// fail. - pub fn wait_with_output(mut self) -> IoResult { unimplemented!() } - - /// Forgets this process, allowing it to outlive the parent - /// - /// This function will forcefully prevent calling `wait()` on the child - /// process in the destructor, allowing the child to outlive the - /// parent. Note that this operation can easily lead to leaking the - /// resources of the child process, so care must be taken when - /// invoking this method. - pub fn forget(mut self) { unimplemented!() } -} - -impl Drop for Process { - fn drop(&mut self) { unimplemented!() } -} diff --git a/src/libst2/io/result.rs b/src/libst2/io/result.rs deleted file mode 100644 index f89cc7c258923..0000000000000 --- a/src/libst2/io/result.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 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. - -//! Implementations of I/O traits for the IoResult type -//! -//! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `IoResult` to be used -//! as a `Reader` without unwrapping the result first. - -use clone::Clone; -use result::{Ok, Err}; -use super::{Reader, Writer, Listener, Acceptor, Seek, SeekStyle, IoResult}; - -impl Writer for IoResult { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - fn flush(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Reader for IoResult { - fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } -} - -impl Seek for IoResult { - fn tell(&self) -> IoResult { unimplemented!() } - fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()> { unimplemented!() } -} - -impl, L: Listener> Listener for IoResult { - fn listen(self) -> IoResult { unimplemented!() } -} - -impl> Acceptor for IoResult { - fn accept(&mut self) -> IoResult { unimplemented!() } -} diff --git a/src/libst2/io/stdio.rs b/src/libst2/io/stdio.rs deleted file mode 100644 index 8b646fe584e8d..0000000000000 --- a/src/libst2/io/stdio.rs +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright 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. - -/*! Non-blocking access to stdin, stdout, and stderr. - -This module provides bindings to the local event loop's TTY interface, using it -to offer synchronous but non-blocking versions of stdio. These handles can be -inspected for information about terminal dimensions or for related information -about the stream or terminal to which it is attached. - -# Example - -```rust -# #![allow(unused_must_use)] -use std::io; - -let mut out = io::stdout(); -out.write(b"Hello, world!"); -``` - -*/ - -use self::StdSource::*; - -use boxed::Box; -use cell::RefCell; -use failure::LOCAL_STDERR; -use fmt; -use io::{Reader, Writer, IoResult, IoError, OtherIoError, - standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use iter::Iterator; -use kinds::Send; -use libc; -use mem; -use option::{Option, Some, None}; -use result::{Ok, Err}; -use rustrt; -use rustrt::local::Local; -use rustrt::task::Task; -use slice::SlicePrelude; -use str::StrPrelude; -use sys::{fs, tty}; -use uint; - -// And so begins the tale of acquiring a uv handle to a stdio stream on all -// platforms in all situations. Our story begins by splitting the world into two -// categories, windows and unix. Then one day the creators of unix said let -// there be redirection! And henceforth there was redirection away from the -// console for standard I/O streams. -// -// After this day, the world split into four factions: -// -// 1. Unix with stdout on a terminal. -// 2. Unix with stdout redirected. -// 3. Windows with stdout on a terminal. -// 4. Windows with stdout redirected. -// -// Many years passed, and then one day the nation of libuv decided to unify this -// world. After months of toiling, uv created three ideas: TTY, Pipe, File. -// These three ideas propagated throughout the lands and the four great factions -// decided to settle among them. -// -// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon -// doing so, they even enhanced themselves further then their Pipe/File -// brethren, becoming the dominant powers. -// -// The group of 4, however, decided to work independently. They abandoned the -// common TTY belief throughout, and even abandoned the fledgling Pipe belief. -// The members of the 4th faction decided to only align themselves with File. -// -// tl;dr; TTY works on everything but when windows stdout is redirected, in that -// case pipe also doesn't work, but magically file does! -enum StdSource { - TTY(tty::TTY), - File(fs::FileDesc), -} - -fn src(fd: libc::c_int, _readable: bool, f: |StdSource| -> T) -> T { - match tty::TTY::new(fd) { - Ok(tty) => f(TTY(tty)), - Err(_) => f(File(fs::FileDesc::new(fd, false))), - } -} - -thread_local!(static LOCAL_STDOUT: RefCell>> = { - RefCell::new(None) -}) - -/// Creates a new non-blocking handle to the stdin of the current process. -/// -/// The returned handled is buffered by default with a `BufferedReader`. If -/// buffered access is not desired, the `stdin_raw` function is provided to -/// provided unbuffered access to stdin. -/// -/// Care should be taken when creating multiple handles to the stdin of a -/// process. Because this is a buffered reader by default, it's possible for -/// pending input to be unconsumed in one reader and unavailable to other -/// readers. It is recommended that only one handle at a time is created for the -/// stdin of a process. -/// -/// See `stdout()` for more notes about this function. -pub fn stdin() -> BufferedReader { - // The default buffer capacity is 64k, but apparently windows doesn't like - // 64k reads on stdin. See #13304 for details, but the idea is that on - // windows we use a slightly smaller buffer that's been seen to be - // acceptable. - if cfg!(windows) { - BufferedReader::with_capacity(8 * 1024, stdin_raw()) - } else { - BufferedReader::new(stdin_raw()) - } -} - -/// Creates a new non-blocking handle to the stdin of the current process. -/// -/// Unlike `stdin()`, the returned reader is *not* a buffered reader. -/// -/// See `stdout()` for more notes about this function. -pub fn stdin_raw() -> StdReader { - src(libc::STDIN_FILENO, true, |src| StdReader { inner: src }) -} - -/// Creates a line-buffered handle to the stdout of the current process. -/// -/// Note that this is a fairly expensive operation in that at least one memory -/// allocation is performed. Additionally, this must be called from a runtime -/// task context because the stream returned will be a non-blocking object using -/// the local scheduler to perform the I/O. -/// -/// Care should be taken when creating multiple handles to an output stream for -/// a single process. While usage is still safe, the output may be surprising if -/// no synchronization is performed to ensure a sane output. -pub fn stdout() -> LineBufferedWriter { - LineBufferedWriter::new(stdout_raw()) -} - -/// Creates an unbuffered handle to the stdout of the current process -/// -/// See notes in `stdout()` for more information. -pub fn stdout_raw() -> StdWriter { - src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src }) -} - -/// Creates a line-buffered handle to the stderr of the current process. -/// -/// See `stdout()` for notes about this function. -pub fn stderr() -> LineBufferedWriter { - LineBufferedWriter::new(stderr_raw()) -} - -/// Creates an unbuffered handle to the stderr of the current process -/// -/// See notes in `stdout()` for more information. -pub fn stderr_raw() -> StdWriter { - src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src }) -} - -/// Resets the task-local stdout handle to the specified writer -/// -/// This will replace the current task's stdout handle, returning the old -/// handle. All future calls to `print` and friends will emit their output to -/// this specified handle. -/// -/// Note that this does not need to be called for all new tasks; the default -/// output handle is to the process's stdout stream. -pub fn set_stdout(stdout: Box) -> Option> { - let mut new = Some(stdout); - LOCAL_STDOUT.with(|slot| { - mem::replace(&mut *slot.borrow_mut(), new.take()) - }).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) -} - -/// Resets the task-local stderr handle to the specified writer -/// -/// This will replace the current task's stderr handle, returning the old -/// handle. Currently, the stderr handle is used for printing panic messages -/// during task panic. -/// -/// Note that this does not need to be called for all new tasks; the default -/// output handle is to the process's stderr stream. -pub fn set_stderr(stderr: Box) -> Option> { - let mut new = Some(stderr); - LOCAL_STDERR.with(|slot| { - mem::replace(&mut *slot.borrow_mut(), new.take()) - }).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) -} - -// Helper to access the local task's stdout handle -// -// Note that this is not a safe function to expose because you can create an -// aliased pointer very easily: -// -// with_task_stdout(|io1| { -// with_task_stdout(|io2| { -// // io1 aliases io2 -// }) -// }) -fn with_task_stdout(f: |&mut Writer| -> IoResult<()>) { - let result = if Local::exists(None::) { - let mut my_stdout = LOCAL_STDOUT.with(|slot| { - slot.borrow_mut().take() - }).unwrap_or_else(|| { - box stdout() as Box - }); - let result = f(&mut *my_stdout); - let mut var = Some(my_stdout); - LOCAL_STDOUT.with(|slot| { - *slot.borrow_mut() = var.take(); - }); - result - } else { - let mut io = rustrt::Stdout; - f(&mut io as &mut Writer) - }; - match result { - Ok(()) => {} - Err(e) => panic!("failed printing to stdout: {}", e), - } -} - -/// Flushes the local task's stdout handle. -/// -/// By default, this stream is a line-buffering stream, so flushing may be -/// necessary to ensure that all output is printed to the screen (if there are -/// no newlines printed). -/// -/// Note that logging macros do not use this stream. Using the logging macros -/// will emit output to stderr, and while they are line buffered the log -/// messages are always terminated in a newline (no need to flush). -pub fn flush() { - with_task_stdout(|io| io.flush()) -} - -/// Prints a string to the stdout of the current process. No newline is emitted -/// after the string is printed. -pub fn print(s: &str) { - with_task_stdout(|io| io.write(s.as_bytes())) -} - -/// Prints a string to the stdout of the current process. A literal -/// `\n` character is printed to the console after the string. -pub fn println(s: &str) { - with_task_stdout(|io| { - io.write(s.as_bytes()).and_then(|()| io.write(&[b'\n'])) - }) -} - -/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible -/// with the `format_args!` macro. -pub fn print_args(fmt: &fmt::Arguments) { - with_task_stdout(|io| write!(io, "{}", fmt)) -} - -/// Similar to `println`, but takes a `fmt::Arguments` structure to be -/// compatible with the `format_args!` macro. -pub fn println_args(fmt: &fmt::Arguments) { - with_task_stdout(|io| writeln!(io, "{}", fmt)) -} - -/// Representation of a reader of a standard input stream -pub struct StdReader { - inner: StdSource -} - -impl StdReader { - /// Returns whether this stream is attached to a TTY instance or not. - pub fn isatty(&self) -> bool { - match self.inner { - TTY(..) => true, - File(..) => false, - } - } -} - -impl Reader for StdReader { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = match self.inner { - TTY(ref mut tty) => { - // Flush the task-local stdout so that weird issues like a - // print!'d prompt not being shown until after the user hits - // enter. - flush(); - tty.read(buf).map(|i| i as uint) - }, - File(ref mut file) => file.read(buf).map(|i| i as uint), - }; - match ret { - // When reading a piped stdin, libuv will return 0-length reads when - // stdin reaches EOF. For pretty much all other streams it will - // return an actual EOF error, but apparently for stdin it's a - // little different. Hence, here we convert a 0 length read to an - // end-of-file indicator so the caller knows to stop reading. - Ok(0) => { Err(standard_error(EndOfFile)) } - ret @ Ok(..) | ret @ Err(..) => ret, - } - } -} - -/// Representation of a writer to a standard output stream -pub struct StdWriter { - inner: StdSource -} - -impl StdWriter { - /// Gets the size of this output window, if possible. This is typically used - /// when the writer is attached to something like a terminal, this is used - /// to fetch the dimensions of the terminal. - /// - /// If successful, returns `Ok((width, height))`. - /// - /// # Error - /// - /// This function will return an error if the output stream is not actually - /// connected to a TTY instance, or if querying the TTY instance fails. - pub fn winsize(&mut self) -> IoResult<(int, int)> { - match self.inner { - TTY(ref mut tty) => { - tty.get_winsize() - } - File(..) => { - Err(IoError { - kind: OtherIoError, - desc: "stream is not a tty", - detail: None, - }) - } - } - } - - /// Controls whether this output stream is a "raw stream" or simply a normal - /// stream. - /// - /// # Error - /// - /// This function will return an error if the output stream is not actually - /// connected to a TTY instance, or if querying the TTY instance fails. - pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { - match self.inner { - TTY(ref mut tty) => { - tty.set_raw(raw) - } - File(..) => { - Err(IoError { - kind: OtherIoError, - desc: "stream is not a tty", - detail: None, - }) - } - } - } - - /// Returns whether this stream is attached to a TTY instance or not. - pub fn isatty(&self) -> bool { - match self.inner { - TTY(..) => true, - File(..) => false, - } - } -} - -impl Writer for StdWriter { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - // As with stdin on windows, stdout often can't handle writes of large - // sizes. For an example, see #14940. For this reason, chunk the output - // buffer on windows, but on unix we can just write the whole buffer all - // at once. - // - // For some other references, it appears that this problem has been - // encountered by others [1] [2]. We choose the number 8KB just because - // libuv does the same. - // - // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232 - // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html - let max_size = if cfg!(windows) {8192} else {uint::MAX}; - for chunk in buf.chunks(max_size) { - try!(match self.inner { - TTY(ref mut tty) => tty.write(chunk), - File(ref mut file) => file.write(chunk), - }) - } - Ok(()) - } -} diff --git a/src/libst2/io/tempfile.rs b/src/libst2/io/tempfile.rs deleted file mode 100644 index 7fed90aa5cc92..0000000000000 --- a/src/libst2/io/tempfile.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 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. - -//! Temporary files and directories - -use io::{fs, IoResult}; -use io; -use libc; -use ops::Drop; -use option::{Option, None, Some}; -use os; -use path::{Path, GenericPath}; -use result::{Ok, Err}; -use sync::atomic; - -/// A wrapper for a path to temporary directory implementing automatic -/// scope-based deletion. -pub struct TempDir { - path: Option, - disarmed: bool -} - -impl TempDir { - /// Attempts to make a temporary directory inside of `tmpdir` whose name - /// will have the suffix `suffix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - pub fn new_in(tmpdir: &Path, suffix: &str) -> IoResult { unimplemented!() } - - /// Attempts to make a temporary directory inside of `os::tmpdir()` whose - /// name will have the suffix `suffix`. The directory will be automatically - /// deleted once the returned wrapper is destroyed. - /// - /// If no directory can be created, `Err` is returned. - pub fn new(suffix: &str) -> IoResult { unimplemented!() } - - /// Unwrap the wrapped `std::path::Path` from the `TempDir` wrapper. - /// This discards the wrapper so that the automatic deletion of the - /// temporary directory is prevented. - pub fn unwrap(self) -> Path { unimplemented!() } - - /// Access the wrapped `std::path::Path` to the temporary directory. - pub fn path<'a>(&'a self) -> &'a Path { unimplemented!() } - - /// Close and remove the temporary directory - /// - /// Although `TempDir` removes the directory on drop, in the destructor - /// any errors are ignored. To detect errors cleaning up the temporary - /// directory, call `close` instead. - pub fn close(mut self) -> IoResult<()> { unimplemented!() } - - fn cleanup_dir(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Drop for TempDir { - fn drop(&mut self) { unimplemented!() } -} - -// the tests for this module need to change the path using change_dir, -// and this doesn't play nicely with other tests so these unit tests are located -// in src/test/run-pass/tempfile.rs diff --git a/src/libst2/io/test.rs b/src/libst2/io/test.rs deleted file mode 100644 index 53ff2e8dc965a..0000000000000 --- a/src/libst2/io/test.rs +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 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. - -/*! Various utility functions useful for writing I/O tests */ - -#![macro_escape] - -use libc; -use os; -use prelude::*; -use std::io::net::ip::*; -use sync::atomic::{AtomicUint, INIT_ATOMIC_UINT, Relaxed}; - -/// Get a port number, starting at 9600, for use in tests -pub fn next_test_port() -> u16 { unimplemented!() } - -/// Get a temporary path which could be the location of a unix socket -pub fn next_test_unix() -> Path { unimplemented!() } - -/// Get a unique IPv4 localhost:port pair starting at 9600 -pub fn next_test_ip4() -> SocketAddr { unimplemented!() } - -/// Get a unique IPv6 localhost:port pair starting at 9600 -pub fn next_test_ip6() -> SocketAddr { unimplemented!() } - -/* -XXX: Welcome to MegaHack City. - -The bots run multiple builds at the same time, and these builds -all want to use ports. This function figures out which workspace -it is running in and assigns a port range based on it. -*/ -fn base_port() -> u16 { unimplemented!() } - -/// Raises the file descriptor limit when running tests if necessary -pub fn raise_fd_limit() { unimplemented!() } - -#[cfg(target_os="macos")] -#[allow(non_camel_case_types)] -mod darwin_fd_limit { - /*! - * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the - * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low - * for our multithreaded scheduler testing, depending on the number of cores available. - * - * This fixes issue #7772. - */ - - use libc; - type rlim_t = libc::uint64_t; - #[repr(C)] - struct rlimit { - rlim_cur: rlim_t, - rlim_max: rlim_t - } - extern { - // name probably doesn't need to be mut, but the C function doesn't specify const - fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint, - oldp: *mut libc::c_void, oldlenp: *mut libc::size_t, - newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int; - fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int; - fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int; - } - static CTL_KERN: libc::c_int = 1; - static KERN_MAXFILESPERPROC: libc::c_int = 29; - static RLIMIT_NOFILE: libc::c_int = 8; - - pub unsafe fn raise_fd_limit() { unimplemented!() } -} - -#[cfg(not(target_os="macos"))] -mod darwin_fd_limit { - pub unsafe fn raise_fd_limit() { unimplemented!() } -} diff --git a/src/libst2/io/timer.rs b/src/libst2/io/timer.rs deleted file mode 100644 index f705dae118dc5..0000000000000 --- a/src/libst2/io/timer.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 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. - -/*! - -Synchronous Timers - -This module exposes the functionality to create timers, block the current task, -and create receivers which will receive notifications after a period of time. - -*/ - -// FIXME: These functions take Durations but only pass ms to the backend impls. - -use comm::{Receiver, Sender, channel}; -use time::Duration; -use io::IoResult; -use sys::timer::Callback; -use sys::timer::Timer as TimerImp; - -/// A synchronous timer object -/// -/// Values of this type can be used to put the current task to sleep for a -/// period of time. Handles to this timer can also be created in the form of -/// receivers which will receive notifications over time. -/// -/// # Example -/// -/// ``` -/// # fn main() {} -/// # fn foo() { -/// use std::io::Timer; -/// use std::time::Duration; -/// -/// let mut timer = Timer::new().unwrap(); -/// timer.sleep(Duration::milliseconds(10)); // block the task for awhile -/// -/// let timeout = timer.oneshot(Duration::milliseconds(10)); -/// // do some work -/// timeout.recv(); // wait for the timeout to expire -/// -/// let periodic = timer.periodic(Duration::milliseconds(10)); -/// loop { -/// periodic.recv(); -/// // this loop is only executed once every 10ms -/// } -/// # } -/// ``` -/// -/// If only sleeping is necessary, then a convenience API is provided through -/// the `io::timer` module. -/// -/// ``` -/// # fn main() {} -/// # fn foo() { -/// use std::io::timer; -/// use std::time::Duration; -/// -/// // Put this task to sleep for 5 seconds -/// timer::sleep(Duration::seconds(5)); -/// # } -/// ``` -pub struct Timer { - inner: TimerImp, -} - -struct TimerCallback { tx: Sender<()> } - -/// Sleep the current task for the specified duration. -/// -/// When provided a zero or negative `duration`, the function will -/// return immediately. -pub fn sleep(duration: Duration) { unimplemented!() } - -impl Timer { - /// Creates a new timer which can be used to put the current task to sleep - /// for a number of milliseconds, or to possibly create channels which will - /// get notified after an amount of time has passed. - pub fn new() -> IoResult { unimplemented!() } - - /// Blocks the current task for the specified duration. - /// - /// Note that this function will cause any other receivers for this timer to - /// be invalidated (the other end will be closed). - /// - /// When provided a zero or negative `duration`, the function will - /// return immediately. - pub fn sleep(&mut self, duration: Duration) { unimplemented!() } - - /// Creates a oneshot receiver which will have a notification sent when - /// the specified duration has elapsed. - /// - /// This does *not* block the current task, but instead returns immediately. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Example - /// - /// ```rust - /// use std::io::Timer; - /// use std::time::Duration; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.oneshot(Duration::milliseconds(10)); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 10 ms after the `oneshot` call - /// ten_milliseconds.recv(); - /// ``` - /// - /// ```rust - /// use std::io::Timer; - /// use std::time::Duration; - /// - /// // Incorrect, method chaining-style: - /// let mut five_ms = Timer::new().unwrap().oneshot(Duration::milliseconds(5)); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv() - /// ``` - /// - /// When provided a zero or negative `duration`, the message will - /// be sent immediately. - pub fn oneshot(&mut self, duration: Duration) -> Receiver<()> { unimplemented!() } - - /// Creates a receiver which will have a continuous stream of notifications - /// being sent each time the specified duration has elapsed. - /// - /// This does *not* block the current task, but instead returns - /// immediately. The first notification will not be received immediately, - /// but rather after the first duration. - /// - /// Note that this invalidates any previous receiver which has been created - /// by this timer, and that the returned receiver will be invalidated once - /// the timer is destroyed (when it falls out of scope). In particular, if - /// this is called in method-chaining style, the receiver will be - /// invalidated at the end of that statement, and all `recv` calls will - /// fail. - /// - /// # Example - /// - /// ```rust - /// use std::io::Timer; - /// use std::time::Duration; - /// - /// let mut timer = Timer::new().unwrap(); - /// let ten_milliseconds = timer.periodic(Duration::milliseconds(10)); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 10 ms after the `periodic` call - /// ten_milliseconds.recv(); - /// - /// for _ in range(0u, 100) { /* do work */ } - /// - /// // blocks until 20 ms after the `periodic` call (*not* 10ms after the - /// // previous `recv`) - /// ten_milliseconds.recv(); - /// ``` - /// - /// ```rust - /// use std::io::Timer; - /// use std::time::Duration; - /// - /// // Incorrect, method chaining-style. - /// let mut five_ms = Timer::new().unwrap().periodic(Duration::milliseconds(5)); - /// // The timer object was destroyed, so this will always fail: - /// // five_ms.recv() - /// ``` - /// - /// When provided a zero or negative `duration`, the messages will - /// be sent without delay. - pub fn periodic(&mut self, duration: Duration) -> Receiver<()> { unimplemented!() } -} - -impl Callback for TimerCallback { - fn call(&mut self) { unimplemented!() } -} - -fn in_ms_u64(d: Duration) -> u64 { unimplemented!() } diff --git a/src/libst2/io/util.rs b/src/libst2/io/util.rs deleted file mode 100644 index 4e1ffc8f8c85f..0000000000000 --- a/src/libst2/io/util.rs +++ /dev/null @@ -1,161 +0,0 @@ -// Copyright 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. - -/*! Utility implementations of Reader and Writer */ - -use prelude::*; -use cmp; -use io; -use slice::bytes::MutableByteVector; - -/// Wraps a `Reader`, limiting the number of bytes that can be read from it. -pub struct LimitReader { - limit: uint, - inner: R -} - -impl LimitReader { - /// Creates a new `LimitReader` - pub fn new(r: R, limit: uint) -> LimitReader { unimplemented!() } - - /// Consumes the `LimitReader`, returning the underlying `Reader`. - pub fn unwrap(self) -> R { unimplemented!() } - - /// Returns the number of bytes that can be read before the `LimitReader` - /// will return EOF. - /// - /// # Note - /// - /// The reader may reach EOF after reading fewer bytes than indicated by - /// this method if the underlying reader reaches EOF. - pub fn limit(&self) -> uint { unimplemented!() } -} - -impl Reader for LimitReader { - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} - -impl Buffer for LimitReader { - fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } - - fn consume(&mut self, amt: uint) { unimplemented!() } - -} - -/// A `Writer` which ignores bytes written to it, like /dev/null. -pub struct NullWriter; - -impl Writer for NullWriter { - #[inline] - fn write(&mut self, _buf: &[u8]) -> io::IoResult<()> { unimplemented!() } -} - -/// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. -pub struct ZeroReader; - -impl Reader for ZeroReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} - -impl Buffer for ZeroReader { - fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } - - fn consume(&mut self, _amt: uint) { unimplemented!() } -} - -/// A `Reader` which is always at EOF, like /dev/null. -pub struct NullReader; - -impl Reader for NullReader { - #[inline] - fn read(&mut self, _buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} - -impl Buffer for NullReader { - fn fill_buf<'a>(&'a mut self) -> io::IoResult<&'a [u8]> { unimplemented!() } - fn consume(&mut self, _amt: uint) { unimplemented!() } -} - -/// A `Writer` which multiplexes writes to a set of `Writer`s. -/// -/// The `Writer`s are delegated to in order. If any `Writer` returns an error, -/// that error is returned immediately and remaining `Writer`s are not called. -pub struct MultiWriter { - writers: Vec> -} - -impl MultiWriter { - /// Creates a new `MultiWriter` - pub fn new(writers: Vec>) -> MultiWriter { unimplemented!() } -} - -impl Writer for MultiWriter { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { unimplemented!() } - - #[inline] - fn flush(&mut self) -> io::IoResult<()> { unimplemented!() } -} - -/// A `Reader` which chains input from multiple `Reader`s, reading each to -/// completion before moving onto the next. -pub struct ChainedReader { - readers: I, - cur_reader: Option, -} - -impl> ChainedReader { - /// Creates a new `ChainedReader` - pub fn new(mut readers: I) -> ChainedReader { unimplemented!() } -} - -impl> Reader for ChainedReader { - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} - -/// A `Reader` which forwards input from another `Reader`, passing it along to -/// a `Writer` as well. Similar to the `tee(1)` command. -pub struct TeeReader { - reader: R, - writer: W, -} - -impl TeeReader { - /// Creates a new `TeeReader` - pub fn new(r: R, w: W) -> TeeReader { unimplemented!() } - - /// Consumes the `TeeReader`, returning the underlying `Reader` and - /// `Writer`. - pub fn unwrap(self) -> (R, W) { unimplemented!() } -} - -impl Reader for TeeReader { - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} - -/// Copies all data from a `Reader` to a `Writer`. -pub fn copy(r: &mut R, w: &mut W) -> io::IoResult<()> { unimplemented!() } - -/// An adaptor converting an `Iterator` to a `Reader`. -pub struct IterReader { - iter: T, -} - -impl> IterReader { - /// Creates a new `IterReader` which will read from the specified - /// `Iterator`. - pub fn new(iter: T) -> IterReader { unimplemented!() } -} - -impl> Reader for IterReader { - #[inline] - fn read(&mut self, buf: &mut [u8]) -> io::IoResult { unimplemented!() } -} diff --git a/src/libst2/lib.rs b/src/libst2/lib.rs deleted file mode 100644 index 77da727e94d31..0000000000000 --- a/src/libst2/lib.rs +++ /dev/null @@ -1,280 +0,0 @@ -// 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. - -//! # The Rust Standard Library -//! -//! The Rust Standard Library provides the essential runtime -//! functionality for building portable Rust software. -//! It is linked to all Rust crates by default. -//! -//! ## Intrinsic types and operations -//! -//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html) -//! modules deal with unsafe pointers and memory manipulation. -//! [`kinds`](kinds/index.html) defines the special built-in traits, -//! and [`raw`](raw/index.html) the runtime representation of Rust types. -//! These are some of the lowest-level building blocks in Rust. -//! -//! ## Math on primitive types and math traits -//! -//! Although basic operations on primitive types are implemented -//! directly by the compiler, the standard library additionally -//! defines many common operations through traits defined in -//! mod [`num`](num/index.html). -//! -//! ## Pervasive types -//! -//! The [`option`](option/index.html) and [`result`](result/index.html) -//! modules define optional and error-handling types, `Option` and `Result`. -//! [`iter`](iter/index.html) defines Rust's iterator protocol -//! along with a wide variety of iterators. -//! [`Cell` and `RefCell`](cell/index.html) are for creating types that -//! manage their own mutability. -//! -//! ## Vectors, slices and strings -//! -//! The common container type, `Vec`, a growable vector backed by an -//! array, lives in the [`vec`](vec/index.html) module. References to -//! arrays, `&[T]`, more commonly called "slices", are built-in types -//! for which the [`slice`](slice/index.html) module defines many -//! methods. -//! -//! `&str`, a UTF-8 string, is a built-in type, and the standard library -//! defines methods for it on a variety of traits in the -//! [`str`](str/index.html) module. Rust strings are immutable; -//! use the `String` type defined in [`string`](string/index.html) -//! for a mutable string builder. -//! -//! For converting to strings use the [`format!`](fmt/index.html) -//! macro, and for converting from strings use the -//! [`FromStr`](str/trait.FromStr.html) trait. -//! -//! ## Platform abstractions -//! -//! Besides basic data types, the standard library is largely concerned -//! with abstracting over differences in common platforms, most notably -//! Windows and Unix derivatives. The [`os`](os/index.html) module -//! provides a number of basic functions for interacting with the -//! operating environment, including program arguments, environment -//! variables, and directory navigation. The [`path`](path/index.html) -//! module encapsulates the platform-specific rules for dealing -//! with file paths. -//! -//! `std` also includes modules for interoperating with the -//! C language: [`c_str`](c_str/index.html) and -//! [`c_vec`](c_vec/index.html). -//! -//! ## Concurrency, I/O, and the runtime -//! -//! The [`task`](task/index.html) module contains Rust's threading abstractions, -//! while [`comm`](comm/index.html) contains the channel types for message -//! passing. [`sync`](sync/index.html) contains further, primitive, shared -//! memory types, including [`atomic`](sync/atomic/index.html). -//! -//! Common types of I/O, including files, TCP, UDP, pipes, Unix domain sockets, -//! timers, and process spawning, are defined in the [`io`](io/index.html) module. -//! -//! Rust's I/O and concurrency depends on a small runtime interface -//! that lives, along with its support code, in mod [`rt`](rt/index.html). -//! While a notable part of the standard library's architecture, this -//! module is not intended for public use. -//! -//! ## The Rust prelude and macros -//! -//! Finally, the [`prelude`](prelude/index.html) defines a -//! common set of traits, types, and functions that are made available -//! to all code by default. [`macros`](macros/index.html) contains -//! all the standard macros, such as `assert!`, `panic!`, `println!`, -//! and `format!`, also available to all Rust code. - -#![crate_name = "std"] -#![unstable] -#![comment = "The Rust standard library"] -#![license = "MIT/ASL2"] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "http://www.rust-lang.org/favicon.ico", - html_root_url = "http://doc.rust-lang.org/nightly/", - html_playground_url = "http://play.rust-lang.org/")] - -#![allow(unknown_features)] -#![feature(macro_rules, globs, linkage)] -#![feature(default_type_params, phase, lang_items, unsafe_destructor)] -#![feature(import_shadowing, slicing_syntax)] - -// Don't link to std. We are std. -#![no_std] - -#![deny(missing_docs)] - -#![reexport_test_harness_main = "test_main"] - -#[cfg(test)] #[phase(plugin, link)] extern crate log; - -extern crate alloc; -extern crate unicode; -extern crate core; -extern crate "collections" as core_collections; -extern crate "rand" as core_rand; -extern crate "sync" as core_sync; -extern crate libc; -extern crate rustrt; - -// Make std testable by not duplicating lang items. See #2912 -#[cfg(test)] extern crate "std" as realstd; -#[cfg(test)] pub use realstd::kinds; -#[cfg(test)] pub use realstd::ops; -#[cfg(test)] pub use realstd::cmp; -#[cfg(test)] pub use realstd::boxed; - - -// NB: These reexports are in the order they should be listed in rustdoc - -pub use core::any; -pub use core::bool; -pub use core::borrow; -pub use core::cell; -pub use core::clone; -#[cfg(not(test))] pub use core::cmp; -pub use core::default; -pub use core::finally; -pub use core::intrinsics; -pub use core::iter; -#[cfg(not(test))] pub use core::kinds; -pub use core::mem; -#[cfg(not(test))] pub use core::ops; -pub use core::ptr; -pub use core::raw; -pub use core::simd; -pub use core::tuple; -// FIXME #15320: primitive documentation needs top-level modules, this -// should be `std::tuple::unit`. -pub use core::unit; -pub use core::result; -pub use core::option; - -pub use alloc::boxed; -pub use alloc::rc; - -pub use core_collections::slice; -pub use core_collections::str; -pub use core_collections::string; -pub use core_collections::vec; - -pub use rustrt::c_str; - -pub use unicode::char; - -pub use core_sync::comm; - -/* Exported macros */ - -pub mod macros; -pub mod bitflags; - -mod rtdeps; - -/* The Prelude. */ - -pub mod prelude; - - -/* Primitive types */ - -#[path = "num/float_macros.rs"] mod float_macros; -#[path = "num/int_macros.rs"] mod int_macros; -#[path = "num/uint_macros.rs"] mod uint_macros; - -#[path = "num/int.rs"] pub mod int; -#[path = "num/i8.rs"] pub mod i8; -#[path = "num/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] pub mod i64; - -#[path = "num/uint.rs"] pub mod uint; -#[path = "num/u8.rs"] pub mod u8; -#[path = "num/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] pub mod u64; - -#[path = "num/f32.rs"] pub mod f32; -#[path = "num/f64.rs"] pub mod f64; - -pub mod ascii; - -/* Common traits */ - -pub mod error; -pub mod num; - -/* Runtime and platform support */ - -pub mod thread_local; -pub mod c_vec; -pub mod dynamic_lib; -pub mod fmt; -pub mod io; -pub mod os; -pub mod path; -pub mod rand; -pub mod time; - -/* Common data structures */ - -pub mod collections; -pub mod hash; - -/* Tasks and communication */ - -pub mod task; -pub mod sync; - -#[cfg(unix)] -#[path = "sys/unix/mod.rs"] mod sys; -#[cfg(windows)] -#[path = "sys/windows/mod.rs"] mod sys; - -#[path = "sys/common/mod.rs"] mod sys_common; - -pub mod rt; -mod failure; - -// A curious inner-module that's not exported that contains the binding -// 'std' so that macro-expanded references to std::error and such -// can be resolved within libstd. -#[doc(hidden)] -mod std { - // mods used for deriving - pub use clone; - pub use cmp; - pub use hash; - - pub use comm; // used for select!() - pub use error; // used for try!() - pub use fmt; // used for any formatting strings - pub use io; // used for println!() - pub use option; // used for bitflags!{} - pub use rt; // used for panic!() - pub use vec; // used for vec![] - pub use cell; // used for tls! - pub use thread_local; // used for thread_local! - pub use kinds; // used for tls! - - // The test runner calls ::std::os::args() but really wants realstd - #[cfg(test)] pub use realstd::os as os; - // The test runner requires std::slice::Vector, so re-export std::slice just for it. - // - // It is also used in vec![] - pub use slice; - - pub use boxed; // used for vec![] - -} diff --git a/src/libst2/macros.rs b/src/libst2/macros.rs deleted file mode 100644 index 08115a313119d..0000000000000 --- a/src/libst2/macros.rs +++ /dev/null @@ -1,626 +0,0 @@ -// 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. - -//! Standard library macros -//! -//! This modules contains a set of macros which are exported from the standard -//! library. Each macro is available for use when linking against the standard -//! library. - -#![experimental] -#![macro_escape] - -/// The entry point for panic of Rust tasks. -/// -/// This macro is used to inject panic into a Rust task, causing the task to -/// unwind and panic entirely. Each task's panic can be reaped as the -/// `Box` type, and the single-argument form of the `panic!` macro will be -/// the value which is transmitted. -/// -/// The multi-argument form of this macro panics with a string and has the -/// `format!` syntax for building a string. -/// -/// # Example -/// -/// ```should_fail -/// # #![allow(unreachable_code)] -/// panic!(); -/// panic!("this is a terrible mistake!"); -/// panic!(4i); // panic with the value of 4 to be collected elsewhere -/// panic!("this is a {} {message}", "fancy", message = "message"); -/// ``` -#[macro_export] -macro_rules! panic( - () => ({ - panic!("explicit panic") - }); - ($msg:expr) => ({ - loop { } - }); - ($fmt:expr, $($arg:tt)*) => ({ - loop { } - }); -) - -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the `panic!` macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// # Example -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// assert!(true); -/// # fn some_computation() -> bool { true } -/// assert!(some_computation()); -/// -/// // assert with a custom message -/// # let x = true; -/// assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; -/// assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -macro_rules! assert( - ($cond:expr) => ( - if !$cond { - panic!(concat!("assertion failed: ", stringify!($cond))) - } - ); - ($cond:expr, $($arg:expr),+) => ( - if !$cond { - panic!($($arg),+) - } - ); -) - -/// Asserts that two expressions are equal to each other, testing equality in -/// both directions. -/// -/// On panic, this macro will print the values of the expressions. -/// -/// # Example -/// -/// ``` -/// let a = 3i; -/// let b = 1i + 2i; -/// assert_eq!(a, b); -/// ``` -#[macro_export] -macro_rules! assert_eq( - ($given:expr , $expected:expr) => ({ - match (&($given), &($expected)) { - (given_val, expected_val) => { - // check both directions of equality.... - if !((*given_val == *expected_val) && - (*expected_val == *given_val)) { - panic!("assertion failed: `(left == right) && (right == left)` \ - (left: `{}`, right: `{}`)", *given_val, *expected_val) - } - } - } - }) -) - -/// Ensure that a boolean expression is `true` at runtime. -/// -/// This will invoke the `panic!` macro if the provided expression cannot be -/// evaluated to `true` at runtime. -/// -/// Unlike `assert!`, `debug_assert!` statements can be disabled by passing -/// `--cfg ndebug` to the compiler. This makes `debug_assert!` useful for -/// checks that are too expensive to be present in a release build but may be -/// helpful during development. -/// -/// # Example -/// -/// ``` -/// // the panic message for these assertions is the stringified value of the -/// // expression given. -/// debug_assert!(true); -/// # fn some_expensive_computation() -> bool { true } -/// debug_assert!(some_expensive_computation()); -/// -/// // assert with a custom message -/// # let x = true; -/// debug_assert!(x, "x wasn't true!"); -/// # let a = 3i; let b = 27i; -/// debug_assert!(a + b == 30, "a = {}, b = {}", a, b); -/// ``` -#[macro_export] -macro_rules! debug_assert( - ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert!($($arg)*); }) -) - -/// Asserts that two expressions are equal to each other, testing equality in -/// both directions. -/// -/// On panic, this macro will print the values of the expressions. -/// -/// Unlike `assert_eq!`, `debug_assert_eq!` statements can be disabled by -/// passing `--cfg ndebug` to the compiler. This makes `debug_assert_eq!` -/// useful for checks that are too expensive to be present in a release build -/// but may be helpful during development. -/// -/// # Example -/// -/// ``` -/// let a = 3i; -/// let b = 1i + 2i; -/// debug_assert_eq!(a, b); -/// ``` -#[macro_export] -macro_rules! debug_assert_eq( - ($($arg:tt)*) => (if cfg!(not(ndebug)) { assert_eq!($($arg)*); }) -) - -/// A utility macro for indicating unreachable code. It will panic if -/// executed. This is occasionally useful to put after loops that never -/// terminate normally, but instead directly return from a function. -/// -/// # Example -/// -/// ```{.rust} -/// struct Item { weight: uint } -/// -/// fn choose_weighted_item(v: &[Item]) -> Item { -/// assert!(!v.is_empty()); -/// let mut so_far = 0u; -/// for item in v.iter() { -/// so_far += item.weight; -/// if so_far > 100 { -/// return *item; -/// } -/// } -/// // The above loop always returns, so we must hint to the -/// // type checker that it isn't possible to get down here -/// unreachable!(); -/// } -/// ``` -#[macro_export] -macro_rules! unreachable( - () => ({ - panic!("internal error: entered unreachable code") - }); - ($msg:expr) => ({ - unreachable!("{}", $msg) - }); - ($fmt:expr, $($arg:tt)*) => ({ - panic!(concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) - }); -) - -/// A standardised placeholder for marking unfinished code. It panics with the -/// message `"not yet implemented"` when executed. -#[macro_export] -macro_rules! unimplemented( - () => (panic!("not yet implemented")) -) - -/// Use the syntax described in `std::fmt` to create a value of type `String`. -/// See `std::fmt` for more information. -/// -/// # Example -/// -/// ``` -/// format!("test"); -/// format!("hello {}", "world!"); -/// format!("x = {}, y = {y}", 10i, y = 30i); -/// ``` -#[macro_export] -#[stable] -macro_rules! format( - ($($arg:tt)*) => ( - format_args!(::std::fmt::format, $($arg)*) - ) -) - -/// Use the `format!` syntax to write data into a buffer of type `&mut Writer`. -/// See `std::fmt` for more information. -/// -/// # Example -/// -/// ``` -/// # #![allow(unused_must_use)] -/// -/// let mut w = Vec::new(); -/// write!(&mut w, "test"); -/// write!(&mut w, "formatted {}", "arguments"); -/// ``` -#[macro_export] -#[stable] -macro_rules! write( - ($dst:expr, $($arg:tt)*) => ({ - let dst = &mut *$dst; - format_args!(|args| { dst.write_fmt(args) }, $($arg)*) - }) -) - -/// Equivalent to the `write!` macro, except that a newline is appended after -/// the message is written. -#[macro_export] -#[stable] -macro_rules! writeln( - ($dst:expr, $fmt:expr $($arg:tt)*) => ( - write!($dst, concat!($fmt, "\n") $($arg)*) - ) -) - -/// Equivalent to the `println!` macro except that a newline is not printed at -/// the end of the message. -#[macro_export] -#[stable] -macro_rules! print( - ($($arg:tt)*) => (format_args!(::std::io::stdio::print_args, $($arg)*)) -) - -/// Macro for printing to a task's stdout handle. -/// -/// Each task can override its stdout handle via `std::io::stdio::set_stdout`. -/// The syntax of this macro is the same as that used for `format!`. For more -/// information, see `std::fmt` and `std::io::stdio`. -/// -/// # Example -/// -/// ``` -/// println!("hello there!"); -/// println!("format {} arguments", "some"); -/// ``` -#[macro_export] -#[stable] -macro_rules! println( - ($($arg:tt)*) => (format_args!(::std::io::stdio::println_args, $($arg)*)) -) - -/// Helper macro for unwrapping `Result` values while returning early with an -/// error if the value of the expression is `Err`. For more information, see -/// `std::io`. -#[macro_export] -macro_rules! try ( - ($expr:expr) => ({ - match $expr { - Ok(val) => val, - Err(err) => return Err(::std::error::FromError::from_error(err)) - } - }) -) - -/// Create a `std::vec::Vec` containing the arguments. -#[macro_export] -macro_rules! vec[ - ($($x:expr),*) => ({ - use std::slice::BoxedSlicePrelude; - let xs: ::std::boxed::Box<[_]> = box [$($x),*]; - xs.into_vec() - }); - ($($x:expr,)*) => (vec![$($x),*]) -] - -/// A macro to select an event from a number of receivers. -/// -/// This macro is used to wait for the first event to occur on a number of -/// receivers. It places no restrictions on the types of receivers given to -/// this macro, this can be viewed as a heterogeneous select. -/// -/// # Example -/// -/// ``` -/// let (tx1, rx1) = channel(); -/// let (tx2, rx2) = channel(); -/// # fn long_running_task() {} -/// # fn calculate_the_answer() -> int { 42i } -/// -/// spawn(proc() { long_running_task(); tx1.send(()) }); -/// spawn(proc() { tx2.send(calculate_the_answer()) }); -/// -/// select! ( -/// () = rx1.recv() => println!("the long running task finished first"), -/// answer = rx2.recv() => { -/// println!("the answer was: {}", answer); -/// } -/// ) -/// ``` -/// -/// For more information about select, see the `std::comm::Select` structure. -#[macro_export] -#[experimental] -macro_rules! select { - ( - $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ - ) => ({ - use std::comm::Select; - let sel = Select::new(); - $( let mut $rx = sel.handle(&$rx); )+ - unsafe { - $( $rx.add(); )+ - } - let ret = sel.wait(); - $( if ret == $rx.id() { let $name = $rx.$meth(); $code } else )+ - { unreachable!() } - }) -} - -// When testing the standard library, we link to the liblog crate to get the -// logging macros. In doing so, the liblog crate was linked against the real -// version of libstd, and uses a different std::fmt module than the test crate -// uses. To get around this difference, we redefine the log!() macro here to be -// just a dumb version of what it should be. -#[cfg(test)] -macro_rules! log ( - ($lvl:expr, $($args:tt)*) => ( - if log_enabled!($lvl) { println!($($args)*) } - ) -) - -/// Built-in macros to the compiler itself. -/// -/// These macros do not have any corresponding definition with a `macro_rules!` -/// macro, but are documented here. Their implementations can be found hardcoded -/// into libsyntax itself. -#[cfg(dox)] -pub mod builtin { - /// The core macro for formatted string creation & output. - /// - /// This macro takes as its first argument a callable expression which will - /// receive as its first argument a value of type `&fmt::Arguments`. This - /// value can be passed to the functions in `std::fmt` for performing useful - /// functions. All other formatting macros (`format!`, `write!`, - /// `println!`, etc) are proxied through this one. - /// - /// For more information, see the documentation in `std::fmt`. - /// - /// # Example - /// - /// ```rust - /// use std::fmt; - /// - /// let s = format_args!(fmt::format, "hello {}", "world"); - /// assert_eq!(s, format!("hello {}", "world")); - /// - /// format_args!(|args| { - /// // pass `args` to another function, etc. - /// }, "hello {}", "world"); - /// ``` - #[macro_export] - macro_rules! format_args( ($closure:expr, $fmt:expr $($args:tt)*) => ({ - /* compiler built-in */ - }) ) - - /// Inspect an environment variable at compile time. - /// - /// This macro will expand to the value of the named environment variable at - /// compile time, yielding an expression of type `&'static str`. - /// - /// If the environment variable is not defined, then a compilation error - /// will be emitted. To not emit a compile error, use the `option_env!` - /// macro instead. - /// - /// # Example - /// - /// ```rust - /// let path: &'static str = env!("PATH"); - /// println!("the $PATH variable at the time of compiling was: {}", path); - /// ``` - #[macro_export] - macro_rules! env( ($name:expr) => ({ /* compiler built-in */ }) ) - - /// Optionally inspect an environment variable at compile time. - /// - /// If the named environment variable is present at compile time, this will - /// expand into an expression of type `Option<&'static str>` whose value is - /// `Some` of the value of the environment variable. If the environment - /// variable is not present, then this will expand to `None`. - /// - /// A compile time error is never emitted when using this macro regardless - /// of whether the environment variable is present or not. - /// - /// # Example - /// - /// ```rust - /// let key: Option<&'static str> = option_env!("SECRET_KEY"); - /// println!("the secret key might be: {}", key); - /// ``` - #[macro_export] - macro_rules! option_env( ($name:expr) => ({ /* compiler built-in */ }) ) - - /// Concatenate literals into a static byte slice. - /// - /// This macro takes any number of comma-separated literal expressions, - /// yielding an expression of type `&'static [u8]` which is the - /// concatenation (left to right) of all the literals in their byte format. - /// - /// This extension currently only supports string literals, character - /// literals, and integers less than 256. The byte slice returned is the - /// utf8-encoding of strings and characters. - /// - /// # Example - /// - /// ``` - /// let rust = bytes!("r", 'u', "st", 255); - /// assert_eq!(rust[1], b'u'); - /// assert_eq!(rust[4], 255); - /// ``` - #[macro_export] - macro_rules! bytes( ($($e:expr),*) => ({ /* compiler built-in */ }) ) - - /// Concatenate identifiers into one identifier. - /// - /// This macro takes any number of comma-separated identifiers, and - /// concatenates them all into one, yielding an expression which is a new - /// identifier. Note that hygiene makes it such that this macro cannot - /// capture local variables, and macros are only allowed in item, - /// statement or expression position, meaning this macro may be difficult to - /// use in some situations. - /// - /// # Example - /// - /// ``` - /// #![feature(concat_idents)] - /// - /// # fn main() { - /// fn foobar() -> int { 23 } - /// - /// let f = concat_idents!(foo, bar); - /// println!("{}", f()); - /// # } - /// ``` - #[macro_export] - macro_rules! concat_idents( ($($e:ident),*) => ({ /* compiler built-in */ }) ) - - /// Concatenates literals into a static string slice. - /// - /// This macro takes any number of comma-separated literals, yielding an - /// expression of type `&'static str` which represents all of the literals - /// concatenated left-to-right. - /// - /// Integer and floating point literals are stringified in order to be - /// concatenated. - /// - /// # Example - /// - /// ``` - /// let s = concat!("test", 10i, 'b', true); - /// assert_eq!(s, "test10btrue"); - /// ``` - #[macro_export] - macro_rules! concat( ($($e:expr),*) => ({ /* compiler built-in */ }) ) - - /// A macro which expands to the line number on which it was invoked. - /// - /// The expanded expression has type `uint`, and the returned line is not - /// the invocation of the `line!()` macro itself, but rather the first macro - /// invocation leading up to the invocation of the `line!()` macro. - /// - /// # Example - /// - /// ``` - /// let current_line = line!(); - /// println!("defined on line: {}", current_line); - /// ``` - #[macro_export] - macro_rules! line( () => ({ /* compiler built-in */ }) ) - - /// A macro which expands to the column number on which it was invoked. - /// - /// The expanded expression has type `uint`, and the returned column is not - /// the invocation of the `column!()` macro itself, but rather the first macro - /// invocation leading up to the invocation of the `column!()` macro. - /// - /// # Example - /// - /// ``` - /// let current_col = column!(); - /// println!("defined on column: {}", current_col); - /// ``` - #[macro_export] - macro_rules! column( () => ({ /* compiler built-in */ }) ) - - /// A macro which expands to the file name from which it was invoked. - /// - /// The expanded expression has type `&'static str`, and the returned file - /// is not the invocation of the `file!()` macro itself, but rather the - /// first macro invocation leading up to the invocation of the `file!()` - /// macro. - /// - /// # Example - /// - /// ``` - /// let this_file = file!(); - /// println!("defined in file: {}", this_file); - /// ``` - #[macro_export] - macro_rules! file( () => ({ /* compiler built-in */ }) ) - - /// A macro which stringifies its argument. - /// - /// This macro will yield an expression of type `&'static str` which is the - /// stringification of all the tokens passed to the macro. No restrictions - /// are placed on the syntax of the macro invocation itself. - /// - /// # Example - /// - /// ``` - /// let one_plus_one = stringify!(1 + 1); - /// assert_eq!(one_plus_one, "1 + 1"); - /// ``` - #[macro_export] - macro_rules! stringify( ($t:tt) => ({ /* compiler built-in */ }) ) - - /// Includes a utf8-encoded file as a string. - /// - /// This macro will yield an expression of type `&'static str` which is the - /// contents of the filename specified. The file is located relative to the - /// current file (similarly to how modules are found), - /// - /// # Example - /// - /// ```rust,ignore - /// let secret_key = include_str!("secret-key.ascii"); - /// ``` - #[macro_export] - macro_rules! include_str( ($file:expr) => ({ /* compiler built-in */ }) ) - - /// Includes a file as a byte slice. - /// - /// This macro will yield an expression of type `&'static [u8]` which is - /// the contents of the filename specified. The file is located relative to - /// the current file (similarly to how modules are found), - /// - /// # Example - /// - /// ```rust,ignore - /// let secret_key = include_bin!("secret-key.bin"); - /// ``` - #[macro_export] - macro_rules! include_bin( ($file:expr) => ({ /* compiler built-in */ }) ) - - /// Expands to a string that represents the current module path. - /// - /// The current module path can be thought of as the hierarchy of modules - /// leading back up to the crate root. The first component of the path - /// returned is the name of the crate currently being compiled. - /// - /// # Example - /// - /// ```rust - /// mod test { - /// pub fn foo() { - /// assert!(module_path!().ends_with("test")); - /// } - /// } - /// - /// test::foo(); - /// ``` - #[macro_export] - macro_rules! module_path( () => ({ /* compiler built-in */ }) ) - - /// Boolean evaluation of configuration flags. - /// - /// In addition to the `#[cfg]` attribute, this macro is provided to allow - /// boolean expression evaluation of configuration flags. This frequently - /// leads to less duplicated code. - /// - /// The syntax given to this macro is the same syntax as the `cfg` - /// attribute. - /// - /// # Example - /// - /// ```rust - /// let my_directory = if cfg!(windows) { - /// "windows-specific-directory" - /// } else { - /// "unix-directory" - /// }; - /// ``` - #[macro_export] - macro_rules! cfg( ($cfg:tt) => ({ /* compiler built-in */ }) ) -} diff --git a/src/libst2/num/f32.rs b/src/libst2/num/f32.rs deleted file mode 100644 index 6c48d747299b2..0000000000000 --- a/src/libst2/num/f32.rs +++ /dev/null @@ -1,261 +0,0 @@ -// 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. - -//! Operations and constants for 32-bits floats (`f32` type) - -#![stable] -#![allow(missing_docs)] -#![allow(unsigned_negation)] -#![doc(primitive = "f32")] - -use prelude::*; - -use intrinsics; -use libc::c_int; -use num::{Float, FloatMath}; -use num::strconv; - -pub use core::f32::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; -pub use core::f32::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; -pub use core::f32::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; -pub use core::f32::consts; - -#[allow(dead_code)] -mod cmath { - use libc::{c_float, c_int}; - - #[link_name = "m"] - extern { - pub fn acosf(n: c_float) -> c_float; - pub fn asinf(n: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn cbrtf(n: c_float) -> c_float; - pub fn coshf(n: c_float) -> c_float; - pub fn erff(n: c_float) -> c_float; - pub fn erfcf(n: c_float) -> c_float; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn frexpf(n: c_float, value: &mut c_int) -> c_float; - pub fn fmaxf(a: c_float, b: c_float) -> c_float; - pub fn fminf(a: c_float, b: c_float) -> c_float; - pub fn fmodf(a: c_float, b: c_float) -> c_float; - pub fn nextafterf(x: c_float, y: c_float) -> c_float; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn ldexpf(x: c_float, n: c_int) -> c_float; - pub fn logbf(n: c_float) -> c_float; - pub fn log1pf(n: c_float) -> c_float; - pub fn ilogbf(n: c_float) -> c_int; - pub fn modff(n: c_float, iptr: &mut c_float) -> c_float; - pub fn sinhf(n: c_float) -> c_float; - pub fn tanf(n: c_float) -> c_float; - pub fn tanhf(n: c_float) -> c_float; - pub fn tgammaf(n: c_float) -> c_float; - - #[cfg(unix)] - pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; - - #[cfg(windows)] - #[link_name="__lgammaf_r"] - pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float; - } -} - -#[unstable = "trait is unstable"] -impl FloatMath for f32 { - /// Constructs a floating point number by multiplying `x` by 2 raised to the - /// power of `exp` - #[inline] - fn ldexp(x: f32, exp: int) -> f32 { unimplemented!() } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - #[inline] - fn frexp(self) -> (f32, int) { unimplemented!() } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - #[inline] - fn next_after(self, other: f32) -> f32 { unimplemented!() } - - #[inline] - fn max(self, other: f32) -> f32 { unimplemented!() } - - #[inline] - fn min(self, other: f32) -> f32 { unimplemented!() } - - #[inline] - fn abs_sub(self, other: f32) -> f32 { unimplemented!() } - - #[inline] - fn cbrt(self) -> f32 { unimplemented!() } - - #[inline] - fn hypot(self, other: f32) -> f32 { unimplemented!() } - - #[inline] - fn sin(self) -> f32 { unimplemented!() } - - #[inline] - fn cos(self) -> f32 { unimplemented!() } - - #[inline] - fn tan(self) -> f32 { unimplemented!() } - - #[inline] - fn asin(self) -> f32 { unimplemented!() } - - #[inline] - fn acos(self) -> f32 { unimplemented!() } - - #[inline] - fn atan(self) -> f32 { unimplemented!() } - - #[inline] - fn atan2(self, other: f32) -> f32 { unimplemented!() } - - /// Simultaneously computes the sine and cosine of the number - #[inline] - fn sin_cos(self) -> (f32, f32) { unimplemented!() } - - /// Returns the exponential of the number, minus `1`, in a way that is - /// accurate even if the number is close to zero - #[inline] - fn exp_m1(self) -> f32 { unimplemented!() } - - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more - /// accurately than if the operations were performed separately - #[inline] - fn ln_1p(self) -> f32 { unimplemented!() } - - #[inline] - fn sinh(self) -> f32 { unimplemented!() } - - #[inline] - fn cosh(self) -> f32 { unimplemented!() } - - #[inline] - fn tanh(self) -> f32 { unimplemented!() } - - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` - /// - `NAN` if `self` is `NAN` - #[inline] - fn asinh(self) -> f32 { unimplemented!() } - - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `INFINITY` if `self` is `INFINITY` - /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - #[inline] - fn acosh(self) -> f32 { unimplemented!() } - - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `INFINITY` if `self` is `1.0` - /// - `NEG_INFINITY` if `self` is `-1.0` - /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `INFINITY` and `NEG_INFINITY`) - #[inline] - fn atanh(self) -> f32 { unimplemented!() } -} - -// -// Section: String Conversions -// - -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_string(num: f32) -> String { unimplemented!() } - -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_hex(num: f32) -> String { unimplemented!() } - -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_radix_special(num: f32, rdx: uint) -> (String, bool) { unimplemented!() } - -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exact(num: f32, dig: uint) -> String { unimplemented!() } - -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_digits(num: f32, dig: uint) -> String { unimplemented!() } - -/// Converts a float to a string using the exponential notation with exactly the number of -/// provided digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> String { unimplemented!() } - -/// Converts a float to a string using the exponential notation with the maximum number of -/// digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String { unimplemented!() } diff --git a/src/libst2/num/f64.rs b/src/libst2/num/f64.rs deleted file mode 100644 index 5c196c8229662..0000000000000 --- a/src/libst2/num/f64.rs +++ /dev/null @@ -1,269 +0,0 @@ -// 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. - -//! Operations and constants for 64-bits floats (`f64` type) - -#![stable] -#![allow(missing_docs)] -#![doc(primitive = "f64")] - -use prelude::*; - -use intrinsics; -use libc::c_int; -use num::{Float, FloatMath}; -use num::strconv; - -pub use core::f64::{RADIX, MANTISSA_DIGITS, DIGITS, EPSILON, MIN_VALUE}; -pub use core::f64::{MIN_POS_VALUE, MAX_VALUE, MIN_EXP, MAX_EXP, MIN_10_EXP}; -pub use core::f64::{MAX_10_EXP, NAN, INFINITY, NEG_INFINITY}; -pub use core::f64::consts; - -#[allow(dead_code)] -mod cmath { - use libc::{c_double, c_int}; - - #[link_name = "m"] - extern { - pub fn acos(n: c_double) -> c_double; - pub fn asin(n: c_double) -> c_double; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn cbrt(n: c_double) -> c_double; - pub fn cosh(n: c_double) -> c_double; - pub fn erf(n: c_double) -> c_double; - pub fn erfc(n: c_double) -> c_double; - pub fn expm1(n: c_double) -> c_double; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fmax(a: c_double, b: c_double) -> c_double; - pub fn fmin(a: c_double, b: c_double) -> c_double; - pub fn fmod(a: c_double, b: c_double) -> c_double; - pub fn nextafter(x: c_double, y: c_double) -> c_double; - pub fn frexp(n: c_double, value: &mut c_int) -> c_double; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn ldexp(x: c_double, n: c_int) -> c_double; - pub fn logb(n: c_double) -> c_double; - pub fn log1p(n: c_double) -> c_double; - pub fn ilogb(n: c_double) -> c_int; - pub fn modf(n: c_double, iptr: &mut c_double) -> c_double; - pub fn sinh(n: c_double) -> c_double; - pub fn tan(n: c_double) -> c_double; - pub fn tanh(n: c_double) -> c_double; - pub fn tgamma(n: c_double) -> c_double; - - // These are commonly only available for doubles - - pub fn j0(n: c_double) -> c_double; - pub fn j1(n: c_double) -> c_double; - pub fn jn(i: c_int, n: c_double) -> c_double; - - pub fn y0(n: c_double) -> c_double; - pub fn y1(n: c_double) -> c_double; - pub fn yn(i: c_int, n: c_double) -> c_double; - - #[cfg(unix)] - pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; - #[cfg(windows)] - #[link_name="__lgamma_r"] - pub fn lgamma_r(n: c_double, sign: &mut c_int) -> c_double; - } -} - -#[unstable = "trait is unstable"] -impl FloatMath for f64 { - /// Constructs a floating point number by multiplying `x` by 2 raised to the - /// power of `exp` - #[inline] - fn ldexp(x: f64, exp: int) -> f64 { unimplemented!() } - - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// - `self = x * pow(2, exp)` - /// - `0.5 <= abs(x) < 1.0` - #[inline] - fn frexp(self) -> (f64, int) { unimplemented!() } - - /// Returns the next representable floating-point value in the direction of - /// `other`. - #[inline] - fn next_after(self, other: f64) -> f64 { unimplemented!() } - - #[inline] - fn max(self, other: f64) -> f64 { unimplemented!() } - - #[inline] - fn min(self, other: f64) -> f64 { unimplemented!() } - - #[inline] - fn abs_sub(self, other: f64) -> f64 { unimplemented!() } - - #[inline] - fn cbrt(self) -> f64 { unimplemented!() } - - #[inline] - fn hypot(self, other: f64) -> f64 { unimplemented!() } - - #[inline] - fn sin(self) -> f64 { unimplemented!() } - - #[inline] - fn cos(self) -> f64 { unimplemented!() } - - #[inline] - fn tan(self) -> f64 { unimplemented!() } - - #[inline] - fn asin(self) -> f64 { unimplemented!() } - - #[inline] - fn acos(self) -> f64 { unimplemented!() } - - #[inline] - fn atan(self) -> f64 { unimplemented!() } - - #[inline] - fn atan2(self, other: f64) -> f64 { unimplemented!() } - - /// Simultaneously computes the sine and cosine of the number - #[inline] - fn sin_cos(self) -> (f64, f64) { unimplemented!() } - - /// Returns the exponential of the number, minus `1`, in a way that is - /// accurate even if the number is close to zero - #[inline] - fn exp_m1(self) -> f64 { unimplemented!() } - - /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more - /// accurately than if the operations were performed separately - #[inline] - fn ln_1p(self) -> f64 { unimplemented!() } - - #[inline] - fn sinh(self) -> f64 { unimplemented!() } - - #[inline] - fn cosh(self) -> f64 { unimplemented!() } - - #[inline] - fn tanh(self) -> f64 { unimplemented!() } - - /// Inverse hyperbolic sine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic sine of `self` will be returned - /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY` - /// - `NAN` if `self` is `NAN` - #[inline] - fn asinh(self) -> f64 { unimplemented!() } - - /// Inverse hyperbolic cosine - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic cosine of `self` will be returned - /// - `INFINITY` if `self` is `INFINITY` - /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`) - #[inline] - fn acosh(self) -> f64 { unimplemented!() } - - /// Inverse hyperbolic tangent - /// - /// # Returns - /// - /// - on success, the inverse hyperbolic tangent of `self` will be returned - /// - `self` if `self` is `0.0` or `-0.0` - /// - `INFINITY` if `self` is `1.0` - /// - `NEG_INFINITY` if `self` is `-1.0` - /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0` - /// (including `INFINITY` and `NEG_INFINITY`) - #[inline] - fn atanh(self) -> f64 { unimplemented!() } -} - -// -// Section: String Conversions -// - -/// Converts a float to a string -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_string(num: f64) -> String { unimplemented!() } - -/// Converts a float to a string in hexadecimal format -/// -/// # Arguments -/// -/// * num - The float value -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_hex(num: f64) -> String { unimplemented!() } - -/// Converts a float to a string in a given radix, and a flag indicating -/// whether it's a special value -/// -/// # Arguments -/// -/// * num - The float value -/// * radix - The base to use -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_radix_special(num: f64, rdx: uint) -> (String, bool) { unimplemented!() } - -/// Converts a float to a string with exactly the number of -/// provided significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exact(num: f64, dig: uint) -> String { unimplemented!() } - -/// Converts a float to a string with a maximum number of -/// significant digits -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of significant digits -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_digits(num: f64, dig: uint) -> String { unimplemented!() } - -/// Converts a float to a string using the exponential notation with exactly the number of -/// provided digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exp_exact(num: f64, dig: uint, upper: bool) -> String { unimplemented!() } - -/// Converts a float to a string using the exponential notation with the maximum number of -/// digits after the decimal point in the significand -/// -/// # Arguments -/// -/// * num - The float value -/// * digits - The number of digits after the decimal point -/// * upper - Use `E` instead of `e` for the exponent sign -#[inline] -#[experimental = "may be removed or relocated"] -pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String { unimplemented!() } diff --git a/src/libst2/num/float_macros.rs b/src/libst2/num/float_macros.rs deleted file mode 100644 index 4b3727ead6148..0000000000000 --- a/src/libst2/num/float_macros.rs +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -#![experimental] -#![macro_escape] -#![doc(hidden)] - -macro_rules! assert_approx_eq( - ($a:expr, $b:expr) => ({ - use num::Float; - let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) -) diff --git a/src/libst2/num/i16.rs b/src/libst2/num/i16.rs deleted file mode 100644 index 333d1d7df0b5c..0000000000000 --- a/src/libst2/num/i16.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for signed 16-bits integers (`i16` type) - -#![stable] -#![doc(primitive = "i16")] - -pub use core::i16::{BITS, BYTES, MIN, MAX}; - -int_module!(i16) diff --git a/src/libst2/num/i32.rs b/src/libst2/num/i32.rs deleted file mode 100644 index 44b5397bf74e5..0000000000000 --- a/src/libst2/num/i32.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for signed 32-bits integers (`i32` type) - -#![stable] -#![doc(primitive = "i32")] - -pub use core::i32::{BITS, BYTES, MIN, MAX}; - -int_module!(i32) diff --git a/src/libst2/num/i64.rs b/src/libst2/num/i64.rs deleted file mode 100644 index de6fa0d3ef841..0000000000000 --- a/src/libst2/num/i64.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for signed 64-bits integers (`i64` type) - -#![stable] -#![doc(primitive = "i64")] - -pub use core::i64::{BITS, BYTES, MIN, MAX}; - -int_module!(i64) diff --git a/src/libst2/num/i8.rs b/src/libst2/num/i8.rs deleted file mode 100644 index 3b9fbcb768bee..0000000000000 --- a/src/libst2/num/i8.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for signed 8-bits integers (`i8` type) - -#![stable] -#![doc(primitive = "i8")] - -pub use core::i8::{BITS, BYTES, MIN, MAX}; - -int_module!(i8) diff --git a/src/libst2/num/int.rs b/src/libst2/num/int.rs deleted file mode 100644 index 36c021efe0a39..0000000000000 --- a/src/libst2/num/int.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -//! Operations and constants for architecture-sized signed integers (`int` type) - -#![unstable] -#![doc(primitive = "int")] - -pub use core::int::{BITS, BYTES, MIN, MAX}; - -int_module!(int) diff --git a/src/libst2/num/int_macros.rs b/src/libst2/num/int_macros.rs deleted file mode 100644 index 2f1162d28e558..0000000000000 --- a/src/libst2/num/int_macros.rs +++ /dev/null @@ -1,17 +0,0 @@ -// 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. - -#![experimental] -#![macro_escape] -#![doc(hidden)] - -macro_rules! int_module (($T:ty) => ( - -)) diff --git a/src/libst2/num/mod.rs b/src/libst2/num/mod.rs deleted file mode 100644 index dd2a8e8cc8fb7..0000000000000 --- a/src/libst2/num/mod.rs +++ /dev/null @@ -1,143 +0,0 @@ -// 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. - -//! Numeric traits and functions for generic mathematics -//! -//! These are implemented for the primitive numeric types in `std::{u8, u16, -//! u32, u64, uint, i8, i16, i32, i64, int, f32, f64}`. - -#![stable] -#![allow(missing_docs)] - -#[cfg(test)] use cmp::PartialEq; -#[cfg(test)] use fmt::Show; -#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; - -pub use core::num::{Num, div_rem, Zero, zero, One, one}; -pub use core::num::{Unsigned, pow, Bounded}; -pub use core::num::{Primitive, Int, SignedInt, UnsignedInt}; -pub use core::num::{cast, FromPrimitive, NumCast, ToPrimitive}; -pub use core::num::{next_power_of_two, is_power_of_two}; -pub use core::num::{checked_next_power_of_two}; -pub use core::num::{from_int, from_i8, from_i16, from_i32, from_i64}; -pub use core::num::{from_uint, from_u8, from_u16, from_u32, from_u64}; -pub use core::num::{from_f32, from_f64}; -pub use core::num::{FromStrRadix, from_str_radix}; -pub use core::num::{FPCategory, FPNaN, FPInfinite, FPZero, FPSubnormal}; -pub use core::num::{FPNormal, Float}; - -#[experimental = "may be removed or relocated"] -pub mod strconv; - -/// Mathematical operations on primitive floating point numbers. -#[unstable = "may be altered to inline the Float trait"] -pub trait FloatMath: Float { - /// Constructs a floating point number created by multiplying `x` by 2 - /// raised to the power of `exp`. - fn ldexp(x: Self, exp: int) -> Self; - /// Breaks the number into a normalized fraction and a base-2 exponent, - /// satisfying: - /// - /// * `self = x * pow(2, exp)` - /// - /// * `0.5 <= abs(x) < 1.0` - fn frexp(self) -> (Self, int); - - /// Returns the next representable floating-point value in the direction of - /// `other`. - fn next_after(self, other: Self) -> Self; - - /// Returns the maximum of the two numbers. - fn max(self, other: Self) -> Self; - /// Returns the minimum of the two numbers. - fn min(self, other: Self) -> Self; - - /// The positive difference of two numbers. Returns `0.0` if the number is - /// less than or equal to `other`, otherwise the difference between`self` - /// and `other` is returned. - fn abs_sub(self, other: Self) -> Self; - - /// Take the cubic root of a number. - fn cbrt(self) -> Self; - /// Calculate the length of the hypotenuse of a right-angle triangle given - /// legs of length `x` and `y`. - fn hypot(self, other: Self) -> Self; - - /// Computes the sine of a number (in radians). - fn sin(self) -> Self; - /// Computes the cosine of a number (in radians). - fn cos(self) -> Self; - /// Computes the tangent of a number (in radians). - fn tan(self) -> Self; - - /// Computes the arcsine of a number. Return value is in radians in - /// the range [-pi/2, pi/2] or NaN if the number is outside the range - /// [-1, 1]. - fn asin(self) -> Self; - /// Computes the arccosine of a number. Return value is in radians in - /// the range [0, pi] or NaN if the number is outside the range - /// [-1, 1]. - fn acos(self) -> Self; - /// Computes the arctangent of a number. Return value is in radians in the - /// range [-pi/2, pi/2]; - fn atan(self) -> Self; - /// Computes the four quadrant arctangent of a number, `y`, and another - /// number `x`. Return value is in radians in the range [-pi, pi]. - fn atan2(self, other: Self) -> Self; - /// Simultaneously computes the sine and cosine of the number, `x`. Returns - /// `(sin(x), cos(x))`. - fn sin_cos(self) -> (Self, Self); - - /// Returns the exponential of the number, minus 1, in a way that is - /// accurate even if the number is close to zero. - fn exp_m1(self) -> Self; - /// Returns the natural logarithm of the number plus 1 (`ln(1+n)`) more - /// accurately than if the operations were performed separately. - fn ln_1p(self) -> Self; - - /// Hyperbolic sine function. - fn sinh(self) -> Self; - /// Hyperbolic cosine function. - fn cosh(self) -> Self; - /// Hyperbolic tangent function. - fn tanh(self) -> Self; - /// Inverse hyperbolic sine function. - fn asinh(self) -> Self; - /// Inverse hyperbolic cosine function. - fn acosh(self) -> Self; - /// Inverse hyperbolic tangent function. - fn atanh(self) -> Self; -} - -// DEPRECATED - -#[deprecated = "Use `FloatMath::abs_sub`"] -pub fn abs_sub(x: T, y: T) -> T { unimplemented!() } - -/// Helper function for testing numeric operations -#[cfg(test)] -pub fn test_num(ten: T, two: T) where - T: PartialEq + NumCast - + Add + Sub - + Mul + Div - + Rem + Show -{ - assert_eq!(ten.add(&two), cast(12i).unwrap()); - assert_eq!(ten.sub(&two), cast(8i).unwrap()); - assert_eq!(ten.mul(&two), cast(20i).unwrap()); - assert_eq!(ten.div(&two), cast(5i).unwrap()); - assert_eq!(ten.rem(&two), cast(0i).unwrap()); - - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.rem(&two), ten % two); -} diff --git a/src/libst2/num/strconv.rs b/src/libst2/num/strconv.rs deleted file mode 100644 index 649298d9c0818..0000000000000 --- a/src/libst2/num/strconv.rs +++ /dev/null @@ -1,558 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15679 - -#![allow(missing_docs)] - -pub use self::ExponentFormat::*; -pub use self::SignificantDigits::*; -pub use self::SignFormat::*; - -use char; -use char::Char; -use num; -use num::{Int, Float, FPNaN, FPInfinite, ToPrimitive}; -use slice::{SlicePrelude, CloneSliceAllocPrelude}; -use str::StrPrelude; -use string::String; -use vec::Vec; - -/// A flag that specifies whether to use exponential (scientific) notation. -pub enum ExponentFormat { - /// Do not use exponential notation. - ExpNone, - /// Use exponential notation with the exponent having a base of 10 and the - /// exponent sign being `e` or `E`. For example, 1000 would be printed - /// 1e3. - ExpDec, - /// Use exponential notation with the exponent having a base of 2 and the - /// exponent sign being `p` or `P`. For example, 8 would be printed 1p3. - ExpBin, -} - -/// The number of digits used for emitting the fractional part of a number, if -/// any. -pub enum SignificantDigits { - /// All calculable digits will be printed. - /// - /// Note that bignums or fractions may cause a surprisingly large number - /// of digits to be printed. - DigAll, - - /// At most the given number of digits will be printed, truncating any - /// trailing zeroes. - DigMax(uint), - - /// Precisely the given number of digits will be printed. - DigExact(uint) -} - -/// How to emit the sign of a number. -pub enum SignFormat { - /// No sign will be printed. The exponent sign will also be emitted. - SignNone, - /// `-` will be printed for negative values, but no sign will be emitted - /// for positive numbers. - SignNeg, - /// `+` will be printed for positive values, and `-` will be printed for - /// negative values. - SignAll, -} - -/** - * Converts an integral number to its string representation as a byte vector. - * This is meant to be a common base implementation for all integral string - * conversion functions like `to_string()` or `to_str_radix()`. - * - * # Arguments - * - `num` - The number to convert. Accepts any number that - * implements the numeric traits. - * - `radix` - Base to use. Accepts only the values 2-36. - * - `sign` - How to emit the sign. Options are: - * - `SignNone`: No sign at all. Basically emits `abs(num)`. - * - `SignNeg`: Only `-` on negative values. - * - `SignAll`: Both `+` on positive, and `-` on negative numbers. - * - `f` - a callback which will be invoked for each ascii character - * which composes the string representation of this integer - * - * # Return value - * A tuple containing the byte vector, and a boolean flag indicating - * whether it represents a special value like `inf`, `-inf`, `NaN` or not. - * It returns a tuple because there can be ambiguity between a special value - * and a number representation at higher bases. - * - * # Panics - * - Panics if `radix` < 2 or `radix` > 36. - */ -fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8|) { - assert!(2 <= radix && radix <= 36); - - let _0: T = Int::zero(); - - let neg = num < _0; - let radix_gen: T = num::cast(radix).unwrap(); - - let mut deccum = num; - // This is just for integral types, the largest of which is a u64. The - // smallest base that we can have is 2, so the most number of digits we're - // ever going to have is 64 - let mut buf = [0u8, ..64]; - let mut cur = 0; - - // Loop at least once to make sure at least a `0` gets emitted. - loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit_signed = deccum % radix_gen; - let current_digit = if current_digit_signed < _0 { - _0 - current_digit_signed - } else { - current_digit_signed - }; - buf[cur] = match current_digit.to_u8().unwrap() { - i @ 0...9 => b'0' + i, - i => b'a' + (i - 10), - }; - cur += 1; - - deccum = deccum / radix_gen; - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // Decide what sign to put in front - match sign { - SignNeg | SignAll if neg => { f(b'-'); } - SignAll => { f(b'+'); } - _ => () - } - - // We built the number in reverse order, so un-reverse it here - while cur > 0 { - cur -= 1; - f(buf[cur]); - } -} - -/** - * Converts a number to its string representation as a byte vector. - * This is meant to be a common base implementation for all numeric string - * conversion functions like `to_string()` or `to_str_radix()`. - * - * # Arguments - * - `num` - The number to convert. Accepts any number that - * implements the numeric traits. - * - `radix` - Base to use. Accepts only the values 2-36. If the exponential notation - * is used, then this base is only used for the significand. The exponent - * itself always printed using a base of 10. - * - `negative_zero` - Whether to treat the special value `-0` as - * `-0` or as `+0`. - * - `sign` - How to emit the sign. See `SignFormat`. - * - `digits` - The amount of digits to use for emitting the fractional - * part, if any. See `SignificantDigits`. - * - `exp_format` - Whether or not to use the exponential (scientific) notation. - * See `ExponentFormat`. - * - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if - * exponential notation is desired. - * - * # Return value - * A tuple containing the byte vector, and a boolean flag indicating - * whether it represents a special value like `inf`, `-inf`, `NaN` or not. - * It returns a tuple because there can be ambiguity between a special value - * and a number representation at higher bases. - * - * # Panics - * - Panics if `radix` < 2 or `radix` > 36. - * - Panics if `radix` > 14 and `exp_format` is `ExpDec` due to conflict - * between digit and exponent sign `'e'`. - * - Panics if `radix` > 25 and `exp_format` is `ExpBin` due to conflict - * between digit and exponent sign `'p'`. - */ -pub fn float_to_str_bytes_common( - num: T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool - ) -> (Vec, bool) { - assert!(2 <= radix && radix <= 36); - match exp_format { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' - => panic!("float_to_str_bytes_common: radix {} incompatible with \ - use of 'p' as binary exponent", radix), - _ => () - } - - let _0: T = Float::zero(); - let _1: T = Float::one(); - - match num.classify() { - FPNaN => { return (b"NaN".to_vec(), true); } - FPInfinite if num > _0 => { - return match sign { - SignAll => (b"+inf".to_vec(), true), - _ => (b"inf".to_vec(), true) - }; - } - FPInfinite if num < _0 => { - return match sign { - SignNone => (b"inf".to_vec(), true), - _ => (b"-inf".to_vec(), true), - }; - } - _ => {} - } - - let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity()); - let mut buf = Vec::new(); - let radix_gen: T = num::cast(radix as int).unwrap(); - - let (num, exp) = match exp_format { - ExpNone => (num, 0i32), - ExpDec | ExpBin => { - if num == _0 { - (num, 0i32) - } else { - let (exp, exp_base) = match exp_format { - ExpDec => (num.abs().log10().floor(), num::cast::(10.0f64).unwrap()), - ExpBin => (num.abs().log2().floor(), num::cast::(2.0f64).unwrap()), - ExpNone => unreachable!() - }; - - (num / exp_base.powf(exp), num::cast::(exp).unwrap()) - } - } - }; - - // First emit the non-fractional part, looping at least once to make - // sure at least a `0` gets emitted. - let mut deccum = num.trunc(); - loop { - // Calculate the absolute value of each digit instead of only - // doing it once for the whole number because a - // representable negative number doesn't necessary have an - // representable additive inverse of the same type - // (See twos complement). But we assume that for the - // numbers [-35 .. 0] we always have [0 .. 35]. - let current_digit = (deccum % radix_gen).abs(); - - // Decrease the deccumulator one digit at a time - deccum = deccum / radix_gen; - deccum = deccum.trunc(); - - buf.push(char::from_digit(current_digit.to_int().unwrap() as uint, radix) - .unwrap() as u8); - - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // If limited digits, calculate one digit more for rounding. - let (limit_digits, digit_count, exact) = match digits { - DigAll => (false, 0u, false), - DigMax(count) => (true, count+1, false), - DigExact(count) => (true, count+1, true) - }; - - // Decide what sign to put in front - match sign { - SignNeg | SignAll if neg => { - buf.push(b'-'); - } - SignAll => { - buf.push(b'+'); - } - _ => () - } - - buf.reverse(); - - // Remember start of the fractional digits. - // Points one beyond end of buf if none get generated, - // or at the '.' otherwise. - let start_fractional_digits = buf.len(); - - // Now emit the fractional part, if any - deccum = num.fract(); - if deccum != _0 || (limit_digits && exact && digit_count > 0) { - buf.push(b'.'); - let mut dig = 0u; - - // calculate new digits while - // - there is no limit and there are digits left - // - or there is a limit, it's not reached yet and - // - it's exact - // - or it's a maximum, and there are still digits left - while (!limit_digits && deccum != _0) - || (limit_digits && dig < digit_count && ( - exact - || (!exact && deccum != _0) - ) - ) { - // Shift first fractional digit into the integer part - deccum = deccum * radix_gen; - - // Calculate the absolute value of each digit. - // See note in first loop. - let current_digit = deccum.trunc().abs(); - - buf.push(char::from_digit( - current_digit.to_int().unwrap() as uint, radix).unwrap() as u8); - - // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fract(); - dig += 1u; - } - - // If digits are limited, and that limit has been reached, - // cut off the one extra digit, and depending on its value - // round the remaining ones. - if limit_digits && dig == digit_count { - let ascii2value = |chr: u8| { - (chr as char).to_digit(radix).unwrap() - }; - let value2ascii = |val: uint| { - char::from_digit(val, radix).unwrap() as u8 - }; - - let extra_digit = ascii2value(buf.pop().unwrap()); - if extra_digit >= radix / 2 { // -> need to round - let mut i: int = buf.len() as int - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i as uint] == b'-' - || buf[i as uint] == b'+' { - buf.insert((i + 1) as uint, value2ascii(1)); - break; - } - - // Skip the '.' - if buf[i as uint] == b'.' { i -= 1; continue; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i as uint]); - if current_digit < (radix - 1) { - buf[i as uint] = value2ascii(current_digit+1); - break; - } else { - buf[i as uint] = value2ascii(0); - i -= 1; - } - } - } - } - } - - // if number of digits is not exact, remove all trailing '0's up to - // and including the '.' - if !exact { - let buf_max_i = buf.len() - 1; - - // index to truncate from - let mut i = buf_max_i; - - // discover trailing zeros of fractional part - while i > start_fractional_digits && buf[i] == b'0' { - i -= 1; - } - - // Only attempt to truncate digits if buf has fractional digits - if i >= start_fractional_digits { - // If buf ends with '.', cut that too. - if buf[i] == b'.' { i -= 1 } - - // only resize buf if we actually remove digits - if i < buf_max_i { - buf = buf.slice(0, i + 1).to_vec(); - } - } - } // If exact and trailing '.', just cut that - else { - let max_i = buf.len() - 1; - if buf[max_i] == b'.' { - buf = buf.slice(0, max_i).to_vec(); - } - } - - match exp_format { - ExpNone => (), - _ => { - buf.push(match exp_format { - ExpDec if exp_upper => 'E', - ExpDec if !exp_upper => 'e', - ExpBin if exp_upper => 'P', - ExpBin if !exp_upper => 'p', - _ => unreachable!() - } as u8); - - int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c)); - } - } - - (buf, false) -} - -/** - * Converts a number to its string representation. This is a wrapper for - * `to_str_bytes_common()`, for details see there. - */ -#[inline] -pub fn float_to_str_common( - num: T, radix: uint, negative_zero: bool, - sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool - ) -> (String, bool) { - let (bytes, special) = float_to_str_bytes_common(num, radix, - negative_zero, sign, digits, exp_format, exp_capital); - (String::from_utf8(bytes).unwrap(), special) -} - -// Some constants for from_str_bytes_common's input validation, -// they define minimum radix values for which the character is a valid digit. -static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u; -static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; - -#[cfg(test)] -mod tests { - use string::ToString; - - #[test] - fn test_int_to_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert_eq!(i8_val.to_string(), "127".to_string()); - - i8_val += 1 as i8; - assert_eq!(i8_val.to_string(), "-128".to_string()); - - let mut i16_val: i16 = 32_767_i16; - assert_eq!(i16_val.to_string(), "32767".to_string()); - - i16_val += 1 as i16; - assert_eq!(i16_val.to_string(), "-32768".to_string()); - - let mut i32_val: i32 = 2_147_483_647_i32; - assert_eq!(i32_val.to_string(), "2147483647".to_string()); - - i32_val += 1 as i32; - assert_eq!(i32_val.to_string(), "-2147483648".to_string()); - - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert_eq!(i64_val.to_string(), "9223372036854775807".to_string()); - - i64_val += 1 as i64; - assert_eq!(i64_val.to_string(), "-9223372036854775808".to_string()); - } -} - -#[cfg(test)] -mod bench { - extern crate test; - - mod uint { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use std::fmt; - - #[inline] - fn to_string(x: uint, base: u8) { - format!("{}", fmt::radix(x, base)); - } - - #[bench] - fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 2); }) - } - - #[bench] - fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 8); }) - } - - #[bench] - fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 10); }) - } - - #[bench] - fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 16); }) - } - - #[bench] - fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 36); }) - } - } - - mod int { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use std::fmt; - - #[inline] - fn to_string(x: int, base: u8) { - format!("{}", fmt::radix(x, base)); - } - - #[bench] - fn to_str_bin(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 2); }) - } - - #[bench] - fn to_str_oct(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 8); }) - } - - #[bench] - fn to_str_dec(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 10); }) - } - - #[bench] - fn to_str_hex(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 16); }) - } - - #[bench] - fn to_str_base_36(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { to_string(rng.gen::(), 36); }) - } - } - - mod f64 { - use super::test::Bencher; - use rand::{weak_rng, Rng}; - use f64; - - #[bench] - fn float_to_string(b: &mut Bencher) { - let mut rng = weak_rng(); - b.iter(|| { f64::to_string(rng.gen()); }) - } - } -} diff --git a/src/libst2/num/u16.rs b/src/libst2/num/u16.rs deleted file mode 100644 index a83a66c23a526..0000000000000 --- a/src/libst2/num/u16.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for unsigned 16-bits integers (`u16` type) - -#![stable] -#![doc(primitive = "u16")] - -pub use core::u16::{BITS, BYTES, MIN, MAX}; - -uint_module!(u16) diff --git a/src/libst2/num/u32.rs b/src/libst2/num/u32.rs deleted file mode 100644 index 7271203b23b6c..0000000000000 --- a/src/libst2/num/u32.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for unsigned 32-bits integers (`u32` type) - -#![stable] -#![doc(primitive = "u32")] - -pub use core::u32::{BITS, BYTES, MIN, MAX}; - -uint_module!(u32) diff --git a/src/libst2/num/u64.rs b/src/libst2/num/u64.rs deleted file mode 100644 index 25de2f3b25565..0000000000000 --- a/src/libst2/num/u64.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for unsigned 64-bits integer (`u64` type) - -#![stable] -#![doc(primitive = "u64")] - -pub use core::u64::{BITS, BYTES, MIN, MAX}; - -uint_module!(u64) diff --git a/src/libst2/num/u8.rs b/src/libst2/num/u8.rs deleted file mode 100644 index 22dedeecf3b10..0000000000000 --- a/src/libst2/num/u8.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Operations and constants for unsigned 8-bits integers (`u8` type) - -#![stable] -#![doc(primitive = "u8")] - -pub use core::u8::{BITS, BYTES, MIN, MAX}; - -uint_module!(u8) diff --git a/src/libst2/num/uint.rs b/src/libst2/num/uint.rs deleted file mode 100644 index a425aab3aa10c..0000000000000 --- a/src/libst2/num/uint.rs +++ /dev/null @@ -1,18 +0,0 @@ -// 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. - -//! Operations and constants for architecture-sized unsigned integers (`uint` type) - -#![unstable] -#![doc(primitive = "uint")] - -pub use core::uint::{BITS, BYTES, MIN, MAX}; - -uint_module!(uint) diff --git a/src/libst2/num/uint_macros.rs b/src/libst2/num/uint_macros.rs deleted file mode 100644 index de27fef50dad3..0000000000000 --- a/src/libst2/num/uint_macros.rs +++ /dev/null @@ -1,37 +0,0 @@ -// 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. - -#![experimental] -#![macro_escape] -#![doc(hidden)] -#![allow(unsigned_negation)] - -macro_rules! uint_module (($T:ty) => ( - -// String conversion functions and impl num -> str - -/// Convert to a string as a byte slice in a given base. -/// -/// Use in place of x.to_string() when you do not need to store the string permanently -/// -/// # Examples -/// -/// ``` -/// #![allow(deprecated)] -/// -/// std::uint::to_str_bytes(123, 10, |v| { -/// assert!(v == "123".as_bytes()); -/// }); -/// ``` -#[inline] -#[deprecated = "just use .to_string(), or a BufWriter with write! if you mustn't allocate"] -pub fn to_str_bytes(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U { unimplemented!() } - -)) diff --git a/src/libst2/os.rs b/src/libst2/os.rs deleted file mode 100644 index db36c8204d7b1..0000000000000 --- a/src/libst2/os.rs +++ /dev/null @@ -1,894 +0,0 @@ -// 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. - -/*! - * Higher-level interfaces to libc::* functions and operating system services. - * - * In general these take and return rust types, use rust idioms (enums, - * closures, vectors) rather than C idioms, and do more extensive safety - * checks. - * - * This module is not meant to only contain 1:1 mappings to libc entries; any - * os-interface code that is reasonably useful and broadly applicable can go - * here. Including utility routines that merely build on other os code. - * - * We assume the general case is that users do not care, and do not want to - * be made to care, which operating system they are on. While they may want - * to special case various special cases -- and so we will not _hide_ the - * facts of which OS the user is on -- they should be given the opportunity - * to write OS-ignorant code by default. - */ - -#![experimental] - -#![allow(missing_docs)] -#![allow(non_snake_case)] - -pub use self::MemoryMapKind::*; -pub use self::MapOption::*; -pub use self::MapError::*; - -use clone::Clone; -use error::{FromError, Error}; -use fmt; -use io::{IoResult, IoError}; -use iter::Iterator; -use libc::{c_void, c_int}; -use libc; -use boxed::Box; -use ops::Drop; -use option::{Some, None, Option}; -use os; -use path::{Path, GenericPath, BytesContainer}; -use sys; -use sys::os as os_imp; -use ptr::RawPtr; -use ptr; -use result::{Err, Ok, Result}; -use slice::{AsSlice, SlicePrelude, PartialEqSlicePrelude}; -use slice::CloneSliceAllocPrelude; -use str::{Str, StrPrelude, StrAllocating}; -use string::{String, ToString}; -use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; -use vec::Vec; - -#[cfg(unix)] use c_str::ToCStr; -#[cfg(unix)] use libc::c_char; - -/// Get the number of cores available -pub fn num_cpus() -> uint { unimplemented!() } - -pub const TMPBUF_SZ : uint = 1000u; -const BUF_BYTES : uint = 2048u; - -/// Returns the current working directory as a `Path`. -/// -/// # Errors -/// -/// Returns an `Err` if the current working directory value is invalid. -/// Possible cases: -/// -/// * Current directory does not exist. -/// * There are insufficient permissions to access the current directory. -/// * The internal buffer is not large enough to hold the path. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// // We assume that we are in a valid directory like "/home". -/// let current_working_directory = os::getcwd().unwrap(); -/// println!("The current directory is {}", current_working_directory.display()); -/// // /home -/// ``` -#[cfg(unix)] -pub fn getcwd() -> IoResult { unimplemented!() } - -/// Returns the current working directory as a `Path`. -/// -/// # Errors -/// -/// Returns an `Err` if the current working directory value is invalid. -/// Possible cases: -/// -/// * Current directory does not exist. -/// * There are insufficient permissions to access the current directory. -/// * The internal buffer is not large enough to hold the path. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// // We assume that we are in a valid directory like "C:\\Windows". -/// let current_working_directory = os::getcwd().unwrap(); -/// println!("The current directory is {}", current_working_directory.display()); -/// // C:\\Windows -/// ``` -#[cfg(windows)] -pub fn getcwd() -> IoResult { unimplemented!() } - -#[cfg(windows)] -pub mod windows { - use libc::types::os::arch::extra::DWORD; - use libc; - use option::{None, Option}; - use option; - use os::TMPBUF_SZ; - use slice::{SlicePrelude}; - use string::String; - use str::StrPrelude; - use vec::Vec; - - pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) - -> Option { unimplemented!() } -} - -/* -Accessing environment variables is not generally threadsafe. -Serialize access through a global lock. -*/ -fn with_env_lock(f: || -> T) -> T { unimplemented!() } - -/// Returns a vector of (variable, value) pairs, for all the environment -/// variables of the current process. -/// -/// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()` -/// for details. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// // We will iterate through the references to the element returned by os::env(); -/// for &(ref key, ref value) in os::env().iter() { -/// println!("'{}': '{}'", key, value ); -/// } -/// ``` -pub fn env() -> Vec<(String,String)> { unimplemented!() } - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env_as_bytes() -> Vec<(Vec,Vec)> { unimplemented!() } - -#[cfg(unix)] -/// Fetches the environment variable `n` from the current process, returning -/// None if the variable isn't set. -/// -/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See -/// `String::from_utf8_lossy()` for details. -/// -/// # Panics -/// -/// Panics if `n` has any interior NULs. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// let key = "HOME"; -/// match os::getenv(key) { -/// Some(val) => println!("{}: {}", key, val), -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -pub fn getenv(n: &str) -> Option { unimplemented!() } - -#[cfg(unix)] -/// Fetches the environment variable `n` byte vector from the current process, -/// returning None if the variable isn't set. -/// -/// # Panics -/// -/// Panics if `n` has any interior NULs. -pub fn getenv_as_bytes(n: &str) -> Option> { unimplemented!() } - -#[cfg(windows)] -/// Fetches the environment variable `n` from the current process, returning -/// None if the variable isn't set. -pub fn getenv(n: &str) -> Option { unimplemented!() } - -#[cfg(windows)] -/// Fetches the environment variable `n` byte vector from the current process, -/// returning None if the variable isn't set. -pub fn getenv_as_bytes(n: &str) -> Option> { unimplemented!() } - -/// Sets the environment variable `n` to the value `v` for the currently running -/// process. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// let key = "KEY"; -/// os::setenv(key, "VALUE"); -/// match os::getenv(key) { -/// Some(ref val) => println!("{}: {}", key, val), -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -pub fn setenv(n: &str, v: T) { unimplemented!() } - -/// Remove a variable from the environment entirely. -pub fn unsetenv(n: &str) { unimplemented!() } - -/// Parses input according to platform conventions for the `PATH` -/// environment variable. -/// -/// # Example -/// ```rust -/// use std::os; -/// -/// let key = "PATH"; -/// match os::getenv_as_bytes(key) { -/// Some(paths) => { -/// for path in os::split_paths(paths).iter() { -/// println!("'{}'", path.display()); -/// } -/// } -/// None => println!("{} is not defined in the environment.", key) -/// } -/// ``` -pub fn split_paths(unparsed: T) -> Vec { unimplemented!() } - -/// A low-level OS in-memory pipe. -pub struct Pipe { - /// A file descriptor representing the reading end of the pipe. Data written - /// on the `out` file descriptor can be read from this file descriptor. - pub reader: c_int, - /// A file descriptor representing the write end of the pipe. Data written - /// to this file descriptor can be read from the `input` file descriptor. - pub writer: c_int, -} - -/// Creates a new low-level OS in-memory pipe. -/// -/// This function can fail to succeed if there are no more resources available -/// to allocate a pipe. -/// -/// This function is also unsafe as there is no destructor associated with the -/// `Pipe` structure will return. If it is not arranged for the returned file -/// descriptors to be closed, the file descriptors will leak. For safe handling -/// of this scenario, use `std::io::PipeStream` instead. -pub unsafe fn pipe() -> IoResult { unimplemented!() } - -/// Returns the proper dll filename for the given basename of a file -/// as a String. -#[cfg(not(target_os="ios"))] -pub fn dll_filename(base: &str) -> String { unimplemented!() } - -/// Optionally returns the filesystem path to the current executable which is -/// running but with the executable name. -/// -/// # Examples -/// -/// ```rust -/// use std::os; -/// -/// match os::self_exe_name() { -/// Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()), -/// None => println!("Unable to get the path of this executable!") -/// }; -/// ``` -pub fn self_exe_name() -> Option { unimplemented!() } - -/// Optionally returns the filesystem path to the current executable which is -/// running. -/// -/// Like self_exe_name() but without the binary's name. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// match os::self_exe_path() { -/// Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()), -/// None => println!("Impossible to fetch the path of this executable.") -/// }; -/// ``` -pub fn self_exe_path() -> Option { unimplemented!() } - -/// Optionally returns the path to the current user's home directory if known. -/// -/// # Unix -/// -/// Returns the value of the 'HOME' environment variable if it is set -/// and not equal to the empty string. -/// -/// # Windows -/// -/// Returns the value of the 'HOME' environment variable if it is -/// set and not equal to the empty string. Otherwise, returns the value of the -/// 'USERPROFILE' environment variable if it is set and not equal to the empty -/// string. -/// -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// match os::homedir() { -/// Some(ref p) => println!("{}", p.display()), -/// None => println!("Impossible to get your home dir!") -/// } -/// ``` -pub fn homedir() -> Option { unimplemented!() } - -/** - * Returns the path to a temporary directory. - * - * On Unix, returns the value of the 'TMPDIR' environment variable if it is - * set, otherwise for non-Android it returns '/tmp'. If Android, since there - * is no global temporary folder (it is usually allocated per-app), we return - * '/data/local/tmp'. - * - * On Windows, returns the value of, in order, the 'TMP', 'TEMP', - * 'USERPROFILE' environment variable if any are set and not the empty - * string. Otherwise, tmpdir returns the path to the Windows directory. - */ -pub fn tmpdir() -> Path { unimplemented!() } - -/// -/// Convert a relative path to an absolute path -/// -/// If the given path is relative, return it prepended with the current working -/// directory. If the given path is already an absolute path, return it -/// as is. -/// -/// # Example -/// ```rust -/// use std::os; -/// use std::path::Path; -/// -/// // Assume we're in a path like /home/someuser -/// let rel_path = Path::new(".."); -/// let abs_path = os::make_absolute(&rel_path).unwrap(); -/// println!("The absolute path is {}", abs_path.display()); -/// // Prints "The absolute path is /home" -/// ``` -// NB: this is here rather than in path because it is a form of environment -// querying; what it does depends on the process working directory, not just -// the input paths. -pub fn make_absolute(p: &Path) -> IoResult { unimplemented!() } - -/// Changes the current working directory to the specified path, returning -/// whether the change was completed successfully or not. -/// -/// # Example -/// ```rust -/// use std::os; -/// use std::path::Path; -/// -/// let root = Path::new("/"); -/// assert!(os::change_dir(&root).is_ok()); -/// println!("Successfully changed working directory to {}!", root.display()); -/// ``` -pub fn change_dir(p: &Path) -> IoResult<()> { unimplemented!() } - -/// Returns the platform-specific value of errno -pub fn errno() -> uint { unimplemented!() } - -/// Return the string corresponding to an `errno()` value of `errnum`. -/// -/// # Example -/// ```rust -/// use std::os; -/// -/// // Same as println!("{}", last_os_error()); -/// println!("{}", os::error_string(os::errno() as uint)); -/// ``` -pub fn error_string(errnum: uint) -> String { unimplemented!() } - -/// Get a string representing the platform-dependent last error -pub fn last_os_error() -> String { unimplemented!() } - -static EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT; - -/** - * Sets the process exit code - * - * Sets the exit code returned by the process if all supervised tasks - * terminate successfully (without panicking). If the current root task panics - * and is supervised by the scheduler then any user-specified exit status is - * ignored and the process exits with the default panic status. - * - * Note that this is not synchronized against modifications of other threads. - */ -pub fn set_exit_status(code: int) { unimplemented!() } - -/// Fetches the process's current exit code. This defaults to 0 and can change -/// by calling `set_exit_status`. -pub fn get_exit_status() -> int { unimplemented!() } - -#[cfg(target_os = "macos")] -unsafe fn load_argc_and_argv(argc: int, - argv: *const *const c_char) -> Vec> { unimplemented!() } - -/** - * Returns the command line arguments - * - * Returns a list of the command line arguments. - */ -#[cfg(target_os = "macos")] -fn real_args_as_bytes() -> Vec> { unimplemented!() } - -// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs -// and use underscores in their names - they're most probably -// are considered private and therefore should be avoided -// Here is another way to get arguments using Objective C -// runtime -// -// In general it looks like: -// res = Vec::new() -// let args = [[NSProcessInfo processInfo] arguments] -// for i in range(0, [args count]) -// res.push([args objectAtIndex:i]) -// res -#[cfg(target_os = "ios")] -fn real_args_as_bytes() -> Vec> { unimplemented!() } - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly"))] -fn real_args_as_bytes() -> Vec> { unimplemented!() } - -#[cfg(not(windows))] -fn real_args() -> Vec { unimplemented!() } - -#[cfg(windows)] -fn real_args() -> Vec { unimplemented!() } - -#[cfg(windows)] -fn real_args_as_bytes() -> Vec> { unimplemented!() } - -type LPCWSTR = *const u16; - -#[cfg(windows)] -#[link_name="kernel32"] -extern "system" { - fn GetCommandLineW() -> LPCWSTR; - fn LocalFree(ptr: *mut c_void); -} - -#[cfg(windows)] -#[link_name="shell32"] -extern "system" { - fn CommandLineToArgvW(lpCmdLine: LPCWSTR, - pNumArgs: *mut c_int) -> *mut *mut u16; -} - -/// Returns the arguments which this program was started with (normally passed -/// via the command line). -/// -/// The first element is traditionally the path to the executable, but it can be -/// set to arbitrary text, and it may not even exist, so this property should not -/// be relied upon for security purposes. -/// -/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD. -/// See `String::from_utf8_lossy` for details. -/// # Example -/// -/// ```rust -/// use std::os; -/// -/// // Prints each argument on a separate line -/// for argument in os::args().iter() { -/// println!("{}", argument); -/// } -/// ``` -pub fn args() -> Vec { unimplemented!() } - -/// Returns the arguments which this program was started with (normally passed -/// via the command line) as byte vectors. -pub fn args_as_bytes() -> Vec> { unimplemented!() } - -#[cfg(target_os = "macos")] -extern { - // These functions are in crt_externs.h. - pub fn _NSGetArgc() -> *mut c_int; - pub fn _NSGetArgv() -> *mut *mut *mut c_char; -} - -// Round up `from` to be divisible by `to` -fn round_up(from: uint, to: uint) -> uint { unimplemented!() } - -/// Returns the page size of the current architecture in bytes. -#[cfg(unix)] -pub fn page_size() -> uint { unimplemented!() } - -/// Returns the page size of the current architecture in bytes. -#[cfg(windows)] -pub fn page_size() -> uint { unimplemented!() } - -/// A memory mapped file or chunk of memory. This is a very system-specific -/// interface to the OS's memory mapping facilities (`mmap` on POSIX, -/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at -/// abstracting platform differences, besides in error values returned. Consider -/// yourself warned. -/// -/// The memory map is released (unmapped) when the destructor is run, so don't -/// let it leave scope by accident if you want it to stick around. -pub struct MemoryMap { - data: *mut u8, - len: uint, - kind: MemoryMapKind, -} - -/// Type of memory map -pub enum MemoryMapKind { - /// Virtual memory map. Usually used to change the permissions of a given - /// chunk of memory. Corresponds to `VirtualAlloc` on Windows. - MapFile(*const u8), - /// Virtual memory map. Usually used to change the permissions of a given - /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on - /// Windows. - MapVirtual -} - -/// Options the memory map is created with -pub enum MapOption { - /// The memory should be readable - MapReadable, - /// The memory should be writable - MapWritable, - /// The memory should be executable - MapExecutable, - /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on - /// POSIX. - MapAddr(*const u8), - /// Create a memory mapping for a file with a given fd. - MapFd(c_int), - /// When using `MapFd`, the start of the map is `uint` bytes from the start - /// of the file. - MapOffset(uint), - /// On POSIX, this can be used to specify the default flags passed to - /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`, - /// `MAP_ANON`. This will override both of those. This is platform-specific - /// (the exact values used) and ignored on Windows. - MapNonStandardFlags(c_int), -} - -/// Possible errors when creating a map. -pub enum MapError { - /// ## The following are POSIX-specific - /// - /// fd was not open for reading or, if using `MapWritable`, was not open for - /// writing. - ErrFdNotAvail, - /// fd was not valid - ErrInvalidFd, - /// Either the address given by `MapAddr` or offset given by `MapOffset` was - /// not a multiple of `MemoryMap::granularity` (unaligned to page size). - ErrUnaligned, - /// With `MapFd`, the fd does not support mapping. - ErrNoMapSupport, - /// If using `MapAddr`, the address + `min_len` was outside of the process's - /// address space. If using `MapFd`, the target of the fd didn't have enough - /// resources to fulfill the request. - ErrNoMem, - /// A zero-length map was requested. This is invalid according to - /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html). - /// Not all platforms obey this, but this wrapper does. - ErrZeroLength, - /// Unrecognized error. The inner value is the unrecognized errno. - ErrUnknown(int), - /// ## The following are Windows-specific - /// - /// Unsupported combination of protection flags - /// (`MapReadable`/`MapWritable`/`MapExecutable`). - ErrUnsupProt, - /// When using `MapFd`, `MapOffset` was given (Windows does not support this - /// at all) - ErrUnsupOffset, - /// When using `MapFd`, there was already a mapping to the file. - ErrAlreadyExists, - /// Unrecognized error from `VirtualAlloc`. The inner value is the return - /// value of GetLastError. - ErrVirtualAlloc(uint), - /// Unrecognized error from `CreateFileMapping`. The inner value is the - /// return value of `GetLastError`. - ErrCreateFileMappingW(uint), - /// Unrecognized error from `MapViewOfFile`. The inner value is the return - /// value of `GetLastError`. - ErrMapViewOfFile(uint) -} - -impl fmt::Show for MapError { - fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl Error for MapError { - fn description(&self) -> &str { unimplemented!() } - fn detail(&self) -> Option { unimplemented!() } -} - -impl FromError for Box { - fn from_error(err: MapError) -> Box { unimplemented!() } -} - -#[cfg(unix)] -impl MemoryMap { - /// Create a new mapping with the given `options`, at least `min_len` bytes - /// long. `min_len` must be greater than zero; see the note on - /// `ErrZeroLength`. - pub fn new(min_len: uint, options: &[MapOption]) -> Result { unimplemented!() } - - /// Granularity that the offset or address must be for `MapOffset` and - /// `MapAddr` respectively. - pub fn granularity() -> uint { unimplemented!() } -} - -#[cfg(unix)] -impl Drop for MemoryMap { - /// Unmap the mapping. Panics the task if `munmap` panics. - fn drop(&mut self) { unimplemented!() } -} - -#[cfg(windows)] -impl MemoryMap { - /// Create a new mapping with the given `options`, at least `min_len` bytes long. - pub fn new(min_len: uint, options: &[MapOption]) -> Result { unimplemented!() } - - /// Granularity of MapAddr() and MapOffset() parameter values. - /// This may be greater than the value returned by page_size(). - pub fn granularity() -> uint { unimplemented!() } -} - -#[cfg(windows)] -impl Drop for MemoryMap { - /// Unmap the mapping. Panics the task if any of `VirtualFree`, - /// `UnmapViewOfFile`, or `CloseHandle` fail. - fn drop(&mut self) { unimplemented!() } -} - -impl MemoryMap { - /// Returns the pointer to the memory created or modified by this map. - pub fn data(&self) -> *mut u8 { unimplemented!() } - /// Returns the number of bytes this map applies to. - pub fn len(&self) -> uint { unimplemented!() } - /// Returns the type of mapping this represents. - pub fn kind(&self) -> MemoryMapKind { unimplemented!() } -} - -#[cfg(target_os = "linux")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `linux`. - pub const SYSNAME: &'static str = "linux"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "macos")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `macos`. - pub const SYSNAME: &'static str = "macos"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.dylib`. - pub const DLL_SUFFIX: &'static str = ".dylib"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `dylib`. - pub const DLL_EXTENSION: &'static str = "dylib"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "ios")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `ios`. - pub const SYSNAME: &'static str = "ios"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "freebsd")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `freebsd`. - pub const SYSNAME: &'static str = "freebsd"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "dragonfly")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `dragonfly`. - pub const SYSNAME: &'static str = "dragonfly"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "android")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "unix"; - - /// A string describing the specific operating system in use: in this - /// case, `android`. - pub const SYSNAME: &'static str = "android"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, `lib`. - pub const DLL_PREFIX: &'static str = "lib"; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.so`. - pub const DLL_SUFFIX: &'static str = ".so"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `so`. - pub const DLL_EXTENSION: &'static str = "so"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, the empty string. - pub const EXE_SUFFIX: &'static str = ""; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, the empty string. - pub const EXE_EXTENSION: &'static str = ""; -} - -#[cfg(target_os = "windows")] -pub mod consts { - pub use os::arch_consts::ARCH; - - pub const FAMILY: &'static str = "windows"; - - /// A string describing the specific operating system in use: in this - /// case, `windows`. - pub const SYSNAME: &'static str = "windows"; - - /// Specifies the filename prefix used for shared libraries on this - /// platform: in this case, the empty string. - pub const DLL_PREFIX: &'static str = ""; - - /// Specifies the filename suffix used for shared libraries on this - /// platform: in this case, `.dll`. - pub const DLL_SUFFIX: &'static str = ".dll"; - - /// Specifies the file extension used for shared libraries on this - /// platform that goes after the dot: in this case, `dll`. - pub const DLL_EXTENSION: &'static str = "dll"; - - /// Specifies the filename suffix used for executable binaries on this - /// platform: in this case, `.exe`. - pub const EXE_SUFFIX: &'static str = ".exe"; - - /// Specifies the file extension, if any, used for executable binaries - /// on this platform: in this case, `exe`. - pub const EXE_EXTENSION: &'static str = "exe"; -} - -#[cfg(target_arch = "x86")] -mod arch_consts { - pub const ARCH: &'static str = "x86"; -} - -#[cfg(target_arch = "x86_64")] -mod arch_consts { - pub const ARCH: &'static str = "x86_64"; -} - -#[cfg(target_arch = "arm")] -mod arch_consts { - pub const ARCH: &'static str = "arm"; -} - -#[cfg(target_arch = "mips")] -mod arch_consts { - pub const ARCH: &'static str = "mips"; -} - -#[cfg(target_arch = "mipsel")] -mod arch_consts { - pub const ARCH: &'static str = "mipsel"; -} diff --git a/src/libst2/path/mod.rs b/src/libst2/path/mod.rs deleted file mode 100644 index 6ee6d3ef79b0d..0000000000000 --- a/src/libst2/path/mod.rs +++ /dev/null @@ -1,780 +0,0 @@ -// Copyright 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. - -/*! - -Cross-platform path support - -This module implements support for two flavors of paths. `PosixPath` represents -a path on any unix-like system, whereas `WindowsPath` represents a path on -Windows. This module also exposes a typedef `Path` which is equal to the -appropriate platform-specific path variant. - -Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which -contains the set of methods that behave the same for both paths. They each also -implement some methods that could not be expressed in `GenericPath`, yet behave -identically for both path flavors, such as `.components()`. - -The three main design goals of this module are 1) to avoid unnecessary -allocation, 2) to behave the same regardless of which flavor of path is being -used, and 3) to support paths that cannot be represented in UTF-8 (as Linux has -no restriction on paths beyond disallowing NUL). - -## Usage - -Usage of this module is fairly straightforward. Unless writing platform-specific -code, `Path` should be used to refer to the platform-native path. - -Creation of a path is typically done with either `Path::new(some_str)` or -`Path::new(some_vec)`. This path can be modified with `.push()` and -`.pop()` (and other setters). The resulting Path can either be passed to another -API that expects a path, or can be turned into a `&[u8]` with `.as_vec()` or a -`Option<&str>` with `.as_str()`. Similarly, attributes of the path can be queried -with methods such as `.filename()`. There are also methods that return a new -path instead of modifying the receiver, such as `.join()` or `.dir_path()`. - -Paths are always kept in normalized form. This means that creating the path -`Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt -to mutate the path will always leave it in normalized form. - -When rendering a path to some form of output, there is a method `.display()` -which is compatible with the `format!()` parameter `{}`. This will render the -path as a string, replacing all non-utf8 sequences with the Replacement -Character (U+FFFD). As such it is not suitable for passing to any API that -actually operates on the path; it is only intended for display. - -## Example - -```rust -use std::io::fs::PathExtensions; - -let mut path = Path::new("/tmp/path"); -println!("path: {}", path.display()); -path.set_filename("foo"); -path.push("bar"); -println!("new path: {}", path.display()); -println!("path exists: {}", path.exists()); -``` - -*/ - -#![experimental] - -use core::kinds::Sized; -use c_str::CString; -use clone::Clone; -use fmt; -use iter::Iterator; -use option::{Option, None, Some}; -use str; -use str::{MaybeOwned, Str, StrPrelude}; -use string::String; -use slice::{AsSlice, CloneSliceAllocPrelude}; -use slice::{PartialEqSlicePrelude, SlicePrelude}; -use vec::Vec; - -/// Typedef for POSIX file paths. -/// See `posix::Path` for more info. -pub use self::posix::Path as PosixPath; - -/// Typedef for Windows file paths. -/// See `windows::Path` for more info. -pub use self::windows::Path as WindowsPath; - -/// Typedef for the platform-native path type -#[cfg(unix)] -pub use self::posix::Path as Path; -/// Typedef for the platform-native path type -#[cfg(windows)] -pub use self::windows::Path as Path; - -/// Typedef for the platform-native component iterator -#[cfg(unix)] -pub use self::posix::Components as Components; -/// Typedef for the platform-native component iterator -#[cfg(windows)] -pub use self::windows::Components as Components; - -/// Typedef for the platform-native str component iterator -#[cfg(unix)] -pub use self::posix::StrComponents as StrComponents; -/// Typedef for the platform-native str component iterator -#[cfg(windows)] -pub use self::windows::StrComponents as StrComponents; - -/// Alias for the platform-native separator character. -#[cfg(unix)] -pub use self::posix::SEP as SEP; -/// Alias for the platform-native separator character. -#[cfg(windows)] -pub use self::windows::SEP as SEP; - -/// Alias for the platform-native separator byte. -#[cfg(unix)] -pub use self::posix::SEP_BYTE as SEP_BYTE; -/// Alias for the platform-native separator byte. -#[cfg(windows)] -pub use self::windows::SEP_BYTE as SEP_BYTE; - -/// Typedef for the platform-native separator char func -#[cfg(unix)] -pub use self::posix::is_sep as is_sep; -/// Typedef for the platform-native separator char func -#[cfg(windows)] -pub use self::windows::is_sep as is_sep; -/// Typedef for the platform-native separator byte func -#[cfg(unix)] -pub use self::posix::is_sep_byte as is_sep_byte; -/// Typedef for the platform-native separator byte func -#[cfg(windows)] -pub use self::windows::is_sep_byte as is_sep_byte; - -pub mod posix; -pub mod windows; - -/// A trait that represents the generic operations available on paths -pub trait GenericPath: Clone + GenericPathUnsafe { - /// Creates a new Path from a byte vector or string. - /// The resulting Path will always be normalized. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let path = Path::new("foo/bar"); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - /// - /// See individual Path impls for additional restrictions. - #[inline] - fn new(path: T) -> Self { unimplemented!() } - - /// Creates a new Path from a byte vector or string, if possible. - /// The resulting Path will always be normalized. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let x: &[u8] = b"foo\0"; - /// assert!(Path::new_opt(x).is_none()); - /// # } - /// ``` - #[inline] - fn new_opt(path: T) -> Option { unimplemented!() } - - /// Returns the path as a string, if possible. - /// If the path is not representable in utf-8, this returns None. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def"); - /// assert_eq!(p.as_str(), Some("/abc/def")); - /// # } - /// ``` - #[inline] - fn as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// Returns the path as a byte vector - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert_eq!(p.as_vec(), b"abc/def"); - /// # } - /// ``` - fn as_vec<'a>(&'a self) -> &'a [u8]; - - /// Converts the Path into an owned byte vector - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert_eq!(p.into_vec(), b"abc/def".to_vec()); - /// // attempting to use p now results in "error: use of moved value" - /// # } - /// ``` - fn into_vec(self) -> Vec; - - /// Returns an object that implements `Show` for printing paths - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// println!("{}", p.display()); // prints "abc/def" - /// # } - /// ``` - fn display<'a>(&'a self) -> Display<'a, Self> { unimplemented!() } - - /// Returns an object that implements `Show` for printing filenames - /// - /// If there is no filename, nothing will be printed. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// println!("{}", p.filename_display()); // prints "def" - /// # } - /// ``` - fn filename_display<'a>(&'a self) -> Display<'a, Self> { unimplemented!() } - - /// Returns the directory component of `self`, as a byte vector (with no trailing separator). - /// If `self` has no directory component, returns ['.']. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.dirname(), b"abc/def"); - /// # } - /// ``` - fn dirname<'a>(&'a self) -> &'a [u8]; - - /// Returns the directory component of `self`, as a string, if possible. - /// See `dirname` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.dirname_str(), Some("abc/def")); - /// # } - /// ``` - #[inline] - fn dirname_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// Returns the file component of `self`, as a byte vector. - /// If `self` represents the root of the file hierarchy, returns None. - /// If `self` is "." or "..", returns None. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.filename(), Some(b"ghi")); - /// # } - /// ``` - fn filename<'a>(&'a self) -> Option<&'a [u8]>; - - /// Returns the file component of `self`, as a string, if possible. - /// See `filename` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert_eq!(p.filename_str(), Some("ghi")); - /// # } - /// ``` - #[inline] - fn filename_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// Returns the stem of the filename of `self`, as a byte vector. - /// The stem is the portion of the filename just before the last '.'. - /// If there is no '.', the entire filename is returned. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def.txt"); - /// assert_eq!(p.filestem(), Some(b"def")); - /// # } - /// ``` - fn filestem<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } - - /// Returns the stem of the filename of `self`, as a string, if possible. - /// See `filestem` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def.txt"); - /// assert_eq!(p.filestem_str(), Some("def")); - /// # } - /// ``` - #[inline] - fn filestem_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// Returns the extension of the filename of `self`, as an optional byte vector. - /// The extension is the portion of the filename just after the last '.'. - /// If there is no extension, None is returned. - /// If the filename ends in '.', the empty vector is returned. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def.txt"); - /// assert_eq!(p.extension(), Some(b"txt")); - /// # } - /// ``` - fn extension<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } - - /// Returns the extension of the filename of `self`, as a string, if possible. - /// See `extension` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def.txt"); - /// assert_eq!(p.extension_str(), Some("txt")); - /// # } - /// ``` - #[inline] - fn extension_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// Replaces the filename portion of the path with the given byte vector or string. - /// If the replacement name is [], this is equivalent to popping the path. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// p.set_filename("foo.dat"); - /// assert!(p == Path::new("abc/foo.dat")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the filename contains a NUL. - #[inline] - fn set_filename(&mut self, filename: T) { unimplemented!() } - - /// Replaces the extension with the given byte vector or string. - /// If there is no extension in `self`, this adds one. - /// If the argument is [] or "", this removes the extension. - /// If `self` has no filename, this is a no-op. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// p.set_extension("csv"); - /// assert!(p == Path::new("abc/def.csv")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the extension contains a NUL. - fn set_extension(&mut self, extension: T) { unimplemented!() } - - /// Returns a new Path constructed by replacing the filename with the given - /// byte vector or string. - /// See `set_filename` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// assert!(p.with_filename("foo.dat") == Path::new("abc/foo.dat")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the filename contains a NUL. - #[inline] - fn with_filename(&self, filename: T) -> Self { unimplemented!() } - - /// Returns a new Path constructed by setting the extension to the given - /// byte vector or string. - /// See `set_extension` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("abc/def.txt"); - /// assert!(p.with_extension("csv") == Path::new("abc/def.csv")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the extension contains a NUL. - #[inline] - fn with_extension(&self, extension: T) -> Self { unimplemented!() } - - /// Returns the directory component of `self`, as a Path. - /// If `self` represents the root of the filesystem hierarchy, returns `self`. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def/ghi"); - /// assert!(p.dir_path() == Path::new("abc/def")); - /// # } - /// ``` - fn dir_path(&self) -> Self { unimplemented!() } - - /// Returns a Path that represents the filesystem root that `self` is rooted in. - /// - /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// assert!(Path::new("abc/def").root_path() == None); - /// assert!(Path::new("/abc/def").root_path() == Some(Path::new("/"))); - /// # } - /// ``` - fn root_path(&self) -> Option; - - /// Pushes a path (as a byte vector or string) onto `self`. - /// If the argument represents an absolute path, it replaces `self`. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo/bar"); - /// p.push("baz.txt"); - /// assert!(p == Path::new("foo/bar/baz.txt")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - #[inline] - fn push(&mut self, path: T) { unimplemented!() } - - /// Pushes multiple paths (as byte vectors or strings) onto `self`. - /// See `push` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo"); - /// p.push_many(&["bar", "baz.txt"]); - /// assert!(p == Path::new("foo/bar/baz.txt")); - /// # } - /// ``` - #[inline] - fn push_many(&mut self, paths: &[T]) { unimplemented!() } - - /// Removes the last path component from the receiver. - /// Returns `true` if the receiver was modified, or `false` if it already - /// represented the root of the file hierarchy. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let mut p = Path::new("foo/bar/baz.txt"); - /// p.pop(); - /// assert!(p == Path::new("foo/bar")); - /// # } - /// ``` - fn pop(&mut self) -> bool; - - /// Returns a new Path constructed by joining `self` with the given path - /// (as a byte vector or string). - /// If the given path is absolute, the new Path will represent just that. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/foo"); - /// assert!(p.join("bar.txt") == Path::new("/foo/bar.txt")); - /// # } - /// ``` - /// - /// # Panics - /// - /// Panics the task if the path contains a NUL. - #[inline] - fn join(&self, path: T) -> Self { unimplemented!() } - - /// Returns a new Path constructed by joining `self` with the given paths - /// (as byte vectors or strings). - /// See `join` for details. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo"); - /// let fbbq = Path::new("foo/bar/baz/quux.txt"); - /// assert!(p.join_many(&["bar", "baz", "quux.txt"]) == fbbq); - /// # } - /// ``` - #[inline] - fn join_many(&self, paths: &[T]) -> Self { unimplemented!() } - - /// Returns whether `self` represents an absolute path. - /// An absolute path is defined as one that, when joined to another path, will - /// yield back the same absolute path. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("/abc/def"); - /// assert!(p.is_absolute()); - /// # } - /// ``` - fn is_absolute(&self) -> bool; - - /// Returns whether `self` represents a relative path. - /// Typically this is the inverse of `is_absolute`. - /// But for Windows paths, it also means the path is not volume-relative or - /// relative to the current working directory. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("abc/def"); - /// assert!(p.is_relative()); - /// # } - /// ``` - fn is_relative(&self) -> bool { unimplemented!() } - - /// Returns whether `self` is equal to, or is an ancestor of, the given path. - /// If both paths are relative, they are compared as though they are relative - /// to the same parent path. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let fb = Path::new("foo/bar"); - /// let bq = Path::new("baz/quux.txt"); - /// assert!(fb.is_ancestor_of(&p)); - /// # } - /// ``` - fn is_ancestor_of(&self, other: &Self) -> bool; - - /// Returns the Path that, were it joined to `base`, would yield `self`. - /// If no such path exists, None is returned. - /// If `self` is absolute and `base` is relative, or on Windows if both - /// paths refer to separate drives, an absolute path is returned. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let fb = Path::new("foo/bar"); - /// let bq = Path::new("baz/quux.txt"); - /// assert!(p.path_relative_from(&fb) == Some(bq)); - /// # } - /// ``` - fn path_relative_from(&self, base: &Self) -> Option; - - /// Returns whether the relative path `child` is a suffix of `self`. - /// - /// # Example - /// - /// ``` - /// # foo(); - /// # #[cfg(windows)] fn foo() {} - /// # #[cfg(unix)] fn foo() { - /// let p = Path::new("foo/bar/baz/quux.txt"); - /// let bq = Path::new("baz/quux.txt"); - /// assert!(p.ends_with_path(&bq)); - /// # } - /// ``` - fn ends_with_path(&self, child: &Self) -> bool; -} - -/// A trait that represents something bytes-like (e.g. a &[u8] or a &str) -pub trait BytesContainer for Sized? { - /// Returns a &[u8] representing the receiver - fn container_as_bytes<'a>(&'a self) -> &'a [u8]; - /// Returns the receiver interpreted as a utf-8 string, if possible - #[inline] - fn container_as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - /// Returns whether .container_as_str() is guaranteed to not fail - // FIXME (#8888): Remove unused arg once :: works - #[inline] - fn is_str(_: Option<&Self>) -> bool { unimplemented!() } -} - -/// A trait that represents the unsafe operations on GenericPaths -pub trait GenericPathUnsafe { - /// Creates a new Path without checking for null bytes. - /// The resulting Path will always be normalized. - unsafe fn new_unchecked(path: T) -> Self; - - /// Replaces the filename portion of the path without checking for null - /// bytes. - /// See `set_filename` for details. - unsafe fn set_filename_unchecked(&mut self, filename: T); - - /// Pushes a path onto `self` without checking for null bytes. - /// See `push` for details. - unsafe fn push_unchecked(&mut self, path: T); -} - -/// Helper struct for printing paths with format!() -pub struct Display<'a, P:'a> { - path: &'a P, - filename: bool -} - -impl<'a, P: GenericPath> fmt::Show for Display<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unimplemented!() } -} - -impl<'a, P: GenericPath> Display<'a, P> { - /// Returns the path as a possibly-owned string. - /// - /// If the path is not UTF-8, invalid sequences will be replaced with the - /// Unicode replacement char. This involves allocation. - #[inline] - pub fn as_maybe_owned(&self) -> MaybeOwned<'a> { unimplemented!() } -} - -impl BytesContainer for str { - #[inline] - fn container_as_bytes(&self) -> &[u8] { unimplemented!() } - #[inline] - fn container_as_str(&self) -> Option<&str> { unimplemented!() } - #[inline] - fn is_str(_: Option<&str>) -> bool { unimplemented!() } -} - -impl BytesContainer for String { - #[inline] - fn container_as_bytes(&self) -> &[u8] { unimplemented!() } - #[inline] - fn container_as_str(&self) -> Option<&str> { unimplemented!() } - #[inline] - fn is_str(_: Option<&String>) -> bool { unimplemented!() } -} - -impl BytesContainer for [u8] { - #[inline] - fn container_as_bytes(&self) -> &[u8] { unimplemented!() } -} - -impl BytesContainer for Vec { - #[inline] - fn container_as_bytes(&self) -> &[u8] { unimplemented!() } -} - -impl BytesContainer for CString { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } -} - -impl<'a> BytesContainer for str::MaybeOwned<'a> { - #[inline] - fn container_as_bytes<'b>(&'b self) -> &'b [u8] { unimplemented!() } - #[inline] - fn container_as_str<'b>(&'b self) -> Option<&'b str> { unimplemented!() } - #[inline] - fn is_str(_: Option<&str::MaybeOwned>) -> bool { unimplemented!() } -} - -impl<'a, Sized? T: BytesContainer> BytesContainer for &'a T { - #[inline] - fn container_as_bytes(&self) -> &[u8] { unimplemented!() } - #[inline] - fn container_as_str(&self) -> Option<&str> { unimplemented!() } - #[inline] - fn is_str(_: Option<& &'a T>) -> bool { unimplemented!() } -} - -#[inline(always)] -fn contains_nul(v: &T) -> bool { unimplemented!() } diff --git a/src/libst2/path/posix.rs b/src/libst2/path/posix.rs deleted file mode 100644 index d364b196027e9..0000000000000 --- a/src/libst2/path/posix.rs +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2013-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. - -//! POSIX file path handling - -use c_str::{CString, ToCStr}; -use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use hash; -use io::Writer; -use iter::{DoubleEndedIterator, AdditiveIterator, Extend, Iterator, Map}; -use kinds::Sized; -use option::{Option, None, Some}; -use str::{FromStr, Str}; -use str; -use slice::{CloneSliceAllocPrelude, Splits, AsSlice, VectorVector, - PartialEqSlicePrelude, SlicePrelude}; -use vec::Vec; - -use super::{BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = Splits<'a, u8>; - -/// Iterator that yields successive components of a Path as Option<&str> -pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>, - Components<'a>>; - -/// Represents a POSIX file path -#[deriving(Clone)] -pub struct Path { - repr: Vec, // assumed to never be empty or contain NULs - sepidx: Option // index of the final separator in repr -} - -/// The standard path separator character -pub const SEP: char = '/'; - -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// Returns whether the given byte is a path separator -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { unimplemented!() } - -/// Returns whether the given char is a path separator -#[inline] -pub fn is_sep(c: char) -> bool { unimplemented!() } - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { unimplemented!() } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { unimplemented!() } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { unimplemented!() } -} - -impl FromStr for Path { - fn from_str(s: &str) -> Option { unimplemented!() } -} - -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { unimplemented!() } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { unimplemented!() } -} - -impl hash::Hash for Path { - #[inline] - fn hash(&self, state: &mut S) { unimplemented!() } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } -} - -impl GenericPathUnsafe for Path { - unsafe fn new_unchecked(path: T) -> Path { unimplemented!() } - - unsafe fn set_filename_unchecked(&mut self, filename: T) { unimplemented!() } - - unsafe fn push_unchecked(&mut self, path: T) { unimplemented!() } -} - -impl GenericPath for Path { - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - fn into_vec(self) -> Vec { unimplemented!() } - - fn dirname<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - fn filename<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } - - fn pop(&mut self) -> bool { unimplemented!() } - - fn root_path(&self) -> Option { unimplemented!() } - - #[inline] - fn is_absolute(&self) -> bool { unimplemented!() } - - fn is_ancestor_of(&self, other: &Path) -> bool { unimplemented!() } - - fn path_relative_from(&self, base: &Path) -> Option { unimplemented!() } - - fn ends_with_path(&self, child: &Path) -> bool { unimplemented!() } -} - -impl Path { - /// Returns a new Path from a byte vector or string - /// - /// # Panics - /// - /// Panics the task if the vector contains a NUL. - #[inline] - pub fn new(path: T) -> Path { unimplemented!() } - - /// Returns a new Path from a byte vector or string, if possible - #[inline] - pub fn new_opt(path: T) -> Option { unimplemented!() } - - /// Returns a normalized byte vector representation of a path, by removing all empty - /// components, and unnecessary . and .. components. - fn normalize>(v: &V) -> Vec { unimplemented!() } - - /// Returns an iterator that yields each component of the path in turn. - /// Does not distinguish between absolute and relative paths, e.g. - /// /a/b/c and a/b/c yield the same set of components. - /// A path of "/" yields no components. A path of "." yields one component. - pub fn components<'a>(&'a self) -> Components<'a> { unimplemented!() } - - /// Returns an iterator that yields each component of the path as Option<&str>. - /// See components() for details. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { unimplemented!() } -} - -// None result means the byte vector didn't need normalizing -fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option> { unimplemented!() } - -#[allow(non_upper_case_globals)] -static dot_static: &'static [u8] = b"."; -#[allow(non_upper_case_globals)] -static dot_dot_static: &'static [u8] = b".."; diff --git a/src/libst2/path/windows.rs b/src/libst2/path/windows.rs deleted file mode 100644 index 1bd3b9a0b207e..0000000000000 --- a/src/libst2/path/windows.rs +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright 2013-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. -// -// ignore-lexer-test FIXME #15883 - -//! Windows file path handling - -pub use self::PathPrefix::*; - -use ascii::AsciiCast; -use c_str::{CString, ToCStr}; -use clone::Clone; -use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; -use hash; -use io::Writer; -use iter::{AdditiveIterator, DoubleEndedIterator, Extend, Iterator, Map}; -use mem; -use option::{Option, Some, None}; -use slice::{AsSlice, SlicePrelude}; -use str::{CharSplits, FromStr, Str, StrAllocating, StrVector, StrPrelude}; -use string::String; -use unicode::char::UnicodeChar; -use vec::Vec; - -use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe}; - -/// Iterator that yields successive components of a Path as &str -/// -/// Each component is yielded as Option<&str> for compatibility with PosixPath, but -/// every component in WindowsPath is guaranteed to be Some. -pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>, - CharSplits<'a, char>>; - -/// Iterator that yields successive components of a Path as &[u8] -pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8], - StrComponents<'a>>; - -/// Represents a Windows path -// Notes for Windows path impl: -// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs -// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information -// about windows paths. -// That same page puts a bunch of restrictions on allowed characters in a path. -// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here -// as `∃P | P.join("\foo.txt") != "\foo.txt"`. -// `C:` is interesting, that means "the current directory on drive C". -// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be -// ignored for now, though, and only added in a hypothetical .to_pwstr() function. -// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the -// processing of "." and ".." components and / as a separator. -// Experimentally, \\?\foo is not the same thing as \foo. -// Also, \\foo is not valid either (certainly not equivalent to \foo). -// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent -// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be -// best to just ignore that and normalize it to C:\foo\bar. -// -// Based on all this, I think the right approach is to do the following: -// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible -// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure). -// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly. -// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing -// server\share. -// * If \\?\, parse disk from following component, if present. Don't error for missing disk. -// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled -// here, they probably aren't, but I'm not going to worry about that. -// * Else if starts with \\, treat following two components as server\share. Don't error for missing -// server\share. -// * Otherwise, attempt to parse drive from start of path. -// -// The only error condition imposed here is valid utf-8. All other invalid paths are simply -// preserved by the data structure; let the Windows API error out on them. -#[deriving(Clone)] -pub struct Path { - repr: String, // assumed to never be empty - prefix: Option, - sepidx: Option // index of the final separator in the non-prefix portion of repr -} - -impl PartialEq for Path { - #[inline] - fn eq(&self, other: &Path) -> bool { unimplemented!() } -} - -impl Eq for Path {} - -impl PartialOrd for Path { - fn partial_cmp(&self, other: &Path) -> Option { unimplemented!() } -} - -impl Ord for Path { - fn cmp(&self, other: &Path) -> Ordering { unimplemented!() } -} - -impl FromStr for Path { - fn from_str(s: &str) -> Option { unimplemented!() } -} - -// FIXME (#12938): Until DST lands, we cannot decompose &str into & and str, so -// we cannot usefully take ToCStr arguments by reference (without forcing an -// additional & around &str). So we are instead temporarily adding an instance -// for &Path, so that we can take ToCStr as owned. When DST lands, the &Path -// instance should be removed, and arguments bound by ToCStr should be passed by -// reference. - -impl ToCStr for Path { - #[inline] - fn to_c_str(&self) -> CString { unimplemented!() } - - #[inline] - unsafe fn to_c_str_unchecked(&self) -> CString { unimplemented!() } -} - -impl hash::Hash for Path { - #[cfg(not(test))] - #[inline] - fn hash(&self, state: &mut S) { unimplemented!() } - - #[cfg(test)] - #[inline] - fn hash(&self, _: &mut S) { unimplemented!() } -} - -impl BytesContainer for Path { - #[inline] - fn container_as_bytes<'a>(&'a self) -> &'a [u8] { unimplemented!() } - #[inline] - fn container_as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - #[inline] - fn is_str(_: Option<&Path>) -> bool { unimplemented!() } -} - -impl GenericPathUnsafe for Path { - /// See `GenericPathUnsafe::from_vec_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - #[inline] - unsafe fn new_unchecked(path: T) -> Path { unimplemented!() } - - /// See `GenericPathUnsafe::set_filename_unchecked`. - /// - /// # Panics - /// - /// Panics if not valid UTF-8. - unsafe fn set_filename_unchecked(&mut self, filename: T) { unimplemented!() } - - /// See `GenericPathUnsafe::push_unchecked`. - /// - /// Concatenating two Windows Paths is rather complicated. - /// For the most part, it will behave as expected, except in the case of - /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no - /// concept of per-volume cwds like Windows does, we can't behave exactly - /// like Windows will. Instead, if the receiver is an absolute path on - /// the same volume as the new path, it will be treated as the cwd that - /// the new path is relative to. Otherwise, the new path will be treated - /// as if it were absolute and will replace the receiver outright. - unsafe fn push_unchecked(&mut self, path: T) { unimplemented!() } -} - -impl GenericPath for Path { - #[inline] - fn new_opt(path: T) -> Option { unimplemented!() } - - /// See `GenericPath::as_str` for info. - /// Always returns a `Some` value. - #[inline] - fn as_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - #[inline] - fn as_vec<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - #[inline] - fn into_vec(self) -> Vec { unimplemented!() } - - #[inline] - fn dirname<'a>(&'a self) -> &'a [u8] { unimplemented!() } - - /// See `GenericPath::dirname_str` for info. - /// Always returns a `Some` value. - fn dirname_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - #[inline] - fn filename<'a>(&'a self) -> Option<&'a [u8]> { unimplemented!() } - - /// See `GenericPath::filename_str` for info. - /// Always returns a `Some` value if `filename` returns a `Some` value. - fn filename_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - /// See `GenericPath::filestem_str` for info. - /// Always returns a `Some` value if `filestem` returns a `Some` value. - #[inline] - fn filestem_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - #[inline] - fn extension_str<'a>(&'a self) -> Option<&'a str> { unimplemented!() } - - fn dir_path(&self) -> Path { unimplemented!() } - - #[inline] - fn pop(&mut self) -> bool { unimplemented!() } - - fn root_path(&self) -> Option { unimplemented!() } - - /// See `GenericPath::is_absolute` for info. - /// - /// A Windows Path is considered absolute only if it has a non-volume prefix, - /// or if it has a volume prefix and the path starts with '\'. - /// A path of `\foo` is not considered absolute because it's actually - /// relative to the "current volume". A separate method `Path::is_vol_relative` - /// is provided to indicate this case. Similarly a path of `C:foo` is not - /// considered absolute because it's relative to the cwd on volume C:. A - /// separate method `Path::is_cwd_relative` is provided to indicate this case. - #[inline] - fn is_absolute(&self) -> bool { unimplemented!() } - - #[inline] - fn is_relative(&self) -> bool { unimplemented!() } - - fn is_ancestor_of(&self, other: &Path) -> bool { unimplemented!() } - - fn path_relative_from(&self, base: &Path) -> Option { unimplemented!() } - - fn ends_with_path(&self, child: &Path) -> bool { unimplemented!() } -} - -impl Path { - /// Returns a new `Path` from a `BytesContainer`. - /// - /// # Panics - /// - /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Example - /// - /// ``` - /// println!("{}", Path::new(r"C:\some\path").display()); - /// ``` - #[inline] - pub fn new(path: T) -> Path { unimplemented!() } - - /// Returns a new `Some(Path)` from a `BytesContainer`. - /// - /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8. - /// - /// # Example - /// - /// ``` - /// let path = Path::new_opt(r"C:\some\path"); - /// - /// match path { - /// Some(path) => println!("{}", path.display()), - /// None => println!("There was a problem with your path."), - /// } - /// ``` - #[inline] - pub fn new_opt(path: T) -> Option { unimplemented!() } - - /// Returns an iterator that yields each component of the path in turn as a Option<&str>. - /// Every component is guaranteed to be Some. - /// Does not yield the path prefix (including server/share components in UNC paths). - /// Does not distinguish between volume-relative and relative paths, e.g. - /// \a\b\c and a\b\c. - /// Does not distinguish between absolute and cwd-relative paths, e.g. - /// C:\foo and C:foo. - pub fn str_components<'a>(&'a self) -> StrComponents<'a> { unimplemented!() } - - /// Returns an iterator that yields each component of the path in turn as a &[u8]. - /// See str_components() for details. - pub fn components<'a>(&'a self) -> Components<'a> { unimplemented!() } - - fn equiv_prefix(&self, other: &Path) -> bool { unimplemented!() } - - fn normalize_(s: S) -> (Option, String) { unimplemented!() } - - fn normalize__(s: &str, prefix: Option) -> Option { unimplemented!() } - - fn update_sepidx(&mut self) { unimplemented!() } - - fn prefix_len(&self) -> uint { unimplemented!() } - - // Returns a tuple (before, after, end) where before is the index of the separator - // and after is the index just after the separator. - // end is the length of the string, normally, or the index of the final character if it is - // a non-semantic trailing separator in a verbatim string. - // If the prefix is considered the separator, before and after are the same. - fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> { unimplemented!() } - - fn has_nonsemantic_trailing_slash(&self) -> bool { unimplemented!() } - - fn update_normalized(&mut self, s: S) { unimplemented!() } -} - -/// Returns whether the path is considered "volume-relative", which means a path -/// that looks like "\foo". Paths of this form are relative to the current volume, -/// but absolute within that volume. -#[inline] -pub fn is_vol_relative(path: &Path) -> bool { unimplemented!() } - -/// Returns whether the path is considered "cwd-relative", which means a path -/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths -/// of this form are relative to the cwd on the given volume. -#[inline] -pub fn is_cwd_relative(path: &Path) -> bool { unimplemented!() } - -/// Returns the PathPrefix for this Path -#[inline] -pub fn prefix(path: &Path) -> Option { unimplemented!() } - -/// Returns whether the Path's prefix is a verbatim prefix, i.e. `\\?\` -#[inline] -pub fn is_verbatim(path: &Path) -> bool { unimplemented!() } - -/// Returns the non-verbatim equivalent of the input path, if possible. -/// If the input path is a device namespace path, None is returned. -/// If the input path is not verbatim, it is returned as-is. -/// If the input path is verbatim, but the same path can be expressed as -/// non-verbatim, the non-verbatim version is returned. -/// Otherwise, None is returned. -pub fn make_non_verbatim(path: &Path) -> Option { unimplemented!() } - -/// The standard path separator character -pub const SEP: char = '\\'; -/// The standard path separator byte -pub const SEP_BYTE: u8 = SEP as u8; - -/// The alternative path separator character -pub const SEP2: char = '/'; -/// The alternative path separator character -pub const SEP2_BYTE: u8 = SEP2 as u8; - -/// Returns whether the given char is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep(c: char) -> bool { unimplemented!() } - -/// Returns whether the given char is a path separator. -/// Only allows the primary separator '\'; use is_sep to allow '/'. -#[inline] -pub fn is_sep_verbatim(c: char) -> bool { unimplemented!() } - -/// Returns whether the given byte is a path separator. -/// Allows both the primary separator '\' and the alternative separator '/'. -#[inline] -pub fn is_sep_byte(u: &u8) -> bool { unimplemented!() } - -/// Returns whether the given byte is a path separator. -/// Only allows the primary separator '\'; use is_sep_byte to allow '/'. -#[inline] -pub fn is_sep_byte_verbatim(u: &u8) -> bool { unimplemented!() } - -/// Prefix types for Path -#[deriving(PartialEq, Clone, Show)] -pub enum PathPrefix { - /// Prefix `\\?\`, uint is the length of the following component - VerbatimPrefix(uint), - /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components - VerbatimUNCPrefix(uint, uint), - /// Prefix `\\?\C:\` (for any alphabetic character) - VerbatimDiskPrefix, - /// Prefix `\\.\`, uint is the length of the following component - DeviceNSPrefix(uint), - /// UNC prefix `\\server\share`, uints are the lengths of the server/share - UNCPrefix(uint, uint), - /// Prefix `C:` for any alphabetic character - DiskPrefix -} - -fn parse_prefix<'a>(mut path: &'a str) -> Option { unimplemented!() } - -// None result means the string didn't need normalizing -fn normalize_helper<'a>(s: &'a str, prefix: Option) -> (bool, Option>) { unimplemented!() } - -fn prefix_is_verbatim(p: Option) -> bool { unimplemented!() } - -fn prefix_len(p: Option) -> uint { unimplemented!() } diff --git a/src/libst2/prelude.rs b/src/libst2/prelude.rs deleted file mode 100644 index 65f45c3f97e14..0000000000000 --- a/src/libst2/prelude.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 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. - -//! The Rust prelude -//! -//! Because `std` is required by most serious Rust software, it is -//! imported at the topmost level of every crate by default, as if the -//! first line of each crate was -//! -//! ```ignore -//! extern crate std; -//! ``` -//! -//! This means that the contents of std can be accessed from any context -//! with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, -//! etc. -//! -//! Additionally, `std` contains a `prelude` module that reexports many of the -//! most common traits, types and functions. The contents of the prelude are -//! imported into every *module* by default. Implicitly, all modules behave as if -//! they contained the following prologue: -//! -//! ```ignore -//! use std::prelude::*; -//! ``` -//! -//! The prelude is primarily concerned with exporting *traits* that are so -//! pervasive that it would be obnoxious to import for every use, particularly -//! those that define methods on primitive types. It does include a few -//! particularly useful standalone functions, like `from_str`, `range`, and -//! `drop`, `spawn`, and `channel`. - -#![experimental] - -// Reexported core operators -#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Sync}; -#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; -#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor}; -#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut}; -#[doc(no_inline)] pub use ops::{Shl, Shr}; -#[doc(no_inline)] pub use ops::{Index, IndexMut}; -#[doc(no_inline)] pub use ops::{Slice, SliceMut}; -#[doc(no_inline)] pub use ops::{Fn, FnMut, FnOnce}; - -// Reexported functions -#[doc(no_inline)] pub use iter::{range, repeat}; -#[doc(no_inline)] pub use mem::drop; -#[doc(no_inline)] pub use str::from_str; - -// Reexported types and traits - -#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; -#[doc(no_inline)] pub use ascii::IntoBytes; -#[doc(no_inline)] pub use c_str::ToCStr; -#[doc(no_inline)] pub use char::{Char, UnicodeChar}; -#[doc(no_inline)] pub use clone::Clone; -#[doc(no_inline)] pub use cmp::{PartialEq, PartialOrd, Eq, Ord}; -#[doc(no_inline)] pub use cmp::{Ordering, Equiv}; -#[doc(no_inline)] pub use cmp::Ordering::{Less, Equal, Greater}; -#[doc(no_inline)] pub use iter::{FromIterator, Extend, ExactSize}; -#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator}; -#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator}; -#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; -#[doc(no_inline)] pub use num::{ToPrimitive, FromPrimitive}; -#[doc(no_inline)] pub use boxed::Box; -#[doc(no_inline)] pub use option::Option; -#[doc(no_inline)] pub use option::Option::{Some, None}; -#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; -#[doc(no_inline)] pub use ptr::{RawPtr, RawMutPtr}; -#[doc(no_inline)] pub use result::Result; -#[doc(no_inline)] pub use result::Result::{Ok, Err}; -#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek, BufferPrelude}; -#[doc(no_inline)] pub use str::{Str, StrVector, StrPrelude}; -#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating, UnicodeStrPrelude}; -#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; -#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; -#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; -#[doc(no_inline)] pub use slice::{SlicePrelude, AsSlice, CloneSlicePrelude}; -#[doc(no_inline)] pub use slice::{VectorVector, PartialEqSlicePrelude, OrdSlicePrelude}; -#[doc(no_inline)] pub use slice::{CloneSliceAllocPrelude, OrdSliceAllocPrelude, SliceAllocPrelude}; -#[doc(no_inline)] pub use string::{IntoString, String, ToString}; -#[doc(no_inline)] pub use vec::Vec; - -// Reexported runtime types -#[doc(no_inline)] pub use comm::{sync_channel, channel}; -#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver}; -#[doc(no_inline)] pub use task::spawn; diff --git a/src/libst2/rand/mod.rs b/src/libst2/rand/mod.rs deleted file mode 100644 index b1e5c7aad0819..0000000000000 --- a/src/libst2/rand/mod.rs +++ /dev/null @@ -1,362 +0,0 @@ -// Copyright 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. - -//! Utilities for random number generation -//! -//! The key functions are `random()` and `Rng::gen()`. These are polymorphic -//! and so can be used to generate any type that implements `Rand`. Type inference -//! means that often a simple call to `rand::random()` or `rng.gen()` will -//! suffice, but sometimes an annotation is required, e.g. `rand::random::()`. -//! -//! See the `distributions` submodule for sampling random numbers from -//! distributions like normal and exponential. -//! -//! # Task-local RNG -//! -//! There is built-in support for a RNG associated with each task stored -//! in task-local storage. This RNG can be accessed via `task_rng`, or -//! used implicitly via `random`. This RNG is normally randomly seeded -//! from an operating-system source of randomness, e.g. `/dev/urandom` on -//! Unix systems, and will automatically reseed itself from this source -//! after generating 32 KiB of random data. -//! -//! # Cryptographic security -//! -//! An application that requires an entropy source for cryptographic purposes -//! must use `OsRng`, which reads randomness from the source that the operating -//! system provides (e.g. `/dev/urandom` on Unixes or `CryptGenRandom()` on Windows). -//! The other random number generators provided by this module are not suitable -//! for such purposes. -//! -//! *Note*: many Unix systems provide `/dev/random` as well as `/dev/urandom`. -//! This module uses `/dev/urandom` for the following reasons: -//! -//! - On Linux, `/dev/random` may block if entropy pool is empty; `/dev/urandom` will not block. -//! This does not mean that `/dev/random` provides better output than -//! `/dev/urandom`; the kernel internally runs a cryptographically secure pseudorandom -//! number generator (CSPRNG) based on entropy pool for random number generation, -//! so the "quality" of `/dev/random` is not better than `/dev/urandom` in most cases. -//! However, this means that `/dev/urandom` can yield somewhat predictable randomness -//! if the entropy pool is very small, such as immediately after first booting. -//! Linux 3,17 added `getrandom(2)` system call which solves the issue: it blocks if entropy -//! pool is not initialized yet, but it does not block once initialized. -//! `OsRng` tries to use `getrandom(2)` if available, and use `/dev/urandom` fallback if not. -//! If an application does not have `getrandom` and likely to be run soon after first booting, -//! or on a system with very few entropy sources, one should consider using `/dev/random` via -//! `ReaderRng`. -//! - On some systems (e.g. FreeBSD, OpenBSD and Mac OS X) there is no difference -//! between the two sources. (Also note that, on some systems e.g. FreeBSD, both `/dev/random` -//! and `/dev/urandom` may block once if the CSPRNG has not seeded yet.) -//! -//! # Examples -//! -//! ```rust -//! use std::rand; -//! use std::rand::Rng; -//! -//! let mut rng = rand::task_rng(); -//! if rng.gen() { // random bool -//! println!("int: {}, uint: {}", rng.gen::(), rng.gen::()) -//! } -//! ``` -//! -//! ```rust -//! use std::rand; -//! -//! let tuple = rand::random::<(f64, char)>(); -//! println!("{}", tuple) -//! ``` -//! -//! ## Monte Carlo estimation of π -//! -//! For this example, imagine we have a square with sides of length 2 and a unit -//! circle, both centered at the origin. Since the area of a unit circle is π, -//! we have: -//! -//! ```notrust -//! (area of unit circle) / (area of square) = π / 4 -//! ``` -//! -//! So if we sample many points randomly from the square, roughly π / 4 of them -//! should be inside the circle. -//! -//! We can use the above fact to estimate the value of π: pick many points in the -//! square at random, calculate the fraction that fall within the circle, and -//! multiply this fraction by 4. -//! -//! ``` -//! use std::rand; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! fn main() { -//! let between = Range::new(-1f64, 1.); -//! let mut rng = rand::task_rng(); -//! -//! let total = 1_000_000u; -//! let mut in_circle = 0u; -//! -//! for _ in range(0u, total) { -//! let a = between.ind_sample(&mut rng); -//! let b = between.ind_sample(&mut rng); -//! if a*a + b*b <= 1. { -//! in_circle += 1; -//! } -//! } -//! -//! // prints something close to 3.14159... -//! println!("{}", 4. * (in_circle as f64) / (total as f64)); -//! } -//! ``` -//! -//! ## Monty Hall Problem -//! -//! This is a simulation of the [Monty Hall Problem][]: -//! -//! > Suppose you're on a game show, and you're given the choice of three doors: -//! > Behind one door is a car; behind the others, goats. You pick a door, say No. 1, -//! > and the host, who knows what's behind the doors, opens another door, say No. 3, -//! > which has a goat. He then says to you, "Do you want to pick door No. 2?" -//! > Is it to your advantage to switch your choice? -//! -//! The rather unintuitive answer is that you will have a 2/3 chance of winning if -//! you switch and a 1/3 chance of winning of you don't, so it's better to switch. -//! -//! This program will simulate the game show and with large enough simulation steps -//! it will indeed confirm that it is better to switch. -//! -//! [Monty Hall Problem]: http://en.wikipedia.org/wiki/Monty_Hall_problem -//! -//! ``` -//! use std::rand; -//! use std::rand::Rng; -//! use std::rand::distributions::{IndependentSample, Range}; -//! -//! struct SimulationResult { -//! win: bool, -//! switch: bool, -//! } -//! -//! // Run a single simulation of the Monty Hall problem. -//! fn simulate(random_door: &Range, rng: &mut R) -> SimulationResult { -//! let car = random_door.ind_sample(rng); -//! -//! // This is our initial choice -//! let mut choice = random_door.ind_sample(rng); -//! -//! // The game host opens a door -//! let open = game_host_open(car, choice, rng); -//! -//! // Shall we switch? -//! let switch = rng.gen(); -//! if switch { -//! choice = switch_door(choice, open); -//! } -//! -//! SimulationResult { win: choice == car, switch: switch } -//! } -//! -//! // Returns the door the game host opens given our choice and knowledge of -//! // where the car is. The game host will never open the door with the car. -//! fn game_host_open(car: uint, choice: uint, rng: &mut R) -> uint { -//! let choices = free_doors(&[car, choice]); -//! rand::sample(rng, choices.into_iter(), 1)[0] -//! } -//! -//! // Returns the door we switch to, given our current choice and -//! // the open door. There will only be one valid door. -//! fn switch_door(choice: uint, open: uint) -> uint { -//! free_doors(&[choice, open])[0] -//! } -//! -//! fn free_doors(blocked: &[uint]) -> Vec { -//! range(0u, 3).filter(|x| !blocked.contains(x)).collect() -//! } -//! -//! fn main() { -//! // The estimation will be more accurate with more simulations -//! let num_simulations = 10000u; -//! -//! let mut rng = rand::task_rng(); -//! let random_door = Range::new(0u, 3); -//! -//! let (mut switch_wins, mut switch_losses) = (0u, 0u); -//! let (mut keep_wins, mut keep_losses) = (0u, 0u); -//! -//! println!("Running {} simulations...", num_simulations); -//! for _ in range(0, num_simulations) { -//! let result = simulate(&random_door, &mut rng); -//! -//! match (result.win, result.switch) { -//! (true, true) => switch_wins += 1, -//! (true, false) => keep_wins += 1, -//! (false, true) => switch_losses += 1, -//! (false, false) => keep_losses += 1, -//! } -//! } -//! -//! let total_switches = switch_wins + switch_losses; -//! let total_keeps = keep_wins + keep_losses; -//! -//! println!("Switched door {} times with {} wins and {} losses", -//! total_switches, switch_wins, switch_losses); -//! -//! println!("Kept our choice {} times with {} wins and {} losses", -//! total_keeps, keep_wins, keep_losses); -//! -//! // With a large number of simulations, the values should converge to -//! // 0.667 and 0.333 respectively. -//! println!("Estimated chance to win if we switch: {}", -//! switch_wins as f32 / total_switches as f32); -//! println!("Estimated chance to win if we don't: {}", -//! keep_wins as f32 / total_keeps as f32); -//! } -//! ``` - -#![experimental] - -use cell::RefCell; -use clone::Clone; -use io::IoResult; -use iter::Iterator; -use mem; -use rc::Rc; -use result::{Ok, Err}; -use vec::Vec; - -#[cfg(not(target_word_size="64"))] -use core_rand::IsaacRng as IsaacWordRng; -#[cfg(target_word_size="64")] -use core_rand::Isaac64Rng as IsaacWordRng; - -pub use core_rand::{Rand, Rng, SeedableRng, Open01, Closed01}; -pub use core_rand::{XorShiftRng, IsaacRng, Isaac64Rng, ChaChaRng}; -pub use core_rand::{distributions, reseeding}; -pub use rand::os::OsRng; - -pub mod os; -pub mod reader; - -/// The standard RNG. This is designed to be efficient on the current -/// platform. -pub struct StdRng { rng: IsaacWordRng } - -impl StdRng { - /// Create a randomly seeded instance of `StdRng`. - /// - /// This is a very expensive operation as it has to read - /// randomness from the operating system and use this in an - /// expensive seeding operation. If one is only generating a small - /// number of random numbers, or doesn't need the utmost speed for - /// generating each number, `task_rng` and/or `random` may be more - /// appropriate. - /// - /// Reading the randomness from the OS may fail, and any error is - /// propagated via the `IoResult` return value. - pub fn new() -> IoResult { unimplemented!() } -} - -impl Rng for StdRng { - #[inline] - fn next_u32(&mut self) -> u32 { unimplemented!() } - - #[inline] - fn next_u64(&mut self) -> u64 { unimplemented!() } -} - -impl<'a> SeedableRng<&'a [uint]> for StdRng { - fn reseed(&mut self, seed: &'a [uint]) { unimplemented!() } - - fn from_seed(seed: &'a [uint]) -> StdRng { unimplemented!() } -} - -/// Create a weak random number generator with a default algorithm and seed. -/// -/// It returns the fastest `Rng` algorithm currently available in Rust without -/// consideration for cryptography or security. If you require a specifically -/// seeded `Rng` for consistency over time you should pick one algorithm and -/// create the `Rng` yourself. -/// -/// This will read randomness from the operating system to seed the -/// generator. -pub fn weak_rng() -> XorShiftRng { unimplemented!() } - -/// Controls how the task-local RNG is reseeded. -struct TaskRngReseeder; - -impl reseeding::Reseeder for TaskRngReseeder { - fn reseed(&mut self, rng: &mut StdRng) { unimplemented!() } -} -static TASK_RNG_RESEED_THRESHOLD: uint = 32_768; -type TaskRngInner = reseeding::ReseedingRng; - -/// The task-local RNG. -pub struct TaskRng { - rng: Rc>, -} - -/// Retrieve the lazily-initialized task-local random number -/// generator, seeded by the system. Intended to be used in method -/// chaining style, e.g. `task_rng().gen::()`. -/// -/// The RNG provided will reseed itself from the operating system -/// after generating a certain amount of randomness. -/// -/// The internal RNG used is platform and architecture dependent, even -/// if the operating system random number generator is rigged to give -/// the same sequence always. If absolute consistency is required, -/// explicitly select an RNG, e.g. `IsaacRng` or `Isaac64Rng`. -pub fn task_rng() -> TaskRng { unimplemented!() } - -impl Rng for TaskRng { - fn next_u32(&mut self) -> u32 { unimplemented!() } - - fn next_u64(&mut self) -> u64 { unimplemented!() } - - #[inline] - fn fill_bytes(&mut self, bytes: &mut [u8]) { unimplemented!() } -} - -/// Generates a random value using the task-local random number generator. -/// -/// `random()` can generate various types of random things, and so may require -/// type hinting to generate the specific type you want. -/// -/// # Examples -/// -/// ```rust -/// use std::rand; -/// -/// let x = rand::random(); -/// println!("{}", 2u * x); -/// -/// let y = rand::random::(); -/// println!("{}", y); -/// -/// if rand::random() { // generates a boolean -/// println!("Better lucky than good!"); -/// } -/// ``` -#[inline] -pub fn random() -> T { unimplemented!() } - -/// Randomly sample up to `amount` elements from an iterator. -/// -/// # Example -/// -/// ```rust -/// use std::rand::{task_rng, sample}; -/// -/// let mut rng = task_rng(); -/// let sample = sample(&mut rng, range(1i, 100), 5); -/// println!("{}", sample); -/// ``` -pub fn sample, R: Rng>(rng: &mut R, - mut iter: I, - amount: uint) -> Vec { unimplemented!() } diff --git a/src/libst2/rand/os.rs b/src/libst2/rand/os.rs deleted file mode 100644 index 2a4d8347c30c9..0000000000000 --- a/src/libst2/rand/os.rs +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright 2013-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. - -//! Interfaces to the operating system provided random number -//! generators. - -pub use self::imp::OsRng; - -#[cfg(all(unix, not(target_os = "ios")))] -mod imp { - extern crate libc; - - use self::OsRngInner::*; - - use io::{IoResult, File}; - use path::Path; - use rand::Rng; - use rand::reader::ReaderRng; - use result::{Ok, Err}; - use slice::SlicePrelude; - use mem; - use os::errno; - - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] - fn getrandom(buf: &mut [u8]) -> libc::c_long { - extern "C" { - fn syscall(number: libc::c_long, ...) -> libc::c_long; - } - - #[cfg(target_arch = "x86_64")] - const NR_GETRANDOM: libc::c_long = 318; - #[cfg(target_arch = "x86")] - const NR_GETRANDOM: libc::c_long = 355; - #[cfg(target_arch = "arm")] - const NR_GETRANDOM: libc::c_long = 384; - - unsafe { - syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u) - } - } - - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] - fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } - - fn getrandom_fill_bytes(v: &mut [u8]) { - let mut read = 0; - let len = v.len(); - while read < len { - let result = getrandom(v[mut read..]); - if result == -1 { - let err = errno() as libc::c_int; - if err == libc::EINTR { - continue; - } else { - panic!("unexpected getrandom error: {}", err); - } - } else { - read += result as uint; - } - } - } - - fn getrandom_next_u32() -> u32 { - let mut buf: [u8, ..4] = [0u8, ..4]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8, ..4], u32>(buf) } - } - - fn getrandom_next_u64() -> u64 { - let mut buf: [u8, ..8] = [0u8, ..8]; - getrandom_fill_bytes(&mut buf); - unsafe { mem::transmute::<[u8, ..8], u64>(buf) } - } - - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))] - fn is_getrandom_available() -> bool { - use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed}; - - static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL; - static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL; - - if !GETRANDOM_CHECKED.load(Relaxed) { - let mut buf: [u8, ..0] = []; - let result = getrandom(&mut buf); - let available = if result == -1 { - let err = errno() as libc::c_int; - err != libc::ENOSYS - } else { - true - }; - GETRANDOM_AVAILABLE.store(available, Relaxed); - GETRANDOM_CHECKED.store(true, Relaxed); - available - } else { - GETRANDOM_AVAILABLE.load(Relaxed) - } - } - - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))] - fn is_getrandom_available() -> bool { false } - - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed - /// This does not block. - pub struct OsRng { - inner: OsRngInner, - } - - enum OsRngInner { - OsGetrandomRng, - OsReaderRng(ReaderRng), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> IoResult { - if is_getrandom_available() { - return Ok(OsRng { inner: OsGetrandomRng }); - } - - let reader = try!(File::open(&Path::new("/dev/urandom"))); - let reader_rng = ReaderRng::new(reader); - - Ok(OsRng { inner: OsReaderRng(reader_rng) }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - match self.inner { - OsGetrandomRng => getrandom_next_u32(), - OsReaderRng(ref mut rng) => rng.next_u32(), - } - } - fn next_u64(&mut self) -> u64 { - match self.inner { - OsGetrandomRng => getrandom_next_u64(), - OsReaderRng(ref mut rng) => rng.next_u64(), - } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - match self.inner { - OsGetrandomRng => getrandom_fill_bytes(v), - OsReaderRng(ref mut rng) => rng.fill_bytes(v) - } - } - } -} - -#[cfg(target_os = "ios")] -mod imp { - extern crate libc; - - use io::{IoResult}; - use kinds::marker; - use mem; - use os; - use rand::Rng; - use result::{Ok}; - use self::libc::{c_int, size_t}; - use slice::{SlicePrelude}; - - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed - /// This does not block. - pub struct OsRng { - marker: marker::NoCopy - } - - #[repr(C)] - struct SecRandom; - - #[allow(non_upper_case_globals)] - static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom; - - #[link(name = "Security", kind = "framework")] - extern "C" { - fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, bytes: *mut u8) -> c_int; - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> IoResult { - Ok(OsRng {marker: marker::NoCopy} ) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0u8, .. 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0u8, .. 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) - }; - if ret == -1 { - panic!("couldn't generate random bytes: {}", os::last_os_error()); - } - } - } -} - -#[cfg(windows)] -mod imp { - extern crate libc; - - use io::{IoResult, IoError}; - use mem; - use ops::Drop; - use os; - use rand::Rng; - use result::{Ok, Err}; - use self::libc::{DWORD, BYTE, LPCSTR, BOOL}; - use self::libc::types::os::arch::extra::{LONG_PTR}; - use slice::{SlicePrelude}; - - type HCRYPTPROV = LONG_PTR; - - /// A random number generator that retrieves randomness straight from - /// the operating system. Platform sources: - /// - /// - Unix-like systems (Linux, Android, Mac OSX): read directly from - /// `/dev/urandom`, or from `getrandom(2)` system call if available. - /// - Windows: calls `CryptGenRandom`, using the default cryptographic - /// service provider with the `PROV_RSA_FULL` type. - /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed - /// This does not block. - pub struct OsRng { - hcryptprov: HCRYPTPROV - } - - static PROV_RSA_FULL: DWORD = 1; - static CRYPT_SILENT: DWORD = 64; - static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; - - #[allow(non_snake_case)] - extern "system" { - fn CryptAcquireContextA(phProv: *mut HCRYPTPROV, - pszContainer: LPCSTR, - pszProvider: LPCSTR, - dwProvType: DWORD, - dwFlags: DWORD) -> BOOL; - fn CryptGenRandom(hProv: HCRYPTPROV, - dwLen: DWORD, - pbBuffer: *mut BYTE) -> BOOL; - fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL; - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> IoResult { - let mut hcp = 0; - let ret = unsafe { - CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR, - PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT) - }; - - if ret == 0 { - Err(IoError::last_error()) - } else { - Ok(OsRng { hcryptprov: hcp }) - } - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0u8, .. 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0u8, .. 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - let ret = unsafe { - CryptGenRandom(self.hcryptprov, v.len() as DWORD, - v.as_mut_ptr()) - }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", os::last_os_error()); - } - } - } - - impl Drop for OsRng { - fn drop(&mut self) { - let ret = unsafe { - CryptReleaseContext(self.hcryptprov, 0) - }; - if ret == 0 { - panic!("couldn't release context: {}", os::last_os_error()); - } - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - - use super::OsRng; - use rand::Rng; - use task; - - #[test] - fn test_os_rng() { - let mut r = OsRng::new().unwrap(); - - r.next_u32(); - r.next_u64(); - - let mut v = [0u8, .. 1000]; - r.fill_bytes(&mut v); - } - - #[test] - fn test_os_rng_tasks() { - - let mut txs = vec!(); - for _ in range(0u, 20) { - let (tx, rx) = channel(); - txs.push(tx); - task::spawn(proc() { - // wait until all the tasks are ready to go. - rx.recv(); - - // deschedule to attempt to interleave things as much - // as possible (XXX: is this a good test?) - let mut r = OsRng::new().unwrap(); - task::deschedule(); - let mut v = [0u8, .. 1000]; - - for _ in range(0u, 100) { - r.next_u32(); - task::deschedule(); - r.next_u64(); - task::deschedule(); - r.fill_bytes(&mut v); - task::deschedule(); - } - }) - } - - // start all the tasks - for tx in txs.iter() { - tx.send(()) - } - } -} diff --git a/src/libst2/rand/reader.rs b/src/libst2/rand/reader.rs deleted file mode 100644 index 796bf7853f73b..0000000000000 --- a/src/libst2/rand/reader.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 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. - -//! A wrapper around any Reader to treat it as an RNG. - -use io::Reader; -use rand::Rng; -use result::{Ok, Err}; -use slice::SlicePrelude; - -/// An RNG that reads random bytes straight from a `Reader`. This will -/// work best with an infinite reader, but this is not required. -/// -/// # Panics -/// -/// It will panic if it there is insufficient data to fulfill a request. -/// -/// # Example -/// -/// ```rust -/// use std::rand::{reader, Rng}; -/// use std::io::MemReader; -/// -/// let mut rng = reader::ReaderRng::new(MemReader::new(vec!(1,2,3,4,5,6,7,8))); -/// println!("{:x}", rng.gen::()); -/// ``` -pub struct ReaderRng { - reader: R -} - -impl ReaderRng { - /// Create a new `ReaderRng` from a `Reader`. - pub fn new(r: R) -> ReaderRng { - ReaderRng { - reader: r - } - } -} - -impl Rng for ReaderRng { - fn next_u32(&mut self) -> u32 { - // This is designed for speed: reading a LE integer on a LE - // platform just involves blitting the bytes into the memory - // of the u32, similarly for BE on BE; avoiding byteswapping. - if cfg!(target_endian="little") { - self.reader.read_le_u32().unwrap() - } else { - self.reader.read_be_u32().unwrap() - } - } - fn next_u64(&mut self) -> u64 { - // see above for explanation. - if cfg!(target_endian="little") { - self.reader.read_le_u64().unwrap() - } else { - self.reader.read_be_u64().unwrap() - } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - if v.len() == 0 { return } - match self.reader.read_at_least(v.len(), v) { - Ok(_) => {} - Err(e) => panic!("ReaderRng.fill_bytes error: {}", e) - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - - use super::ReaderRng; - use io::MemReader; - use num::Int; - use rand::Rng; - - #[test] - fn test_reader_rng_u64() { - // transmute from the target to avoid endianness concerns. - let v = vec![0u8, 0, 0, 0, 0, 0, 0, 1, - 0 , 0, 0, 0, 0, 0, 0, 2, - 0, 0, 0, 0, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); - - assert_eq!(rng.next_u64(), 1_u64.to_be()); - assert_eq!(rng.next_u64(), 2_u64.to_be()); - assert_eq!(rng.next_u64(), 3_u64.to_be()); - } - #[test] - fn test_reader_rng_u32() { - let v = vec![0u8, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3]; - let mut rng = ReaderRng::new(MemReader::new(v)); - - assert_eq!(rng.next_u32(), 1_u32.to_be()); - assert_eq!(rng.next_u32(), 2_u32.to_be()); - assert_eq!(rng.next_u32(), 3_u32.to_be()); - } - #[test] - fn test_reader_rng_fill_bytes() { - let v = [1u8, 2, 3, 4, 5, 6, 7, 8]; - let mut w = [0u8, .. 8]; - - let mut rng = ReaderRng::new(MemReader::new(v.as_slice().to_vec())); - rng.fill_bytes(&mut w); - - assert!(v == w); - } - - #[test] - #[should_fail] - fn test_reader_rng_insufficient_bytes() { - let mut rng = ReaderRng::new(MemReader::new(vec!())); - let mut v = [0u8, .. 3]; - rng.fill_bytes(&mut v); - } -} diff --git a/src/libst2/rt/backtrace.rs b/src/libst2/rt/backtrace.rs deleted file mode 100644 index ad7361fb53e4c..0000000000000 --- a/src/libst2/rt/backtrace.rs +++ /dev/null @@ -1,501 +0,0 @@ -// 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 backtrace functionality (to print on panic) - -#![allow(non_camel_case_types)] - -use io::{IoResult, Writer}; -use iter::Iterator; -use option::{Some, None}; -use os; -use result::{Ok, Err}; -use str::{StrPrelude, from_str}; -use sync::atomic; -use unicode::char::UnicodeChar; - -pub use self::imp::write; - -// For now logging is turned off by default, and this function checks to see -// whether the magical environment variable is present to see if it's turned on. -pub fn log_enabled() -> bool { unimplemented!() } - -#[cfg(target_word_size = "64")] const HEX_WIDTH: uint = 18; -#[cfg(target_word_size = "32")] const HEX_WIDTH: uint = 10; - -// All rust symbols are in theory lists of "::"-separated identifiers. Some -// assemblers, however, can't handle these characters in symbol names. To get -// around this, we use C++-style mangling. The mangling method is: -// -// 1. Prefix the symbol with "_ZN" -// 2. For each element of the path, emit the length plus the element -// 3. End the path with "E" -// -// For example, "_ZN4testE" => "test" and "_ZN3foo3bar" => "foo::bar". -// -// We're the ones printing our backtraces, so we can't rely on anything else to -// demangle our symbols. It's *much* nicer to look at demangled symbols, so -// this function is implemented to give us nice pretty output. -// -// Note that this demangler isn't quite as fancy as it could be. We have lots -// of other information in our symbols like hashes, version, type information, -// etc. Additionally, this doesn't handle glue symbols at all. -fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> { unimplemented!() } - -/// Backtrace support built on libgcc with some extra OS-specific support -/// -/// Some methods of getting a backtrace: -/// -/// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on OSX, and the address to symbol portion of it -/// suffers problems that are described below. -/// -/// * Using libunwind. This is more difficult than it sounds because libunwind -/// isn't installed everywhere by default. It's also a bit of a hefty library, -/// so possibly not the best option. When testing, libunwind was excellent at -/// getting both accurate backtraces and accurate symbols across platforms. -/// This route was not chosen in favor of the next option, however. -/// -/// * We're already using libgcc_s for exceptions in rust (triggering task -/// unwinding and running destructors on the stack), and it turns out that it -/// conveniently comes with a function that also gives us a backtrace. All of -/// these functions look like _Unwind_*, but it's not quite the full -/// repertoire of the libunwind API. Due to it already being in use, this was -/// the chosen route of getting a backtrace. -/// -/// After choosing libgcc_s for backtraces, the sad part is that it will only -/// give us a stack trace of instruction pointers. Thankfully these instruction -/// pointers are accurate (they work for green and native threads), but it's -/// then up to us again to figure out how to translate these addresses to -/// symbols. As with before, we have a few options. Before, that, a little bit -/// of an interlude about symbols. This is my very limited knowledge about -/// symbol tables, and this information is likely slightly wrong, but the -/// general idea should be correct. -/// -/// When talking about symbols, it's helpful to know a few things about where -/// symbols are located. Some symbols are located in the dynamic symbol table -/// of the executable which in theory means that they're available for dynamic -/// linking and lookup. Other symbols end up only in the local symbol table of -/// the file. This loosely corresponds to pub and priv functions in Rust. -/// -/// Armed with this knowledge, we know that our solution for address to symbol -/// translation will need to consult both the local and dynamic symbol tables. -/// With that in mind, here's our options of translating an address to -/// a symbol. -/// -/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() -/// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on OSX. It appears dladdr() -/// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for OSX, this is the -/// method used for translation. It's provided by the system and easy to do.o -/// -/// Sadly, all other systems have a dladdr() implementation that does not -/// consult the local symbol table. This means that most functions are blank -/// because they don't have symbols. This means that we need another solution. -/// -/// * Use unw_get_proc_name(). This is part of the libunwind api (not the -/// libgcc_s version of the libunwind api), but involves taking a dependency -/// to libunwind. We may pursue this route in the future if we bundle -/// libunwind, but libunwind was unwieldy enough that it was not chosen at -/// this time to provide this functionality. -/// -/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a -/// semi-reasonable solution. The stdlib already knows how to spawn processes, -/// so in theory it could invoke readelf, parse the output, and consult the -/// local/dynamic symbol tables from there. This ended up not getting chosen -/// due to the craziness of the idea plus the advent of the next option. -/// -/// * Use `libbacktrace`. It turns out that this is a small library bundled in -/// the gcc repository which provides backtrace and symbol translation -/// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not OSX, so this is the -/// chosen route for now. -/// -/// In summary, the current situation uses libgcc_s to get a trace of stack -/// pointers, and we use dladdr() or libbacktrace to translate these addresses -/// to symbols. This is a bit of a hokey implementation as-is, but it works for -/// all unix platforms we support right now, so it at least gets the job done. -#[cfg(unix)] -mod imp { - use c_str::CString; - use io::{IoResult, Writer}; - use libc; - use mem; - use option::{Some, None, Option}; - use result::{Ok, Err}; - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - - /// As always - iOS on arm uses SjLj exceptions and - /// _Unwind_Backtrace is even not available there. Still, - /// backtraces could be extracted using a backtrace function, - /// which thanks god is public - /// - /// As mentioned in a huge comment block above, backtrace doesn't - /// play well with green threads, so while it is extremely nice - /// and simple to use it should be used only on iOS devices as the - /// only viable option. - #[cfg(all(target_os = "ios", target_arch = "arm"))] - #[inline(never)] - pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } - - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - #[inline(never)] // if we know this is a function call, we can skip it when - // tracing - pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { unimplemented!() } - - #[cfg(not(any(target_os = "macos", target_os = "ios")))] - fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { unimplemented!() } - - // Finally, after all that work above, we can emit a symbol. - fn output(w: &mut Writer, idx: int, addr: *mut libc::c_void, - s: Option) -> IoResult<()> { unimplemented!() } - - /// Unwind library interface used for backtraces - /// - /// Note that the native libraries come from librustrt, not this - /// module. - /// Note that dead code is allowed as here are just bindings - /// iOS doesn't use all of them it but adding more - /// platform-specific configs pollutes the code too much - #[allow(non_camel_case_types)] - #[allow(non_snake_case)] - #[allow(dead_code)] - mod uw { - pub use self::_Unwind_Reason_Code::*; - - use libc; - - #[repr(C)] - pub enum _Unwind_Reason_Code { - _URC_NO_REASON = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9, // used only by ARM EABI - } - - pub enum _Unwind_Context {} - - pub type _Unwind_Trace_Fn = - extern fn(ctx: *mut _Unwind_Context, - arg: *mut libc::c_void) -> _Unwind_Reason_Code; - - extern { - // No native _Unwind_Backtrace on iOS - #[cfg(not(all(target_os = "ios", target_arch = "arm")))] - pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn, - trace_argument: *mut libc::c_void) - -> _Unwind_Reason_Code; - - #[cfg(all(not(target_os = "android"), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t; - - #[cfg(all(not(target_os = "android"), - not(all(target_os = "linux", target_arch = "arm"))))] - pub fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) - -> *mut libc::c_void; - } - - // On android, the function _Unwind_GetIP is a macro, and this is the - // expansion of the macro. This is all copy/pasted directly from the - // header file with the definition of _Unwind_GetIP. - #[cfg(any(target_os = "android", - all(target_os = "linux", target_arch = "arm")))] - pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) -> libc::uintptr_t { unimplemented!() } - - // This function also doesn't exist on Android or ARM/Linux, so make it - // a no-op - #[cfg(any(target_os = "android", - all(target_os = "linux", target_arch = "arm")))] - pub unsafe fn _Unwind_FindEnclosingFunction(pc: *mut libc::c_void) - -> *mut libc::c_void - { unimplemented!() } - } -} - -/// As always, windows has something very different than unix, we mainly want -/// to avoid having to depend too much on libunwind for windows. -/// -/// If you google around, you'll find a fair bit of references to built-in -/// functions to get backtraces on windows. It turns out that most of these are -/// in an external library called dbghelp. I was unable to find this library -/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -/// of it. -/// -/// You'll also find that there's a function called CaptureStackBackTrace -/// mentioned frequently (which is also easy to use), but sadly I didn't have a -/// copy of that function in my mingw install (maybe it was broken?). Instead, -/// this takes the route of using StackWalk64 in order to walk the stack. -#[cfg(windows)] -#[allow(dead_code, non_snake_case)] -mod imp { - use c_str::CString; - use intrinsics; - use io::{IoResult, Writer}; - use libc; - use mem; - use ops::Drop; - use option::{Some, None}; - use path::Path; - use result::{Ok, Err}; - use rustrt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT}; - use slice::SlicePrelude; - use str::StrPrelude; - use dynamic_lib::DynamicLibrary; - - #[allow(non_snake_case)] - extern "system" { - fn GetCurrentProcess() -> libc::HANDLE; - fn GetCurrentThread() -> libc::HANDLE; - fn RtlCaptureContext(ctx: *mut arch::CONTEXT); - } - - type SymFromAddrFn = - extern "system" fn(libc::HANDLE, u64, *mut u64, - *mut SYMBOL_INFO) -> libc::BOOL; - type SymInitializeFn = - extern "system" fn(libc::HANDLE, *mut libc::c_void, - libc::BOOL) -> libc::BOOL; - type SymCleanupFn = - extern "system" fn(libc::HANDLE) -> libc::BOOL; - - type StackWalk64Fn = - extern "system" fn(libc::DWORD, libc::HANDLE, libc::HANDLE, - *mut STACKFRAME64, *mut arch::CONTEXT, - *mut libc::c_void, *mut libc::c_void, - *mut libc::c_void, *mut libc::c_void) -> libc::BOOL; - - const MAX_SYM_NAME: uint = 2000; - const IMAGE_FILE_MACHINE_I386: libc::DWORD = 0x014c; - const IMAGE_FILE_MACHINE_IA64: libc::DWORD = 0x0200; - const IMAGE_FILE_MACHINE_AMD64: libc::DWORD = 0x8664; - - #[repr(C)] - struct SYMBOL_INFO { - SizeOfStruct: libc::c_ulong, - TypeIndex: libc::c_ulong, - Reserved: [u64, ..2], - Index: libc::c_ulong, - Size: libc::c_ulong, - ModBase: u64, - Flags: libc::c_ulong, - Value: u64, - Address: u64, - Register: libc::c_ulong, - Scope: libc::c_ulong, - Tag: libc::c_ulong, - NameLen: libc::c_ulong, - MaxNameLen: libc::c_ulong, - // note that windows has this as 1, but it basically just means that - // the name is inline at the end of the struct. For us, we just bump - // the struct size up to MAX_SYM_NAME. - Name: [libc::c_char, ..MAX_SYM_NAME], - } - - - #[repr(C)] - enum ADDRESS_MODE { - AddrMode1616, - AddrMode1632, - AddrModeReal, - AddrModeFlat, - } - - struct ADDRESS64 { - Offset: u64, - Segment: u16, - Mode: ADDRESS_MODE, - } - - struct STACKFRAME64 { - AddrPC: ADDRESS64, - AddrReturn: ADDRESS64, - AddrFrame: ADDRESS64, - AddrStack: ADDRESS64, - AddrBStore: ADDRESS64, - FuncTableEntry: *mut libc::c_void, - Params: [u64, ..4], - Far: libc::BOOL, - Virtual: libc::BOOL, - Reserved: [u64, ..3], - KdHelp: KDHELP64, - } - - struct KDHELP64 { - Thread: u64, - ThCallbackStack: libc::DWORD, - ThCallbackBStore: libc::DWORD, - NextCallback: libc::DWORD, - FramePointer: libc::DWORD, - KiCallUserMode: u64, - KeUserCallbackDispatcher: u64, - SystemRangeStart: u64, - KiUserExceptionDispatcher: u64, - StackBase: u64, - StackLimit: u64, - Reserved: [u64, ..5], - } - - #[cfg(target_arch = "x86")] - mod arch { - use libc; - - const MAXIMUM_SUPPORTED_EXTENSION: uint = 512; - - #[repr(C)] - pub struct CONTEXT { - ContextFlags: libc::DWORD, - Dr0: libc::DWORD, - Dr1: libc::DWORD, - Dr2: libc::DWORD, - Dr3: libc::DWORD, - Dr6: libc::DWORD, - Dr7: libc::DWORD, - FloatSave: FLOATING_SAVE_AREA, - SegGs: libc::DWORD, - SegFs: libc::DWORD, - SegEs: libc::DWORD, - SegDs: libc::DWORD, - Edi: libc::DWORD, - Esi: libc::DWORD, - Ebx: libc::DWORD, - Edx: libc::DWORD, - Ecx: libc::DWORD, - Eax: libc::DWORD, - Ebp: libc::DWORD, - Eip: libc::DWORD, - SegCs: libc::DWORD, - EFlags: libc::DWORD, - Esp: libc::DWORD, - SegSs: libc::DWORD, - ExtendedRegisters: [u8, ..MAXIMUM_SUPPORTED_EXTENSION], - } - - #[repr(C)] - pub struct FLOATING_SAVE_AREA { - ControlWord: libc::DWORD, - StatusWord: libc::DWORD, - TagWord: libc::DWORD, - ErrorOffset: libc::DWORD, - ErrorSelector: libc::DWORD, - DataOffset: libc::DWORD, - DataSelector: libc::DWORD, - RegisterArea: [u8, ..80], - Cr0NpxState: libc::DWORD, - } - - pub fn init_frame(frame: &mut super::STACKFRAME64, - ctx: &CONTEXT) -> libc::DWORD { unimplemented!() } - } - - #[cfg(target_arch = "x86_64")] - mod arch { - use libc::{c_longlong, c_ulonglong}; - use libc::types::os::arch::extra::{WORD, DWORD, DWORDLONG}; - use simd; - - #[repr(C)] - pub struct CONTEXT { - _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte - P1Home: DWORDLONG, - P2Home: DWORDLONG, - P3Home: DWORDLONG, - P4Home: DWORDLONG, - P5Home: DWORDLONG, - P6Home: DWORDLONG, - - ContextFlags: DWORD, - MxCsr: DWORD, - - SegCs: WORD, - SegDs: WORD, - SegEs: WORD, - SegFs: WORD, - SegGs: WORD, - SegSs: WORD, - EFlags: DWORD, - - Dr0: DWORDLONG, - Dr1: DWORDLONG, - Dr2: DWORDLONG, - Dr3: DWORDLONG, - Dr6: DWORDLONG, - Dr7: DWORDLONG, - - Rax: DWORDLONG, - Rcx: DWORDLONG, - Rdx: DWORDLONG, - Rbx: DWORDLONG, - Rsp: DWORDLONG, - Rbp: DWORDLONG, - Rsi: DWORDLONG, - Rdi: DWORDLONG, - R8: DWORDLONG, - R9: DWORDLONG, - R10: DWORDLONG, - R11: DWORDLONG, - R12: DWORDLONG, - R13: DWORDLONG, - R14: DWORDLONG, - R15: DWORDLONG, - - Rip: DWORDLONG, - - FltSave: FLOATING_SAVE_AREA, - - VectorRegister: [M128A, .. 26], - VectorControl: DWORDLONG, - - DebugControl: DWORDLONG, - LastBranchToRip: DWORDLONG, - LastBranchFromRip: DWORDLONG, - LastExceptionToRip: DWORDLONG, - LastExceptionFromRip: DWORDLONG, - } - - #[repr(C)] - pub struct M128A { - _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte - Low: c_ulonglong, - High: c_longlong - } - - #[repr(C)] - pub struct FLOATING_SAVE_AREA { - _align_hack: [simd::u64x2, ..0], // FIXME align on 16-byte - _Dummy: [u8, ..512] // FIXME: Fill this out - } - - pub fn init_frame(frame: &mut super::STACKFRAME64, - ctx: &CONTEXT) -> DWORD { unimplemented!() } - } - - #[repr(C)] - struct Cleanup { - handle: libc::HANDLE, - SymCleanup: SymCleanupFn, - } - - impl Drop for Cleanup { - fn drop(&mut self) { unimplemented!() } - } - - pub fn write(w: &mut Writer) -> IoResult<()> { unimplemented!() } -} diff --git a/src/libst2/rt/mod.rs b/src/libst2/rt/mod.rs deleted file mode 100644 index 89573be5f2de5..0000000000000 --- a/src/libst2/rt/mod.rs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 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. - -/*! Runtime services, including the task scheduler and I/O dispatcher - -The `rt` module provides the private runtime infrastructure necessary -to support core language features like the exchange and local heap, -logging, local data and unwinding. It also implements the default task -scheduler and task model. Initialization routines are provided for setting -up runtime resources in common configurations, including that used by -`rustc` when generating executables. - -It is intended that the features provided by `rt` can be factored in a -way such that the core library can be built with different 'profiles' -for different use cases, e.g. excluding the task scheduler. A number -of runtime features though are critical to the functioning of the -language and an implementation must be provided regardless of the -execution environment. - -Of foremost importance is the global exchange heap, in the module -`heap`. Very little practical Rust code can be written without -access to the global heap. Unlike most of `rt` the global heap is -truly a global resource and generally operates independently of the -rest of the runtime. - -All other runtime features are task-local, including the local heap, -local storage, logging and the stack unwinder. - -The relationship between `rt` and the rest of the core library is -not entirely clear yet and some modules will be moving into or -out of `rt` as development proceeds. - -Several modules in `core` are clients of `rt`: - -* `std::task` - The user-facing interface to the Rust task model. -* `std::local_data` - The interface to local data. -* `std::unstable::lang` - Miscellaneous lang items, some of which rely on `std::rt`. -* `std::cleanup` - Local heap destruction. -* `std::io` - In the future `std::io` will use an `rt` implementation. -* `std::logging` -* `std::comm` - -*/ - -#![experimental] - -// FIXME: this should not be here. -#![allow(missing_docs)] - -#![allow(dead_code)] - -use failure; -use rustrt; -use os; - -// Reexport some of our utilities which are expected by other crates. -pub use self::util::{default_sched_threads, min_stack, running_on_valgrind}; - -// Reexport functionality from librustrt and other crates underneath the -// standard library which work together to create the entire runtime. -pub use alloc::heap; -pub use rustrt::{begin_unwind, begin_unwind_fmt, at_exit}; - -// Simple backtrace functionality (to print on panic) -pub mod backtrace; - -// Just stuff -mod util; - -/// One-time runtime initialization. -/// -/// Initializes global state, including frobbing -/// the crate's logging flags, registering GC -/// metadata, and storing the process arguments. -#[allow(experimental)] -pub fn init(argc: int, argv: *const *const u8) { unimplemented!() } - -#[cfg(any(windows, android))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 1 << 20; -#[cfg(all(unix, not(android)))] -static OS_DEFAULT_STACK_ESTIMATE: uint = 2 * (1 << 20); - -#[cfg(not(test))] -#[lang = "start"] -fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { unimplemented!() } - -/// Executes the given procedure after initializing the runtime with the given -/// argc/argv. -/// -/// This procedure is guaranteed to run on the thread calling this function, but -/// the stack bounds for this rust task will *not* be set. Care must be taken -/// for this function to not overflow its stack. -/// -/// This function will only return once *all* native threads in the system have -/// exited. -pub fn start(argc: int, argv: *const *const u8, main: proc()) -> int { unimplemented!() } - -/// One-time runtime cleanup. -/// -/// This function is unsafe because it performs no checks to ensure that the -/// runtime has completely ceased running. It is the responsibility of the -/// caller to ensure that the runtime is entirely shut down and nothing will be -/// poking around at the internal components. -/// -/// Invoking cleanup while portions of the runtime are still in use may cause -/// undefined behavior. -pub unsafe fn cleanup() { unimplemented!() } diff --git a/src/libst2/rt/util.rs b/src/libst2/rt/util.rs deleted file mode 100644 index 8b87547a89626..0000000000000 --- a/src/libst2/rt/util.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 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. - -use libc::uintptr_t; -use option::{Some, None, Option}; -use os; -use str::{FromStr, from_str, Str}; -use sync::atomic; - -/// Dynamically inquire about whether we're running under V. -/// You should usually not use this unless your test definitely -/// can't run correctly un-altered. Valgrind is there to help -/// you notice weirdness in normal, un-doctored code paths! -pub fn running_on_valgrind() -> bool { unimplemented!() } - -/// Valgrind has a fixed-sized array (size around 2000) of segment descriptors -/// wired into it; this is a hard limit and requires rebuilding valgrind if you -/// want to go beyond it. Normally this is not a problem, but in some tests, we -/// produce a lot of threads casually. Making lots of threads alone might not -/// be a problem _either_, except on OSX, the segments produced for new threads -/// _take a while_ to get reclaimed by the OS. Combined with the fact that libuv -/// schedulers fork off a separate thread for polling fsevents on OSX, we get a -/// perfect storm of creating "too many mappings" for valgrind to handle when -/// running certain stress tests in the runtime. -pub fn limit_thread_creation_due_to_osx_and_valgrind() -> bool { unimplemented!() } - -pub fn min_stack() -> uint { unimplemented!() } - -/// Get's the number of scheduler threads requested by the environment -/// either `RUST_THREADS` or `num_cpus`. -pub fn default_sched_threads() -> uint { unimplemented!() } diff --git a/src/libst2/rtdeps.rs b/src/libst2/rtdeps.rs deleted file mode 100644 index 35a8713711591..0000000000000 --- a/src/libst2/rtdeps.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 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. - -//! This module contains the linkage attributes to all runtime dependencies of -//! the standard library This varies per-platform, but these libraries are -//! necessary for running libstd. - -#![experimental] - -// All platforms need to link to rustrt -#[cfg(not(test))] -#[link(name = "rust_builtin", kind = "static")] -extern {} - -// LLVM implements the `frem` instruction as a call to `fmod`, which lives in -// libm. Hence, we must explicitly link to it. -// -// On Linux, librt and libdl are indirect dependencies via rustrt, -// and binutils 2.22+ won't add them automatically -#[cfg(target_os = "linux")] -#[link(name = "dl")] -#[link(name = "pthread")] -extern {} - -#[cfg(target_os = "android")] -#[link(name = "dl")] -#[link(name = "log")] -extern {} - -#[cfg(target_os = "freebsd")] -#[link(name = "execinfo")] -#[link(name = "pthread")] -extern {} - -#[cfg(target_os = "dragonfly")] -#[link(name = "pthread")] -extern {} - -#[cfg(target_os = "macos")] -#[link(name = "System")] -extern {} - -#[cfg(target_os = "ios")] -#[link(name = "System")] -extern {} diff --git a/src/libst2/sync/future.rs b/src/libst2/sync/future.rs deleted file mode 100644 index d62d1941fb6ac..0000000000000 --- a/src/libst2/sync/future.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * A type representing values that may be computed concurrently and - * operations for working with them. - * - * # Example - * - * ```rust - * use std::sync::Future; - * # fn fib(n: uint) -> uint {42}; - * # fn make_a_sandwich() {}; - * let mut delayed_fib = Future::spawn(proc() { fib(5000) }); - * make_a_sandwich(); - * println!("fib(5000) = {}", delayed_fib.get()) - * ``` - */ - -#![allow(missing_docs)] - -use core::prelude::*; -use core::mem::replace; - -use self::FutureState::*; -use comm::{Receiver, channel}; -use task::spawn; - -/// A type encapsulating the result of a computation which may not be complete -pub struct Future { - state: FutureState, -} - -enum FutureState { - Pending(proc():Send -> A), - Evaluating, - Forced(A) -} - -/// Methods on the `future` type -impl Future { - pub fn get(&mut self) -> A { unimplemented!() } -} - -impl Future { - /// Gets the value from this future, forcing evaluation. - pub fn unwrap(mut self) -> A { unimplemented!() } - - pub fn get_ref<'a>(&'a mut self) -> &'a A { unimplemented!() } - - pub fn from_value(val: A) -> Future { unimplemented!() } - - pub fn from_fn(f: proc():Send -> A) -> Future { unimplemented!() } -} - -impl Future { - pub fn from_receiver(rx: Receiver) -> Future { unimplemented!() } - - pub fn spawn(blk: proc():Send -> A) -> Future { unimplemented!() } -} diff --git a/src/libst2/sync/mod.rs b/src/libst2/sync/mod.rs deleted file mode 100644 index 38e1e952f77e2..0000000000000 --- a/src/libst2/sync/mod.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 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. - -//! Useful synchronization primitives -//! -//! This module contains useful safe and unsafe synchronization primitives. -//! Most of the primitives in this module do not provide any sort of locking -//! and/or blocking at all, but rather provide the necessary tools to build -//! other types of concurrent primitives. - -#![experimental] - -#[stable] -pub use core_sync::atomic; - -pub use core_sync::{deque, mpmc_bounded_queue, mpsc_queue, spsc_queue}; -pub use core_sync::{Arc, Weak, Mutex, MutexGuard, Condvar, Barrier}; -pub use core_sync::{RWLock, RWLockReadGuard, RWLockWriteGuard}; -pub use core_sync::{Semaphore, SemaphoreGuard}; -pub use core_sync::one::{Once, ONCE_INIT}; - -pub use self::future::Future; -pub use self::task_pool::TaskPool; - -mod future; -mod task_pool; diff --git a/src/libst2/sync/task_pool.rs b/src/libst2/sync/task_pool.rs deleted file mode 100644 index 87249af72ab4c..0000000000000 --- a/src/libst2/sync/task_pool.rs +++ /dev/null @@ -1,80 +0,0 @@ -// 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. - -//! Abstraction of a task pool for basic parallelism. - -use core::prelude::*; - -use task::spawn; -use comm::{channel, Sender, Receiver}; -use sync::{Arc, Mutex}; - -struct Sentinel<'a> { - jobs: &'a Arc>>, - active: bool -} - -impl<'a> Sentinel<'a> { - fn new(jobs: &Arc>>) -> Sentinel { unimplemented!() } - - // Cancel and destroy this sentinel. - fn cancel(mut self) { unimplemented!() } -} - -#[unsafe_destructor] -impl<'a> Drop for Sentinel<'a> { - fn drop(&mut self) { unimplemented!() } -} - -/// A task pool used to execute functions in parallel. -/// -/// Spawns `n` worker tasks and replenishes the pool if any worker tasks -/// panic. -/// -/// # Example -/// -/// ```rust -/// # use std::sync::TaskPool; -/// # use std::iter::AdditiveIterator; -/// -/// let pool = TaskPool::new(4u); -/// -/// let (tx, rx) = channel(); -/// for _ in range(0, 8u) { -/// let tx = tx.clone(); -/// pool.execute(proc() { -/// tx.send(1u); -/// }); -/// } -/// -/// assert_eq!(rx.iter().take(8u).sum(), 8u); -/// ``` -pub struct TaskPool { - // How the taskpool communicates with subtasks. - // - // This is the only such Sender, so when it is dropped all subtasks will - // quit. - jobs: Sender -} - -impl TaskPool { - /// Spawns a new task pool with `tasks` tasks. - /// - /// # Panics - /// - /// This function will panic if `tasks` is 0. - pub fn new(tasks: uint) -> TaskPool { unimplemented!() } - - /// Executes the function `job` on a task in the pool. - pub fn execute(&self, job: proc():Send) { unimplemented!() } -} - -fn spawn_in_pool(jobs: Arc>>) { unimplemented!() } - diff --git a/src/libst2/sys/common/helper_thread.rs b/src/libst2/sys/common/helper_thread.rs deleted file mode 100644 index bc2f3a8ac3555..0000000000000 --- a/src/libst2/sys/common/helper_thread.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2013-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. - -//! Implementation of the helper thread for the timer module -//! -//! This module contains the management necessary for the timer worker thread. -//! This thread is responsible for performing the send()s on channels for timers -//! that are using channels instead of a blocking call. -//! -//! The timer thread is lazily initialized, and it's shut down via the -//! `shutdown` function provided. It must be maintained as an invariant that -//! `shutdown` is only called when the entire program is finished. No new timers -//! can be created in the future and there must be no active timers at that -//! time. - -use mem; -use rustrt::bookkeeping; -use rustrt::mutex::StaticNativeMutex; -use rustrt; -use cell::UnsafeCell; -use sys::helper_signal; -use prelude::*; - -use task; - -/// A structure for management of a helper thread. -/// -/// This is generally a static structure which tracks the lifetime of a helper -/// thread. -/// -/// The fields of this helper are all public, but they should not be used, this -/// is for static initialization. -pub struct Helper { - /// Internal lock which protects the remaining fields - pub lock: StaticNativeMutex, - - // You'll notice that the remaining fields are UnsafeCell, and this is - // because all helper thread operations are done through &self, but we need - // these to be mutable (once `lock` is held). - - /// Lazily allocated channel to send messages to the helper thread. - pub chan: UnsafeCell<*mut Sender>, - - /// OS handle used to wake up a blocked helper thread - pub signal: UnsafeCell, - - /// Flag if this helper thread has booted and been initialized yet. - pub initialized: UnsafeCell, -} - -impl Helper { - /// Lazily boots a helper thread, becoming a no-op if the helper has already - /// been spawned. - /// - /// This function will check to see if the thread has been initialized, and - /// if it has it returns quickly. If initialization has not happened yet, - /// the closure `f` will be run (inside of the initialization lock) and - /// passed to the helper thread in a separate task. - /// - /// This function is safe to be called many times. - pub fn boot(&'static self, - f: || -> T, - helper: fn(helper_signal::signal, Receiver, T)) { unimplemented!() } - - /// Sends a message to a spawned worker thread. - /// - /// This is only valid if the worker thread has previously booted - pub fn send(&'static self, msg: M) { unimplemented!() } - - fn shutdown(&'static self) { unimplemented!() } -} diff --git a/src/libst2/sys/common/mod.rs b/src/libst2/sys/common/mod.rs deleted file mode 100644 index 254ad0719e6f1..0000000000000 --- a/src/libst2/sys/common/mod.rs +++ /dev/null @@ -1,55 +0,0 @@ -// 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. - -#![allow(missing_docs)] -#![allow(dead_code)] - -use io::{mod, IoError, IoResult}; -use prelude::*; -use sys::{last_error, retry, fs}; -use c_str::CString; -use num::Int; -use path::BytesContainer; -use collections; - -pub mod net; -pub mod helper_thread; -pub mod thread_local; - -// common error constructors - -pub fn eof() -> IoError { unimplemented!() } - -pub fn timeout(desc: &'static str) -> IoError { unimplemented!() } - -pub fn short_write(n: uint, desc: &'static str) -> IoError { unimplemented!() } - -pub fn unimpl() -> IoError { unimplemented!() } - -// unix has nonzero values as errors -pub fn mkerr_libc(ret: T) -> IoResult<()> { unimplemented!() } - -pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { unimplemented!() } - -// traits for extracting representations from - -pub trait AsFileDesc { - fn as_fd(&self) -> &fs::FileDesc; -} - -pub trait ProcessConfig { - fn program(&self) -> &CString; - fn args(&self) -> &[CString]; - fn env(&self) -> Option<&collections::HashMap>; - fn cwd(&self) -> Option<&CString>; - fn uid(&self) -> Option; - fn gid(&self) -> Option; - fn detach(&self) -> bool; -} diff --git a/src/libst2/sys/common/net.rs b/src/libst2/sys/common/net.rs deleted file mode 100644 index f6b73ddfa9d75..0000000000000 --- a/src/libst2/sys/common/net.rs +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2013-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. - -pub use self::SocketStatus::*; -pub use self::InAddr::*; - -use alloc::arc::Arc; -use libc::{mod, c_char, c_int}; -use mem; -use num::Int; -use ptr::{mod, null, null_mut}; -use rustrt::mutex; -use io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; -use io::net::addrinfo; -use io::{IoResult, IoError}; -use sys::{mod, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, - wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, - decode_error_detailed}; -use sys_common::{mod, keep_going, short_write, timeout}; -use prelude::*; -use cmp; -use io; - -// FIXME: move uses of Arc and deadline tracking to std::io - -#[deriving(Show)] -pub enum SocketStatus { - Readable, - Writable, -} - -//////////////////////////////////////////////////////////////////////////////// -// sockaddr and misc bindings -//////////////////////////////////////////////////////////////////////////////// - -pub fn htons(u: u16) -> u16 { unimplemented!() } -pub fn ntohs(u: u16) -> u16 { unimplemented!() } - -pub enum InAddr { - In4Addr(libc::in_addr), - In6Addr(libc::in6_addr), -} - -pub fn ip_to_inaddr(ip: IpAddr) -> InAddr { unimplemented!() } - -pub fn addr_to_sockaddr(addr: SocketAddr, - storage: &mut libc::sockaddr_storage) - -> libc::socklen_t { unimplemented!() } - -pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult { unimplemented!() } - -pub fn setsockopt(fd: sock_t, opt: libc::c_int, val: libc::c_int, - payload: T) -> IoResult<()> { unimplemented!() } - -pub fn getsockopt(fd: sock_t, opt: libc::c_int, - val: libc::c_int) -> IoResult { unimplemented!() } - -pub fn sockname(fd: sock_t, - f: unsafe extern "system" fn(sock_t, *mut libc::sockaddr, - *mut libc::socklen_t) -> libc::c_int) - -> IoResult -{ unimplemented!() } - -pub fn sockaddr_to_addr(storage: &libc::sockaddr_storage, - len: uint) -> IoResult { unimplemented!() } - -//////////////////////////////////////////////////////////////////////////////// -// get_host_addresses -//////////////////////////////////////////////////////////////////////////////// - -extern "system" { - fn getaddrinfo(node: *const c_char, service: *const c_char, - hints: *const libc::addrinfo, - res: *mut *mut libc::addrinfo) -> c_int; - fn freeaddrinfo(res: *mut libc::addrinfo); -} - -pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, - hint: Option) - -> Result, IoError> -{ unimplemented!() } - -//////////////////////////////////////////////////////////////////////////////// -// Timeout helpers -// -// The read/write functions below are the helpers for reading/writing a socket -// with a possible deadline specified. This is generally viewed as a timed out -// I/O operation. -// -// From the application's perspective, timeouts apply to the I/O object, not to -// the underlying file descriptor (it's one timeout per object). This means that -// we can't use the SO_RCVTIMEO and corresponding send timeout option. -// -// The next idea to implement timeouts would be to use nonblocking I/O. An -// invocation of select() would wait (with a timeout) for a socket to be ready. -// Once its ready, we can perform the operation. Note that the operation *must* -// be nonblocking, even though select() says the socket is ready. This is -// because some other thread could have come and stolen our data (handles can be -// cloned). -// -// To implement nonblocking I/O, the first option we have is to use the -// O_NONBLOCK flag. Remember though that this is a global setting, affecting all -// I/O objects, so this was initially viewed as unwise. -// -// It turns out that there's this nifty MSG_DONTWAIT flag which can be passed to -// send/recv, but the niftiness wears off once you realize it only works well on -// Linux [1] [2]. This means that it's pretty easy to get a nonblocking -// operation on Linux (no flag fiddling, no affecting other objects), but not on -// other platforms. -// -// To work around this constraint on other platforms, we end up using the -// original strategy of flipping the O_NONBLOCK flag. As mentioned before, this -// could cause other objects' blocking operations to suddenly become -// nonblocking. To get around this, a "blocking operation" which returns EAGAIN -// falls back to using the same code path as nonblocking operations, but with an -// infinite timeout (select + send/recv). This helps emulate blocking -// reads/writes despite the underlying descriptor being nonblocking, as well as -// optimizing the fast path of just hitting one syscall in the good case. -// -// As a final caveat, this implementation uses a mutex so only one thread is -// doing a nonblocking operation at at time. This is the operation that comes -// after the select() (at which point we think the socket is ready). This is -// done for sanity to ensure that the state of the O_NONBLOCK flag is what we -// expect (wouldn't want someone turning it on when it should be off!). All -// operations performed in the lock are *nonblocking* to avoid holding the mutex -// forever. -// -// So, in summary, Linux uses MSG_DONTWAIT and doesn't need mutexes, everyone -// else uses O_NONBLOCK and mutexes with some trickery to make sure blocking -// reads/writes are still blocking. -// -// Fun, fun! -// -// [1] http://twistedmatrix.com/pipermail/twisted-commits/2012-April/034692.html -// [2] http://stackoverflow.com/questions/19819198/does-send-msg-dontwait - -pub fn read(fd: sock_t, - deadline: u64, - lock: || -> T, - read: |bool| -> libc::c_int) -> IoResult { unimplemented!() } - -pub fn write(fd: sock_t, - deadline: u64, - buf: &[u8], - write_everything: bool, - lock: || -> T, - write: |bool, *const u8, uint| -> i64) -> IoResult { unimplemented!() } - -// See http://developerweb.net/viewtopic.php?id=3196 for where this is -// derived from. -pub fn connect_timeout(fd: sock_t, - addrp: *const libc::sockaddr, - len: libc::socklen_t, - timeout_ms: u64) -> IoResult<()> { unimplemented!() } - -pub fn await(fds: &[sock_t], deadline: Option, - status: SocketStatus) -> IoResult<()> { unimplemented!() } - -//////////////////////////////////////////////////////////////////////////////// -// Basic socket representation -//////////////////////////////////////////////////////////////////////////////// - -struct Inner { - fd: sock_t, - - // Unused on Linux, where this lock is not necessary. - #[allow(dead_code)] - lock: mutex::NativeMutex -} - -impl Inner { - fn new(fd: sock_t) -> Inner { unimplemented!() } -} - -impl Drop for Inner { - fn drop(&mut self) { unimplemented!() } -} - -pub struct Guard<'a> { - pub fd: sock_t, - pub guard: mutex::LockGuard<'a>, -} - -#[unsafe_destructor] -impl<'a> Drop for Guard<'a> { - fn drop(&mut self) { unimplemented!() } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpStream { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl TcpStream { - pub fn connect(addr: SocketAddr, timeout: Option) -> IoResult { unimplemented!() } - - pub fn new(fd: sock_t) -> TcpStream { unimplemented!() } - - pub fn fd(&self) -> sock_t { unimplemented!() } - - pub fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { unimplemented!() } - - pub fn set_keepalive(&mut self, seconds: Option) -> IoResult<()> { unimplemented!() } - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { unimplemented!() } - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - fn set_tcp_keepalive(&mut self, seconds: uint) -> IoResult<()> { unimplemented!() } - #[cfg(not(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly")))] - fn set_tcp_keepalive(&mut self, _seconds: uint) -> IoResult<()> { unimplemented!() } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) { unimplemented!() } - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - pub fn peer_name(&mut self) -> IoResult { unimplemented!() } - - pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } - pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } - - pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } - pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } - pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } - - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } -} - -impl Clone for TcpStream { - fn clone(&self) -> TcpStream { unimplemented!() } -} - -//////////////////////////////////////////////////////////////////////////////// -// UDP -//////////////////////////////////////////////////////////////////////////////// - -pub struct UdpSocket { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl UdpSocket { - pub fn bind(addr: SocketAddr) -> IoResult { unimplemented!() } - - pub fn fd(&self) -> sock_t { unimplemented!() } - - pub fn set_broadcast(&mut self, on: bool) -> IoResult<()> { unimplemented!() } - - pub fn set_multicast_loop(&mut self, on: bool) -> IoResult<()> { unimplemented!() } - - pub fn set_membership(&mut self, addr: IpAddr, opt: libc::c_int) -> IoResult<()> { unimplemented!() } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) { unimplemented!() } - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } - - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } - - pub fn recv_from(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> { unimplemented!() } - - pub fn send_to(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> { unimplemented!() } - - pub fn join_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } - pub fn leave_multicast(&mut self, multi: IpAddr) -> IoResult<()> { unimplemented!() } - - pub fn multicast_time_to_live(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } - pub fn time_to_live(&mut self, ttl: int) -> IoResult<()> { unimplemented!() } - - pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } - pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } - pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } -} - -impl Clone for UdpSocket { - fn clone(&self) -> UdpSocket { unimplemented!() } -} diff --git a/src/libst2/sys/common/thread_local.rs b/src/libst2/sys/common/thread_local.rs deleted file mode 100644 index ce138f7aac43c..0000000000000 --- a/src/libst2/sys/common/thread_local.rs +++ /dev/null @@ -1,215 +0,0 @@ -// 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. - -//! OS-based thread local storage -//! -//! This module provides an implementation of OS-based thread local storage, -//! using the native OS-provided facilities (think `TlsAlloc` or -//! `pthread_setspecific`). The interface of this differs from the other types -//! of thread-local-storage provided in this crate in that OS-based TLS can only -//! get/set pointers, -//! -//! This module also provides two flavors of TLS. One is intended for static -//! initialization, and does not contain a `Drop` implementation to deallocate -//! the OS-TLS key. The other is a type which does implement `Drop` and hence -//! has a safe interface. -//! -//! # Usage -//! -//! This module should likely not be used directly unless other primitives are -//! being built on. types such as `thread_local::scoped::Key` are likely much -//! more useful in practice than this OS-based version which likely requires -//! unsafe code to interoperate with. -//! -//! # Example -//! -//! Using a dynamically allocated TLS key. Note that this key can be shared -//! among many threads via an `Arc`. -//! -//! ```rust,ignore -//! let key = Key::new(None); -//! assert!(key.get().is_null()); -//! key.set(1 as *mut u8); -//! assert!(!key.get().is_null()); -//! -//! drop(key); // deallocate this TLS slot. -//! ``` -//! -//! Sometimes a statically allocated key is either required or easier to work -//! with, however. -//! -//! ```rust,ignore -//! static KEY: StaticKey = INIT; -//! -//! unsafe { -//! assert!(KEY.get().is_null()); -//! KEY.set(1 as *mut u8); -//! } -//! ``` - -#![allow(non_camel_case_types)] - -use prelude::*; - -use kinds::marker; -use mem; -use rustrt::exclusive::Exclusive; -use rustrt; -use sync::atomic::{mod, AtomicUint}; -use sync::{Once, ONCE_INIT}; - -use sys::thread_local as imp; - -/// A type for TLS keys that are statically allocated. -/// -/// This type is entirely `unsafe` to use as it does not protect against -/// use-after-deallocation or use-during-deallocation. -/// -/// The actual OS-TLS key is lazily allocated when this is used for the first -/// time. The key is also deallocated when the Rust runtime exits or `destroy` -/// is called, whichever comes first. -/// -/// # Example -/// -/// ```ignore -/// use tls::os::{StaticKey, INIT}; -/// -/// static KEY: StaticKey = INIT; -/// -/// unsafe { -/// assert!(KEY.get().is_null()); -/// KEY.set(1 as *mut u8); -/// } -/// ``` -pub struct StaticKey { - /// Inner static TLS key (internals), created with by `INIT_INNER` in this - /// module. - pub inner: StaticKeyInner, - /// Destructor for the TLS value. - /// - /// See `Key::new` for information about when the destructor runs and how - /// it runs. - pub dtor: Option, -} - -/// Inner contents of `StaticKey`, created by the `INIT_INNER` constant. -pub struct StaticKeyInner { - key: AtomicUint, - nc: marker::NoCopy, -} - -/// A type for a safely managed OS-based TLS slot. -/// -/// This type allocates an OS TLS key when it is initialized and will deallocate -/// the key when it falls out of scope. When compared with `StaticKey`, this -/// type is entirely safe to use. -/// -/// Implementations will likely, however, contain unsafe code as this type only -/// operates on `*mut u8`, an unsafe pointer. -/// -/// # Example -/// -/// ```rust,ignore -/// use tls::os::Key; -/// -/// let key = Key::new(None); -/// assert!(key.get().is_null()); -/// key.set(1 as *mut u8); -/// assert!(!key.get().is_null()); -/// -/// drop(key); // deallocate this TLS slot. -/// ``` -pub struct Key { - key: imp::Key, -} - -/// Constant initialization value for static TLS keys. -/// -/// This value specifies no destructor by default. -pub const INIT: StaticKey = StaticKey { - inner: INIT_INNER, - dtor: None, -}; - -/// Constant initialization value for the inner part of static TLS keys. -/// -/// This value allows specific configuration of the destructor for a TLS key. -pub const INIT_INNER: StaticKeyInner = StaticKeyInner { - key: atomic::INIT_ATOMIC_UINT, - nc: marker::NoCopy, -}; - -static INIT_KEYS: Once = ONCE_INIT; -static mut KEYS: *mut Exclusive> = 0 as *mut _; - -impl StaticKey { - /// Gets the value associated with this TLS key - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn get(&self) -> *mut u8 { unimplemented!() } - - /// Sets this TLS key to a new value. - /// - /// This will lazily allocate a TLS key from the OS if one has not already - /// been allocated. - #[inline] - pub unsafe fn set(&self, val: *mut u8) { unimplemented!() } - - /// Deallocates this OS TLS key. - /// - /// This function is unsafe as there is no guarantee that the key is not - /// currently in use by other threads or will not ever be used again. - /// - /// Note that this does *not* run the user-provided destructor if one was - /// specified at definition time. Doing so must be done manually. - pub unsafe fn destroy(&self) { unimplemented!() } - - #[inline] - unsafe fn key(&self) -> imp::Key { unimplemented!() } - - unsafe fn lazy_init(&self) -> uint { unimplemented!() } -} - -impl Key { - /// Create a new managed OS TLS key. - /// - /// This key will be deallocated when the key falls out of scope. - /// - /// The argument provided is an optionally-specified destructor for the - /// value of this TLS key. When a thread exits and the value for this key - /// is non-null the destructor will be invoked. The TLS value will be reset - /// to null before the destructor is invoked. - /// - /// Note that the destructor will not be run when the `Key` goes out of - /// scope. - #[inline] - pub fn new(dtor: Option) -> Key { unimplemented!() } - - /// See StaticKey::get - #[inline] - pub fn get(&self) -> *mut u8 { unimplemented!() } - - /// See StaticKey::set - #[inline] - pub fn set(&self, val: *mut u8) { unimplemented!() } -} - -impl Drop for Key { - fn drop(&mut self) { unimplemented!() } -} - -fn init_keys() { unimplemented!() } - -fn register_key(key: imp::Key) { unimplemented!() } - -fn unregister_key(key: imp::Key) { unimplemented!() } - diff --git a/src/libst2/sys/unix/c.rs b/src/libst2/sys/unix/c.rs deleted file mode 100644 index 2b9791b87fe2e..0000000000000 --- a/src/libst2/sys/unix/c.rs +++ /dev/null @@ -1,257 +0,0 @@ -// 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. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -pub use self::select::fd_set; -pub use self::signal::{sigaction, siginfo, sigset_t}; -pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP}; -pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; - -use libc; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const FIONBIO: libc::c_ulong = 0x8004667e; -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -pub const FIONBIO: libc::c_ulong = 0x5421; -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -pub const FIONBIO: libc::c_ulong = 0x667e; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const FIOCLEX: libc::c_ulong = 0x20006601; -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -pub const FIOCLEX: libc::c_ulong = 0x5451; -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -pub const FIOCLEX: libc::c_ulong = 0x6601; - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -pub const MSG_DONTWAIT: libc::c_int = 0x80; -#[cfg(any(target_os = "linux", target_os = "android"))] -pub const MSG_DONTWAIT: libc::c_int = 0x40; - -pub const WNOHANG: libc::c_int = 1; - -extern { - pub fn gettimeofday(timeval: *mut libc::timeval, - tzp: *mut libc::c_void) -> libc::c_int; - pub fn select(nfds: libc::c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - errorfds: *mut fd_set, - timeout: *mut libc::timeval) -> libc::c_int; - pub fn getsockopt(sockfd: libc::c_int, - level: libc::c_int, - optname: libc::c_int, - optval: *mut libc::c_void, - optlen: *mut libc::socklen_t) -> libc::c_int; - pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; - - - pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int, - options: libc::c_int) -> libc::pid_t; - - pub fn sigaction(signum: libc::c_int, - act: *const sigaction, - oldact: *mut sigaction) -> libc::c_int; - - pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; - pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; - pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; -} - -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod select { - pub const FD_SETSIZE: uint = 1024; - - #[repr(C)] - pub struct fd_set { - fds_bits: [i32, ..(FD_SETSIZE / 32)] - } - - pub fn fd_set(set: &mut fd_set, fd: i32) { unimplemented!() } -} - -#[cfg(any(target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "linux"))] -mod select { - use uint; - use libc; - - pub const FD_SETSIZE: uint = 1024; - - #[repr(C)] - pub struct fd_set { - // FIXME: shouldn't this be a c_ulong? - fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)] - } - - pub fn fd_set(set: &mut fd_set, fd: i32) { unimplemented!() } -} - -#[cfg(any(all(target_os = "linux", - any(target_arch = "x86", - target_arch = "x86_64", - target_arch = "arm")), - target_os = "android"))] -mod signal { - use libc; - - pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; - pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002; - pub const SA_NODEFER: libc::c_ulong = 0x40000000; - pub const SA_ONSTACK: libc::c_ulong = 0x08000000; - pub const SA_RESETHAND: libc::c_ulong = 0x80000000; - pub const SA_RESTART: libc::c_ulong = 0x10000000; - pub const SA_SIGINFO: libc::c_ulong = 0x00000004; - pub const SIGCHLD: libc::c_int = 17; - - // This definition is not as accurate as it could be, {pid, uid, status} is - // actually a giant union. Currently we're only interested in these fields, - // however. - #[repr(C)] - pub struct siginfo { - si_signo: libc::c_int, - si_errno: libc::c_int, - si_code: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_handler: extern fn(libc::c_int), - pub sa_mask: sigset_t, - pub sa_flags: libc::c_ulong, - sa_restorer: *mut libc::c_void, - } - - #[repr(C)] - #[cfg(target_word_size = "32")] - pub struct sigset_t { - __val: [libc::c_ulong, ..32], - } - - #[repr(C)] - #[cfg(target_word_size = "64")] - pub struct sigset_t { - __val: [libc::c_ulong, ..16], - } -} - -#[cfg(all(target_os = "linux", - any(target_arch = "mips", target_arch = "mipsel")))] -mod signal { - use libc; - - pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; - pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000; - pub const SA_NODEFER: libc::c_ulong = 0x40000000; - pub const SA_ONSTACK: libc::c_ulong = 0x08000000; - pub const SA_RESETHAND: libc::c_ulong = 0x80000000; - pub const SA_RESTART: libc::c_ulong = 0x10000000; - pub const SA_SIGINFO: libc::c_ulong = 0x00000008; - pub const SIGCHLD: libc::c_int = 18; - - // This definition is not as accurate as it could be, {pid, uid, status} is - // actually a giant union. Currently we're only interested in these fields, - // however. - #[repr(C)] - pub struct siginfo { - si_signo: libc::c_int, - si_code: libc::c_int, - si_errno: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_flags: libc::c_uint, - pub sa_handler: extern fn(libc::c_int), - pub sa_mask: sigset_t, - sa_restorer: *mut libc::c_void, - sa_resv: [libc::c_int, ..1], - } - - #[repr(C)] - pub struct sigset_t { - __val: [libc::c_ulong, ..32], - } -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd", - target_os = "dragonfly"))] -mod signal { - use libc; - - pub const SA_ONSTACK: libc::c_int = 0x0001; - pub const SA_RESTART: libc::c_int = 0x0002; - pub const SA_RESETHAND: libc::c_int = 0x0004; - pub const SA_NOCLDSTOP: libc::c_int = 0x0008; - pub const SA_NODEFER: libc::c_int = 0x0010; - pub const SA_NOCLDWAIT: libc::c_int = 0x0020; - pub const SA_SIGINFO: libc::c_int = 0x0040; - pub const SIGCHLD: libc::c_int = 20; - - #[cfg(any(target_os = "macos", target_os = "ios"))] - pub type sigset_t = u32; - #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] - #[repr(C)] - pub struct sigset_t { - bits: [u32, ..4], - } - - // This structure has more fields, but we're not all that interested in - // them. - #[repr(C)] - pub struct siginfo { - pub si_signo: libc::c_int, - pub si_errno: libc::c_int, - pub si_code: libc::c_int, - pub pid: libc::pid_t, - pub uid: libc::uid_t, - pub status: libc::c_int, - } - - #[repr(C)] - pub struct sigaction { - pub sa_handler: extern fn(libc::c_int), - pub sa_flags: libc::c_int, - pub sa_mask: sigset_t, - } -} diff --git a/src/libst2/sys/unix/fs.rs b/src/libst2/sys/unix/fs.rs deleted file mode 100644 index 08286313cc1e4..0000000000000 --- a/src/libst2/sys/unix/fs.rs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2013-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. - -//! Blocking posix-based file I/O - -use libc::{mod, c_int, c_void}; -use c_str::CString; -use mem; -use io; - -use prelude::*; - -use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; -use io::{IoResult, FileStat, SeekStyle, Reader}; -use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; -use result::{Ok, Err}; -use sys::retry; -use sys_common::{keep_going, eof, mkerr_libc}; - -pub use path::PosixPath as Path; - -pub type fd_t = libc::c_int; - -pub struct FileDesc { - /// The underlying C file descriptor. - fd: fd_t, - - /// Whether to close the file descriptor on drop. - close_on_drop: bool, -} - -impl FileDesc { - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { unimplemented!() } - - pub fn read(&self, buf: &mut [u8]) -> IoResult { unimplemented!() } - pub fn write(&self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - pub fn fd(&self) -> fd_t { unimplemented!() } - - pub fn seek(&self, pos: i64, whence: SeekStyle) -> IoResult { unimplemented!() } - - pub fn tell(&self) -> IoResult { unimplemented!() } - - pub fn fsync(&self) -> IoResult<()> { unimplemented!() } - - pub fn datasync(&self) -> IoResult<()> { unimplemented!() } - - pub fn truncate(&self, offset: i64) -> IoResult<()> { unimplemented!() } - - pub fn fstat(&self) -> IoResult { unimplemented!() } - - /// Extract the actual filedescriptor without closing it. - pub fn unwrap(self) -> fd_t { unimplemented!() } -} - -impl Drop for FileDesc { - fn drop(&mut self) { unimplemented!() } -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { unimplemented!() } - -pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { unimplemented!() } - -pub fn readdir(p: &Path) -> IoResult> { unimplemented!() } - -pub fn unlink(p: &Path) -> IoResult<()> { unimplemented!() } - -pub fn rename(old: &Path, new: &Path) -> IoResult<()> { unimplemented!() } - -pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { unimplemented!() } - -pub fn rmdir(p: &Path) -> IoResult<()> { unimplemented!() } - -pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { unimplemented!() } - -pub fn readlink(p: &Path) -> IoResult { unimplemented!() } - -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } - -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { unimplemented!() } - -fn mkstat(stat: &libc::stat) -> FileStat { unimplemented!() } - -pub fn stat(p: &Path) -> IoResult { unimplemented!() } - -pub fn lstat(p: &Path) -> IoResult { unimplemented!() } - -pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { unimplemented!() } diff --git a/src/libst2/sys/unix/helper_signal.rs b/src/libst2/sys/unix/helper_signal.rs deleted file mode 100644 index e677012cb018f..0000000000000 --- a/src/libst2/sys/unix/helper_signal.rs +++ /dev/null @@ -1,22 +0,0 @@ -// 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. - -use libc; -use os; - -use sys::fs::FileDesc; - -pub type signal = libc::c_int; - -pub fn new() -> (signal, signal) { unimplemented!() } - -pub fn signal(fd: libc::c_int) { unimplemented!() } - -pub fn close(fd: libc::c_int) { unimplemented!() } diff --git a/src/libst2/sys/unix/mod.rs b/src/libst2/sys/unix/mod.rs deleted file mode 100644 index 140f3b84142c7..0000000000000 --- a/src/libst2/sys/unix/mod.rs +++ /dev/null @@ -1,82 +0,0 @@ -// 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. - -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] - -extern crate libc; - -use num; -use num::{Int, SignedInt}; -use prelude::*; -use io::{mod, IoResult, IoError}; -use sys_common::mkerr_libc; - -macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - }; -) ) - -pub mod c; -pub mod fs; -pub mod helper_signal; -pub mod os; -pub mod pipe; -pub mod process; -pub mod tcp; -pub mod timer; -pub mod thread_local; -pub mod tty; -pub mod udp; - -pub mod addrinfo { - pub use sys_common::net::get_host_addresses; -} - -// FIXME: move these to c module -pub type sock_t = self::fs::fd_t; -pub type wrlen = libc::size_t; -pub type msglen_t = libc::size_t; -pub unsafe fn close_sock(sock: sock_t) { unimplemented!() } - -pub fn last_error() -> IoError { unimplemented!() } - -pub fn last_net_error() -> IoError { unimplemented!() } - -extern "system" { - fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char; -} - -pub fn last_gai_error(s: libc::c_int) -> IoError { unimplemented!() } - -/// Convert an `errno` value into a high-level error variant and description. -pub fn decode_error(errno: i32) -> IoError { unimplemented!() } - -pub fn decode_error_detailed(errno: i32) -> IoError { unimplemented!() } - -#[inline] -pub fn retry (f: || -> T) -> T { unimplemented!() } - -pub fn ms_to_timeval(ms: u64) -> libc::timeval { unimplemented!() } - -pub fn wouldblock() -> bool { unimplemented!() } - -pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { unimplemented!() } - -// nothing needed on unix platforms -pub fn init_net() { unimplemented!() } diff --git a/src/libst2/sys/unix/os.rs b/src/libst2/sys/unix/os.rs deleted file mode 100644 index 1fc855ceea0be..0000000000000 --- a/src/libst2/sys/unix/os.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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. - -use libc; -use libc::{c_int, c_char}; -use prelude::*; -use io::IoResult; -use sys::fs::FileDesc; - -use os::TMPBUF_SZ; - -/// Returns the platform-specific value of errno -pub fn errno() -> int { unimplemented!() } - -/// Get a detailed string description for the given error number -pub fn error_string(errno: i32) -> String { unimplemented!() } - -pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { unimplemented!() } diff --git a/src/libst2/sys/unix/pipe.rs b/src/libst2/sys/unix/pipe.rs deleted file mode 100644 index f328e409b510b..0000000000000 --- a/src/libst2/sys/unix/pipe.rs +++ /dev/null @@ -1,151 +0,0 @@ -// 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. - -use alloc::arc::Arc; -use libc; -use c_str::CString; -use mem; -use rustrt::mutex; -use sync::atomic; -use io::{mod, IoResult, IoError}; -use prelude::*; - -use sys::{mod, timer, retry, c, set_nonblocking, wouldblock}; -use sys::fs::{fd_t, FileDesc}; -use sys_common::net::*; -use sys_common::{eof, mkerr_libc}; - -fn unix_socket(ty: libc::c_int) -> IoResult { unimplemented!() } - -fn addr_to_sockaddr_un(addr: &CString, - storage: &mut libc::sockaddr_storage) - -> IoResult { unimplemented!() } - -struct Inner { - fd: fd_t, - - // Unused on Linux, where this lock is not necessary. - #[allow(dead_code)] - lock: mutex::NativeMutex -} - -impl Inner { - fn new(fd: fd_t) -> Inner { unimplemented!() } -} - -impl Drop for Inner { - fn drop(&mut self) { unimplemented!() } -} - -fn connect(addr: &CString, ty: libc::c_int, - timeout: Option) -> IoResult { unimplemented!() } - -fn bind(addr: &CString, ty: libc::c_int) -> IoResult { unimplemented!() } - -//////////////////////////////////////////////////////////////////////////////// -// Unix Streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixStream { - inner: Arc, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - pub fn connect(addr: &CString, - timeout: Option) -> IoResult { unimplemented!() } - - fn new(inner: Arc) -> UnixStream { unimplemented!() } - - fn fd(&self) -> fd_t { unimplemented!() } - - #[cfg(target_os = "linux")] - fn lock_nonblocking(&self) { unimplemented!() } - - #[cfg(not(target_os = "linux"))] - fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { unimplemented!() } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - let fd = self.fd(); - let dolock = || self.lock_nonblocking(); - let doread = |nb| unsafe { - let flags = if nb {c::MSG_DONTWAIT} else {0}; - libc::recv(fd, - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as libc::size_t, - flags) as libc::c_int - }; - read(fd, self.read_deadline, dolock, doread) - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - - pub fn close_write(&mut self) -> IoResult<()> { unimplemented!() } - - pub fn close_read(&mut self) -> IoResult<()> { unimplemented!() } - - pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } - - pub fn set_read_timeout(&mut self, timeout: Option) { unimplemented!() } - - pub fn set_write_timeout(&mut self, timeout: Option) { unimplemented!() } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { unimplemented!() } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Listener -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixListener { - inner: Inner, - path: CString, -} - -impl UnixListener { - pub fn bind(addr: &CString) -> IoResult { unimplemented!() } - - fn fd(&self) -> fd_t { unimplemented!() } - - pub fn listen(self) -> IoResult { unimplemented!() } -} - -pub struct UnixAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: UnixListener, - reader: FileDesc, - writer: FileDesc, - closed: atomic::AtomicBool, -} - -impl UnixAcceptor { - fn fd(&self) -> fd_t { unimplemented!() } - - pub fn accept(&mut self) -> IoResult { unimplemented!() } - - pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } - - pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Clone for UnixAcceptor { - fn clone(&self) -> UnixAcceptor { unimplemented!() } -} - -impl Drop for UnixListener { - fn drop(&mut self) { unimplemented!() } -} diff --git a/src/libst2/sys/unix/process.rs b/src/libst2/sys/unix/process.rs deleted file mode 100644 index 7734b3a9fdf9b..0000000000000 --- a/src/libst2/sys/unix/process.rs +++ /dev/null @@ -1,69 +0,0 @@ -// 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. -use self::Req::*; - -use libc::{mod, pid_t, c_void, c_int}; -use c_str::CString; -use io::{mod, IoResult, IoError}; -use mem; -use os; -use ptr; -use prelude::*; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; -use path::BytesContainer; -use hash::Hash; - -use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval}; -use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use sys_common::{AsFileDesc, mkerr_libc, timeout}; - -pub use sys_common::ProcessConfig; - -helper_init!(static HELPER: Helper) - -/// The unique id of the process (this should never be negative). -pub struct Process { - pub pid: pid_t -} - -enum Req { - NewChild(libc::pid_t, Sender, u64), -} - -impl Process { - pub fn id(&self) -> pid_t { unimplemented!() } - - pub unsafe fn kill(&self, signal: int) -> IoResult<()> { unimplemented!() } - - pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { unimplemented!() } - - pub fn spawn(cfg: &C, in_fd: Option

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsFileDesc, - K: BytesContainer + Eq + Hash, V: BytesContainer - { unimplemented!() } - - pub fn wait(&self, deadline: u64) -> IoResult { unimplemented!() } - - pub fn try_wait(&self) -> Option { unimplemented!() } -} - -fn with_argv(prog: &CString, args: &[CString], - cb: proc(*const *const libc::c_char) -> T) -> T { unimplemented!() } - -fn with_envp(env: Option<&collections::HashMap>, - cb: proc(*const c_void) -> T) -> T - where K: BytesContainer + Eq + Hash, V: BytesContainer -{ unimplemented!() } - -fn translate_status(status: c_int) -> ProcessExit { unimplemented!() } diff --git a/src/libst2/sys/unix/tcp.rs b/src/libst2/sys/unix/tcp.rs deleted file mode 100644 index 7f6236dcad975..0000000000000 --- a/src/libst2/sys/unix/tcp.rs +++ /dev/null @@ -1,71 +0,0 @@ -// 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. - -use io::net::ip; -use io::IoResult; -use libc; -use mem; -use ptr; -use prelude::*; -use super::{last_error, last_net_error, retry, sock_t}; -use sync::{Arc, atomic}; -use sys::fs::FileDesc; -use sys::{set_nonblocking, wouldblock}; -use sys; -use sys_common; -use sys_common::net::*; - -pub use sys_common::net::TcpStream; - -//////////////////////////////////////////////////////////////////////////////// -// TCP listeners -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpListener { - pub inner: FileDesc, -} - -impl TcpListener { - pub fn bind(addr: ip::SocketAddr) -> IoResult { unimplemented!() } - - pub fn fd(&self) -> sock_t { unimplemented!() } - - pub fn listen(self, backlog: int) -> IoResult { unimplemented!() } - - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } -} - -pub struct TcpAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: TcpListener, - reader: FileDesc, - writer: FileDesc, - closed: atomic::AtomicBool, -} - -impl TcpAcceptor { - pub fn fd(&self) -> sock_t { unimplemented!() } - - pub fn accept(&mut self) -> IoResult { unimplemented!() } - - pub fn socket_name(&mut self) -> IoResult { unimplemented!() } - - pub fn set_timeout(&mut self, timeout: Option) { unimplemented!() } - - pub fn close_accept(&mut self) -> IoResult<()> { unimplemented!() } -} - -impl Clone for TcpAcceptor { - fn clone(&self) -> TcpAcceptor { unimplemented!() } -} diff --git a/src/libst2/sys/unix/thread_local.rs b/src/libst2/sys/unix/thread_local.rs deleted file mode 100644 index d507efbdebf5a..0000000000000 --- a/src/libst2/sys/unix/thread_local.rs +++ /dev/null @@ -1,40 +0,0 @@ -// 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. - -use prelude::*; -use libc::c_int; - -pub type Key = pthread_key_t; - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { unimplemented!() } - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { unimplemented!() } - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { unimplemented!() } - -#[inline] -pub unsafe fn destroy(key: Key) { unimplemented!() } - -#[cfg(target_os = "macos")] -type pthread_key_t = ::libc::c_ulong; - -#[cfg(not(target_os = "macos"))] -type pthread_key_t = ::libc::c_uint; - -extern { - fn pthread_key_create(key: *mut pthread_key_t, - dtor: Option) -> c_int; - fn pthread_key_delete(key: pthread_key_t) -> c_int; - fn pthread_getspecific(key: pthread_key_t) -> *mut u8; - fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int; -} diff --git a/src/libst2/sys/unix/timer.rs b/src/libst2/sys/unix/timer.rs deleted file mode 100644 index 11b46793d9d1b..0000000000000 --- a/src/libst2/sys/unix/timer.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 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. - -//! Timers for non-Linux/non-Windows OSes -//! -//! This module implements timers with a worker thread, select(), and a lot of -//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate -//! part is that I'm at a loss of what else to do one these OSes. This is also -//! why Linux has a specialized timerfd implementation and windows has its own -//! implementation (they're more accurate than this one). -//! -//! The basic idea is that there is a worker thread that's communicated to via a -//! channel and a pipe, the pipe is used by the worker thread in a select() -//! syscall with a timeout. The timeout is the "next timer timeout" while the -//! channel is used to send data over to the worker thread. -//! -//! Whenever the call to select() times out, then a channel receives a message. -//! Whenever the call returns that the file descriptor has information, then the -//! channel from timers is drained, enqueuing all incoming requests. -//! -//! The actual implementation of the helper thread is a sorted array of -//! timers in terms of target firing date. The target is the absolute time at -//! which the timer should fire. Timers are then re-enqueued after a firing if -//! the repeat boolean is set. -//! -//! Naturally, all this logic of adding times and keeping track of -//! relative/absolute time is a little lossy and not quite exact. I've done the -//! best I could to reduce the amount of calls to 'now()', but there's likely -//! still inaccuracies trickling in here and there. -//! -//! One of the tricky parts of this implementation is that whenever a timer is -//! acted upon, it must cancel whatever the previous action was (if one is -//! active) in order to act like the other implementations of this timer. In -//! order to do this, the timer's inner pointer is transferred to the worker -//! thread. Whenever the timer is modified, it first takes ownership back from -//! the worker thread in order to modify the same data structure. This has the -//! side effect of "cancelling" the previous requests while allowing a -//! re-enqueuing later on. -//! -//! Note that all time units in this file are in *milliseconds*. - -pub use self::Req::*; - -use libc; -use mem; -use os; -use ptr; -use sync::atomic; -use comm; -use sys::c; -use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use prelude::*; -use io::IoResult; - -helper_init!(static HELPER: Helper) - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - id: uint, - inner: Option>, -} - -pub struct Inner { - cb: Option>, - interval: u64, - repeat: bool, - target: u64, - id: uint, -} - -pub enum Req { - // Add a new timer to the helper thread. - NewTimer(Box), - - // Remove a timer based on its id and then send it back on the channel - // provided - RemoveTimer(uint, Sender>), -} - -// returns the current time (in milliseconds) -pub fn now() -> u64 { unimplemented!() } - -fn helper(input: libc::c_int, messages: Receiver, _: ()) { unimplemented!() } - -impl Timer { - pub fn new() -> IoResult { unimplemented!() } - - pub fn sleep(&mut self, ms: u64) { unimplemented!() } - - pub fn oneshot(&mut self, msecs: u64, cb: Box) { unimplemented!() } - - pub fn period(&mut self, msecs: u64, cb: Box) { unimplemented!() } - - fn inner(&mut self) -> Box { unimplemented!() } -} - -impl Drop for Timer { - fn drop(&mut self) { unimplemented!() } -} diff --git a/src/libst2/sys/unix/tty.rs b/src/libst2/sys/unix/tty.rs deleted file mode 100644 index 917b947586ba2..0000000000000 --- a/src/libst2/sys/unix/tty.rs +++ /dev/null @@ -1,29 +0,0 @@ -// 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. - -use sys::fs::FileDesc; -use prelude::*; -use libc::{mod, c_int}; -use io::{mod, IoResult, IoError}; -use sys_common; - -pub struct TTY { - pub fd: FileDesc, -} - -impl TTY { - pub fn new(fd: c_int) -> IoResult { unimplemented!() } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { unimplemented!() } - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { unimplemented!() } - pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> { unimplemented!() } - pub fn get_winsize(&mut self) -> IoResult<(int, int)> { unimplemented!() } - pub fn isatty(&self) -> bool { unimplemented!() } -} diff --git a/src/libst2/sys/unix/udp.rs b/src/libst2/sys/unix/udp.rs deleted file mode 100644 index 50f8fb828ad32..0000000000000 --- a/src/libst2/sys/unix/udp.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub use sys_common::net::UdpSocket; diff --git a/src/libst2/sys/windows/c.rs b/src/libst2/sys/windows/c.rs deleted file mode 100644 index b8e9b1dca3abc..0000000000000 --- a/src/libst2/sys/windows/c.rs +++ /dev/null @@ -1,250 +0,0 @@ -// 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. - -//! C definitions used by libnative that don't belong in liblibc - -#![allow(overflowing_literals)] -#![allow(dead_code)] -#![allow(non_camel_case_types)] - -use libc; -use prelude::*; - -pub const WSADESCRIPTION_LEN: uint = 256; -pub const WSASYS_STATUS_LEN: uint = 128; -pub const FIONBIO: libc::c_long = 0x8004667e; -pub const FD_SETSIZE: uint = 64; -pub const MSG_DONTWAIT: libc::c_int = 0; -pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582; -pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4; -pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80; -pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20; -pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2; -pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1; -pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40; -pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; - -pub const FD_ACCEPT: libc::c_long = 0x08; -pub const FD_MAX_EVENTS: uint = 10; -pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; -pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; -pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; -pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; - -#[repr(C)] -#[cfg(target_arch = "x86")] -pub struct WSADATA { - pub wVersion: libc::WORD, - pub wHighVersion: libc::WORD, - pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, -} -#[repr(C)] -#[cfg(target_arch = "x86_64")] -pub struct WSADATA { - pub wVersion: libc::WORD, - pub wHighVersion: libc::WORD, - pub iMaxSockets: u16, - pub iMaxUdpDg: u16, - pub lpVendorInfo: *mut u8, - pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], - pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], -} - -pub type LPWSADATA = *mut WSADATA; - -#[repr(C)] -pub struct WSANETWORKEVENTS { - pub lNetworkEvents: libc::c_long, - pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS], -} - -pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; - -pub type WSAEVENT = libc::HANDLE; - -#[repr(C)] -pub struct fd_set { - fd_count: libc::c_uint, - fd_array: [libc::SOCKET, ..FD_SETSIZE], -} - -pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) { - set.fd_array[set.fd_count as uint] = s; - set.fd_count += 1; -} - -#[link(name = "ws2_32")] -extern "system" { - pub fn WSAStartup(wVersionRequested: libc::WORD, - lpWSAData: LPWSADATA) -> libc::c_int; - pub fn WSAGetLastError() -> libc::c_int; - pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; - pub fn WSACreateEvent() -> WSAEVENT; - pub fn WSAEventSelect(s: libc::SOCKET, - hEventObject: WSAEVENT, - lNetworkEvents: libc::c_long) -> libc::c_int; - pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL; - pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD, - lphEvents: *const WSAEVENT, - fWaitAll: libc::BOOL, - dwTimeout: libc::DWORD, - fAltertable: libc::BOOL) -> libc::DWORD; - pub fn WSAEnumNetworkEvents(s: libc::SOCKET, - hEventObject: WSAEVENT, - lpNetworkEvents: LPWSANETWORKEVENTS) - -> libc::c_int; - - pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, - argp: *mut libc::c_ulong) -> libc::c_int; - pub fn select(nfds: libc::c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *mut libc::timeval) -> libc::c_int; - pub fn getsockopt(sockfd: libc::SOCKET, - level: libc::c_int, - optname: libc::c_int, - optval: *mut libc::c_char, - optlen: *mut libc::c_int) -> libc::c_int; - - pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL; - pub fn WaitForMultipleObjects(nCount: libc::DWORD, - lpHandles: *const libc::HANDLE, - bWaitAll: libc::BOOL, - dwMilliseconds: libc::DWORD) -> libc::DWORD; - - pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; - pub fn CancelIoEx(hFile: libc::HANDLE, - lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; -} - -pub mod compat { - use intrinsics::{atomic_store_relaxed, transmute}; - use iter::Iterator; - use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; - use prelude::*; - - extern "system" { - fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; - } - - // store_func() is idempotent, so using relaxed ordering for the atomics - // should be enough. This way, calling a function in this compatibility - // layer (after it's loaded) shouldn't be any slower than a regular DLL - // call. - unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { - let mut module: Vec = module.utf16_units().collect(); - module.push(0); - symbol.with_c_str(|symbol| { - let handle = GetModuleHandleW(module.as_ptr()); - let func: uint = transmute(GetProcAddress(handle, symbol)); - atomic_store_relaxed(ptr, if func == 0 { - fallback - } else { - func - }) - }) - } - - /// Macro for creating a compatibility fallback for a Windows function - /// - /// # Example - /// ``` - /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { - /// // Fallback implementation - /// }) - /// ``` - /// - /// Note that arguments unused by the fallback implementation should not be called `_` as - /// they are used to be passed to the real function if available. - macro_rules! compat_fn( - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty $fallback:block) => ( - #[inline(always)] - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { - static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; - - extern "system" fn thunk($($argname: $argtype),*) -> $rettype { - unsafe { - ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint, - stringify!($module), - stringify!($symbol), - fallback as uint); - ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) - } - } - - extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback - - ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) - } - ); - - ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( - compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) - ) - ) - - /// Compatibility layer for functions in `kernel32.dll` - /// - /// Latest versions of Windows this is needed for: - /// - /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 - /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 - pub mod kernel32 { - use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; - use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; - - extern "system" { - fn SetLastError(dwErrCode: DWORD); - } - - compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, - _lpTargetFileName: LPCWSTR, - _dwFlags: DWORD) -> BOOLEAN { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } - 0 - }) - - compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } - 0 - }) - } -} - -extern "system" { - // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL - pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, - lpBuffer: libc::LPVOID, - nNumberOfCharsToRead: libc::DWORD, - lpNumberOfCharsRead: libc::LPDWORD, - pInputControl: libc::LPVOID) -> libc::BOOL; - - pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE, - lpBuffer: libc::types::os::arch::extra::LPCVOID, - nNumberOfCharsToWrite: libc::DWORD, - lpNumberOfCharsWritten: libc::LPDWORD, - lpReserved: libc::LPVOID) -> libc::BOOL; - - pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE, - lpMode: libc::LPDWORD) -> libc::BOOL; - - pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE, - lpMode: libc::DWORD) -> libc::BOOL; -} diff --git a/src/libst2/sys/windows/fs.rs b/src/libst2/sys/windows/fs.rs deleted file mode 100644 index b881eb2d4955c..0000000000000 --- a/src/libst2/sys/windows/fs.rs +++ /dev/null @@ -1,460 +0,0 @@ -// 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. - -//! Blocking Windows-based file I/O - -use alloc::arc::Arc; -use libc::{mod, c_int}; - -use c_str::CString; -use mem; -use os::windows::fill_utf16_buf_and_decode; -use path; -use ptr; -use str; -use io; - -use prelude::*; -use sys; -use sys_common::{keep_going, eof, mkerr_libc}; - -use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; -use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; -use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; - -pub use path::WindowsPath as Path; -pub type fd_t = libc::c_int; - -pub struct FileDesc { - /// The underlying C file descriptor. - pub fd: fd_t, - - /// Whether to close the file descriptor on drop. - close_on_drop: bool, -} - -impl FileDesc { - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { fd: fd, close_on_drop: close_on_drop } - } - - pub fn read(&self, buf: &mut [u8]) -> IoResult { - let mut read = 0; - let ret = unsafe { - libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut read, - ptr::null_mut()) - }; - if ret != 0 { - Ok(read as uint) - } else { - Err(super::last_error()) - } - } - - pub fn write(&self, buf: &[u8]) -> IoResult<()> { - let mut cur = buf.as_ptr(); - let mut remaining = buf.len(); - while remaining > 0 { - let mut amt = 0; - let ret = unsafe { - libc::WriteFile(self.handle(), cur as libc::LPVOID, - remaining as libc::DWORD, &mut amt, - ptr::null_mut()) - }; - if ret != 0 { - remaining -= amt as uint; - cur = unsafe { cur.offset(amt as int) }; - } else { - return Err(super::last_error()) - } - } - Ok(()) - } - - pub fn fd(&self) -> fd_t { self.fd } - - pub fn handle(&self) -> libc::HANDLE { - unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE } - } - - // A version of seek that takes &self so that tell can call it - // - the private seek should of course take &mut self. - fn seek_common(&self, pos: i64, style: SeekStyle) -> IoResult { - let whence = match style { - SeekSet => libc::FILE_BEGIN, - SeekEnd => libc::FILE_END, - SeekCur => libc::FILE_CURRENT, - }; - unsafe { - let mut newpos = 0; - match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, whence) { - 0 => Err(super::last_error()), - _ => Ok(newpos as u64), - } - } - } - - pub fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult { - self.seek_common(pos, style) - } - - pub fn tell(&self) -> IoResult { - self.seek_common(0, SeekCur) - } - - pub fn fsync(&mut self) -> IoResult<()> { - super::mkerr_winbool(unsafe { - libc::FlushFileBuffers(self.handle()) - }) - } - - pub fn datasync(&mut self) -> IoResult<()> { return self.fsync(); } - - pub fn truncate(&mut self, offset: i64) -> IoResult<()> { - let orig_pos = try!(self.tell()); - let _ = try!(self.seek(offset, SeekSet)); - let ret = unsafe { - match libc::SetEndOfFile(self.handle()) { - 0 => Err(super::last_error()), - _ => Ok(()) - } - }; - let _ = self.seek(orig_pos as i64, SeekSet); - return ret; - } - - pub fn fstat(&mut self) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::fstat(self.fd(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - } - - /// Extract the actual filedescriptor without closing it. - pub fn unwrap(self) -> fd_t { - let fd = self.fd; - unsafe { mem::forget(self) }; - fd - } -} - -impl Drop for FileDesc { - 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 - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.close_on_drop && self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, self.fd); - } - } - } -} - -pub fn to_utf16(s: &Path) -> IoResult> { - sys::to_utf16(s.as_str()) -} - -pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult { - // Flags passed to open_osfhandle - let flags = match fm { - Open => 0, - Append => libc::O_APPEND, - Truncate => libc::O_TRUNC, - }; - let flags = match fa { - Read => flags | libc::O_RDONLY, - Write => flags | libc::O_WRONLY | libc::O_CREAT, - ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, - }; - let mut dwDesiredAccess = match fa { - Read => libc::FILE_GENERIC_READ, - Write => libc::FILE_GENERIC_WRITE, - ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE - }; - - // libuv has a good comment about this, but the basic idea is what we try to - // emulate unix semantics by enabling all sharing by allowing things such as - // deleting a file while it's still open. - let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE | - libc::FILE_SHARE_DELETE; - - let dwCreationDisposition = match (fm, fa) { - (Truncate, Read) => libc::TRUNCATE_EXISTING, - (Truncate, _) => libc::CREATE_ALWAYS, - (Open, Read) => libc::OPEN_EXISTING, - (Open, _) => libc::OPEN_ALWAYS, - (Append, Read) => { - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_EXISTING - } - (Append, _) => { - dwDesiredAccess &= !libc::FILE_WRITE_DATA; - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_ALWAYS - } - }; - - let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL; - // Compat with unix, this allows opening directories (see libuv) - dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS; - - let path = try!(to_utf16(path)); - let handle = unsafe { - libc::CreateFileW(path.as_ptr(), - dwDesiredAccess, - dwShareMode, - ptr::null_mut(), - dwCreationDisposition, - dwFlagsAndAttributes, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - Err(super::last_error()) - } else { - let fd = unsafe { - libc::open_osfhandle(handle as libc::intptr_t, flags) - }; - if fd < 0 { - let _ = unsafe { libc::CloseHandle(handle) }; - Err(super::last_error()) - } else { - Ok(FileDesc::new(fd, true)) - } - } -} - -pub fn mkdir(p: &Path, _mode: uint) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_winbool(unsafe { - // FIXME: turn mode into something useful? #2623 - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - }) -} - -pub fn readdir(p: &Path) -> IoResult> { - fn prune(root: &Path, dirs: Vec) -> Vec { - dirs.into_iter().filter(|path| { - path.as_vec() != b"." && path.as_vec() != b".." - }).map(|path| root.join(path)).collect() - } - - let star = p.join("*"); - let path = try!(to_utf16(&star)); - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != libc::INVALID_HANDLE_VALUE { - let mut paths = vec![]; - let mut more_files = 1 as libc::BOOL; - while more_files != 0 { - { - let filename = str::truncate_utf16_at_nul(&wfd.cFileName); - match String::from_utf16(filename) { - Some(filename) => paths.push(Path::new(filename)), - None => { - assert!(libc::FindClose(find_handle) != 0); - return Err(IoError { - kind: io::InvalidInput, - desc: "path was not valid UTF-16", - detail: Some(format!("path was not valid UTF-16: {}", filename)), - }) - }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring - } - } - more_files = libc::FindNextFileW(find_handle, &mut wfd); - } - assert!(libc::FindClose(find_handle) != 0); - Ok(prune(p, paths)) - } else { - Err(super::last_error()) - } - } -} - -pub fn unlink(p: &Path) -> IoResult<()> { - fn do_unlink(p_utf16: &Vec) -> IoResult<()> { - super::mkerr_winbool(unsafe { libc::DeleteFileW(p_utf16.as_ptr()) }) - } - - let p_utf16 = try!(to_utf16(p)); - let res = do_unlink(&p_utf16); - match res { - Ok(()) => Ok(()), - Err(e) => { - // FIXME: change the code below to use more direct calls - // than `stat` and `chmod`, to avoid re-conversion to - // utf16 etc. - - // On unix, a readonly file can be successfully removed. On windows, - // however, it cannot. To keep the two platforms in line with - // respect to their behavior, catch this case on windows, attempt to - // change it to read-write, and then remove the file. - if e.kind == io::PermissionDenied { - let stat = match stat(p) { - Ok(stat) => stat, - Err(..) => return Err(e), - }; - if stat.perm.intersects(io::USER_WRITE) { return Err(e) } - - match chmod(p, (stat.perm | io::USER_WRITE).bits() as uint) { - Ok(()) => do_unlink(&p_utf16), - Err(..) => { - // Try to put it back as we found it - let _ = chmod(p, stat.perm.bits() as uint); - Err(e) - } - } - } else { - Err(e) - } - } - } -} - -pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = try!(to_utf16(old)); - let new = try!(to_utf16(new)); - super::mkerr_winbool(unsafe { - libc::MoveFileExW(old.as_ptr(), new.as_ptr(), libc::MOVEFILE_REPLACE_EXISTING) - }) -} - -pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = try!(to_utf16(p)); - mkerr_libc(unsafe { - libc::wchmod(p.as_ptr(), mode as libc::c_int) - }) -} - -pub fn rmdir(p: &Path) -> IoResult<()> { - let p = try!(to_utf16(p)); - mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) }) -} - -pub fn chown(_p: &Path, _uid: int, _gid: int) -> IoResult<()> { - // libuv has this as a no-op, so seems like this should as well? - Ok(()) -} - -pub fn readlink(p: &Path) -> IoResult { - // FIXME: I have a feeling that this reads intermediate symlinks as well. - use sys::c::compat::kernel32::GetFinalPathNameByHandleW; - let p = try!(to_utf16(p)); - let handle = unsafe { - libc::CreateFileW(p.as_ptr(), - libc::GENERIC_READ, - libc::FILE_SHARE_READ, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_ATTRIBUTE_NORMAL, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - // Specify (sz - 1) because the documentation states that it's the size - // without the null pointer - let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe { - GetFinalPathNameByHandleW(handle, - buf as *const u16, - sz - 1, - libc::VOLUME_NAME_DOS) - }); - let ret = match ret { - Some(ref s) if s.as_slice().starts_with(r"\\?\") => { // " - Ok(Path::new(s.as_slice().slice_from(4))) - } - Some(s) => Ok(Path::new(s)), - None => Err(super::last_error()), - }; - assert!(unsafe { libc::CloseHandle(handle) } != 0); - return ret; -} - -pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - use sys::c::compat::kernel32::CreateSymbolicLinkW; - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL - }) -} - -pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) - }) -} - -fn mkstat(stat: &libc::stat) -> FileStat { - FileStat { - size: stat.st_size as u64, - kind: match (stat.st_mode as libc::c_int) & libc::S_IFMT { - libc::S_IFREG => io::TypeFile, - libc::S_IFDIR => io::TypeDirectory, - libc::S_IFIFO => io::TypeNamedPipe, - libc::S_IFBLK => io::TypeBlockSpecial, - libc::S_IFLNK => io::TypeSymlink, - _ => io::TypeUnknown, - }, - perm: FilePermission::from_bits_truncate(stat.st_mode as u32), - created: stat.st_ctime as u64, - modified: stat.st_mtime as u64, - accessed: stat.st_atime as u64, - unstable: UnstableFileStat { - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize:0, - blocks: 0, - flags: 0, - gen: 0, - }, - } -} - -pub fn stat(p: &Path) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - let p = try!(to_utf16(p)); - match unsafe { libc::wstat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -// FIXME: move this to platform-specific modules (for now)? -pub fn lstat(_p: &Path) -> IoResult { - // FIXME: implementation is missing - Err(super::unimpl()) -} - -pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let mut buf = libc::utimbuf { - actime: atime as libc::time64_t, - modtime: mtime as libc::time64_t, - }; - let p = try!(to_utf16(p)); - mkerr_libc(unsafe { - libc::wutime(p.as_ptr(), &mut buf) - }) -} diff --git a/src/libst2/sys/windows/helper_signal.rs b/src/libst2/sys/windows/helper_signal.rs deleted file mode 100644 index c547c79e83a13..0000000000000 --- a/src/libst2/sys/windows/helper_signal.rs +++ /dev/null @@ -1,38 +0,0 @@ -// 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. - -use libc::{mod, BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle}; -use ptr; - -pub type signal = HANDLE; - -pub fn new() -> (HANDLE, HANDLE) { - unsafe { - let handle = CreateEventA(ptr::null_mut(), libc::FALSE, libc::FALSE, - ptr::null()); - (handle, handle) - } -} - -pub fn signal(handle: HANDLE) { - assert!(unsafe { SetEvent(handle) != 0 }); -} - -pub fn close(handle: HANDLE) { - assert!(unsafe { CloseHandle(handle) != 0 }); -} - -extern "system" { - fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - bInitialState: BOOL, - lpName: LPCSTR) -> HANDLE; - fn SetEvent(hEvent: HANDLE) -> BOOL; -} diff --git a/src/libst2/sys/windows/mod.rs b/src/libst2/sys/windows/mod.rs deleted file mode 100644 index b627ab0f7c747..0000000000000 --- a/src/libst2/sys/windows/mod.rs +++ /dev/null @@ -1,85 +0,0 @@ -// 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. - -#![allow(missing_docs)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] - -extern crate libc; - -use num; -use mem; -use prelude::*; -use io::{mod, IoResult, IoError}; -use sync::{Once, ONCE_INIT}; - -macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::rustrt::mutex::NATIVE_MUTEX_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - }; -) ) - -pub mod c; -pub mod fs; -pub mod helper_signal; -pub mod os; -pub mod pipe; -pub mod process; -pub mod tcp; -pub mod thread_local; -pub mod timer; -pub mod tty; -pub mod udp; - -pub mod addrinfo { - pub use sys_common::net::get_host_addresses; -} - -// FIXME: move these to c module -pub type sock_t = libc::SOCKET; -pub type wrlen = libc::c_int; -pub type msglen_t = libc::c_int; -pub unsafe fn close_sock(sock: sock_t) { unimplemented!() } - -// windows has zero values as errors -fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { unimplemented!() } - -pub fn last_error() -> IoError { unimplemented!() } - -pub fn last_net_error() -> IoError { unimplemented!() } - -pub fn last_gai_error(_errno: i32) -> IoError { unimplemented!() } - -/// Convert an `errno` value into a high-level error variant and description. -pub fn decode_error(errno: i32) -> IoError { unimplemented!() } - -pub fn decode_error_detailed(errno: i32) -> IoError { unimplemented!() } - -#[inline] -pub fn retry (f: || -> I) -> I { unimplemented!() } // PR rust-lang/rust/#17020 - -pub fn ms_to_timeval(ms: u64) -> libc::timeval { unimplemented!() } - -pub fn wouldblock() -> bool { unimplemented!() } - -pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { unimplemented!() } - -pub fn init_net() { unimplemented!() } - -pub fn unimpl() -> IoError { unimplemented!() } - -pub fn to_utf16(s: Option<&str>) -> IoResult> { unimplemented!() } diff --git a/src/libst2/sys/windows/os.rs b/src/libst2/sys/windows/os.rs deleted file mode 100644 index aa43b42e74643..0000000000000 --- a/src/libst2/sys/windows/os.rs +++ /dev/null @@ -1,103 +0,0 @@ -// 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. - -// FIXME: move various extern bindings from here into liblibc or -// something similar - -use libc; -use libc::{c_int, c_char, c_void}; -use prelude::*; -use io::{IoResult, IoError}; -use sys::fs::FileDesc; -use ptr; - -use os::TMPBUF_SZ; - -pub fn errno() -> uint { - use libc::types::os::arch::extra::DWORD; - - #[link_name = "kernel32"] - extern "system" { - fn GetLastError() -> DWORD; - } - - unsafe { - GetLastError() as uint - } -} - -/// Get a detailed string description for the given error number -pub fn error_string(errnum: i32) -> String { - use libc::types::os::arch::extra::DWORD; - use libc::types::os::arch::extra::LPWSTR; - use libc::types::os::arch::extra::LPVOID; - use libc::types::os::arch::extra::WCHAR; - - #[link_name = "kernel32"] - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void) - -> DWORD; - } - - static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; - static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as DWORD; - - let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; - - unsafe { - let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::null_mut(), - errnum as DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as DWORD, - ptr::null()); - if res == 0 { - // Sometimes FormatMessageW can fail e.g. system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); - } - - let msg = String::from_utf16(::str::truncate_utf16_at_nul(&buf)); - match msg { - Some(msg) => format!("OS Error {}: {}", errnum, msg), - None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), - } - } -} - -pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { - // Windows pipes work subtly differently than unix pipes, and their - // inheritance has to be handled in a different way that I do not - // fully understand. Here we explicitly make the pipe non-inheritable, - // which means to pass it to a subprocess they need to be duplicated - // first, as in std::run. - let mut fds = [0, ..2]; - match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, - (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { - 0 => { - assert!(fds[0] != -1 && fds[0] != 0); - assert!(fds[1] != -1 && fds[1] != 0); - Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) - } - _ => Err(IoError::last_error()), - } -} diff --git a/src/libst2/sys/windows/pipe.rs b/src/libst2/sys/windows/pipe.rs deleted file mode 100644 index a623c2cd8e297..0000000000000 --- a/src/libst2/sys/windows/pipe.rs +++ /dev/null @@ -1,751 +0,0 @@ -// 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. - -//! Named pipes implementation for windows -//! -//! If are unfortunate enough to be reading this code, I would like to first -//! apologize. This was my first encounter with windows named pipes, and it -//! didn't exactly turn out very cleanly. If you, too, are new to named pipes, -//! read on as I'll try to explain some fun things that I ran into. -//! -//! # Unix pipes vs Named pipes -//! -//! As with everything else, named pipes on windows are pretty different from -//! unix pipes on unix. On unix, you use one "server pipe" to accept new client -//! pipes. So long as this server pipe is active, new children pipes can -//! connect. On windows, you instead have a number of "server pipes", and each -//! of these server pipes can throughout their lifetime be attached to a client -//! or not. Once attached to a client, a server pipe may then disconnect at a -//! later date. -//! -//! # Accepting clients -//! -//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces -//! are built around the unix flavors. This means that we have one "server -//! pipe" to which many clients can connect. In order to make this compatible -//! with the windows model, each connected client consumes ownership of a server -//! pipe, and then a new server pipe is created for the next client. -//! -//! Note that the server pipes attached to clients are never given back to the -//! listener for recycling. This could possibly be implemented with a channel so -//! the listener half can re-use server pipes, but for now I err'd on the simple -//! side of things. Each stream accepted by a listener will destroy the server -//! pipe after the stream is dropped. -//! -//! This model ends up having a small race or two, and you can find more details -//! on the `native_accept` method. -//! -//! # Simultaneous reads and writes -//! -//! In testing, I found that two simultaneous writes and two simultaneous reads -//! on a pipe ended up working out just fine, but problems were encountered when -//! a read was executed simultaneously with a write. After some googling around, -//! it sounded like named pipes just weren't built for this kind of interaction, -//! and the suggested solution was to use overlapped I/O. -//! -//! I don't really know what overlapped I/O is, but my basic understanding after -//! reading about it is that you have an external Event which is used to signal -//! I/O completion, passed around in some OVERLAPPED structures. As to what this -//! is, I'm not exactly sure. -//! -//! This problem implies that all named pipes are created with the -//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is -//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and -//! inside of this structure is a HANDLE from CreateEvent. After the I/O is -//! determined to be pending (may complete in the future), the -//! GetOverlappedResult function is used to block on the event, waiting for the -//! I/O to finish. -//! -//! This scheme ended up working well enough. There were two snags that I ran -//! into, however: -//! -//! * Each UnixStream instance needs its own read/write events to wait on. These -//! can't be shared among clones of the same stream because the documentation -//! states that it unsets the event when the I/O is started (would possibly -//! corrupt other events simultaneously waiting). For convenience's sake, -//! these events are lazily initialized. -//! -//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition -//! to all pipes created through `connect`. Notably this means that the -//! ConnectNamedPipe function is nonblocking, implying that the Listener needs -//! to have yet another event to do the actual blocking. -//! -//! # Conclusion -//! -//! The conclusion here is that I probably don't know the best way to work with -//! windows named pipes, but the solution here seems to work well enough to get -//! the test suite passing (the suite is in libstd), and that's good enough for -//! me! - -use alloc::arc::Arc; -use libc; -use c_str::CString; -use mem; -use ptr; -use sync::atomic; -use rustrt::mutex; -use io::{mod, IoError, IoResult}; -use prelude::*; - -use sys_common::{mod, eof}; - -use super::{c, os, timer, to_utf16, decode_error_detailed}; - -struct Event(libc::HANDLE); - -impl Event { - fn new(manual_reset: bool, initial_state: bool) -> IoResult { - let event = unsafe { - libc::CreateEventW(ptr::null_mut(), - manual_reset as libc::BOOL, - initial_state as libc::BOOL, - ptr::null()) - }; - if event as uint == 0 { - Err(super::last_error()) - } else { - Ok(Event(event)) - } - } - - fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle } -} - -impl Drop for Event { - fn drop(&mut self) { - unsafe { let _ = libc::CloseHandle(self.handle()); } - } -} - -struct Inner { - handle: libc::HANDLE, - lock: mutex::NativeMutex, - read_closed: atomic::AtomicBool, - write_closed: atomic::AtomicBool, -} - -impl Inner { - fn new(handle: libc::HANDLE) -> Inner { - Inner { - handle: handle, - lock: unsafe { mutex::NativeMutex::new() }, - read_closed: atomic::AtomicBool::new(false), - write_closed: atomic::AtomicBool::new(false), - } - } -} - -impl Drop for Inner { - fn drop(&mut self) { - unsafe { - let _ = libc::FlushFileBuffers(self.handle); - let _ = libc::CloseHandle(self.handle); - } - } -} - -unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE { - libc::CreateNamedPipeW( - name, - libc::PIPE_ACCESS_DUPLEX | - if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} | - libc::FILE_FLAG_OVERLAPPED, - libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE | - libc::PIPE_WAIT, - libc::PIPE_UNLIMITED_INSTANCES, - 65536, - 65536, - 0, - ptr::null_mut() - ) -} - -pub fn await(handle: libc::HANDLE, deadline: u64, - events: &[libc::HANDLE]) -> IoResult { - use libc::consts::os::extra::{WAIT_FAILED, WAIT_TIMEOUT, WAIT_OBJECT_0}; - - // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo - // to figure out if we should indeed get the result. - let ms = if deadline == 0 { - libc::INFINITE as u64 - } else { - let now = timer::now(); - if deadline < now {0} else {deadline - now} - }; - let ret = unsafe { - c::WaitForMultipleObjects(events.len() as libc::DWORD, - events.as_ptr(), - libc::FALSE, - ms as libc::DWORD) - }; - match ret { - WAIT_FAILED => Err(super::last_error()), - WAIT_TIMEOUT => unsafe { - let _ = c::CancelIo(handle); - Err(sys_common::timeout("operation timed out")) - }, - n => Ok((n - WAIT_OBJECT_0) as uint) - } -} - -fn epipe() -> IoError { - IoError { - kind: io::EndOfFile, - desc: "the pipe has ended", - detail: None, - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Streams -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixStream { - inner: Arc, - write: Option, - read: Option, - read_deadline: u64, - write_deadline: u64, -} - -impl UnixStream { - fn try_connect(p: *const u16) -> Option { - // Note that most of this is lifted from the libuv implementation. - // The idea is that if we fail to open a pipe in read/write mode - // that we try afterwards in just read or just write - let mut result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_READ | libc::GENERIC_WRITE, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - - let err = unsafe { libc::GetLastError() }; - if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { - result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - } - let err = unsafe { libc::GetLastError() }; - if err == libc::ERROR_ACCESS_DENIED as libc::DWORD { - result = unsafe { - libc::CreateFileW(p, - libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES, - 0, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_FLAG_OVERLAPPED, - ptr::null_mut()) - }; - if result != libc::INVALID_HANDLE_VALUE { - return Some(result) - } - } - None - } - - pub fn connect(addr: &CString, timeout: Option) -> IoResult { - let addr = try!(to_utf16(addr.as_str())); - let start = timer::now(); - loop { - match UnixStream::try_connect(addr.as_ptr()) { - Some(handle) => { - let inner = Inner::new(handle); - let mut mode = libc::PIPE_TYPE_BYTE | - libc::PIPE_READMODE_BYTE | - libc::PIPE_WAIT; - let ret = unsafe { - libc::SetNamedPipeHandleState(inner.handle, - &mut mode, - ptr::null_mut(), - ptr::null_mut()) - }; - return if ret == 0 { - Err(super::last_error()) - } else { - Ok(UnixStream { - inner: Arc::new(inner), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - }) - } - } - None => {} - } - - // On windows, if you fail to connect, you may need to call the - // `WaitNamedPipe` function, and this is indicated with an error - // code of ERROR_PIPE_BUSY. - let code = unsafe { libc::GetLastError() }; - if code as int != libc::ERROR_PIPE_BUSY as int { - return Err(super::last_error()) - } - - match timeout { - Some(timeout) => { - let now = timer::now(); - let timed_out = (now - start) >= timeout || unsafe { - let ms = (timeout - (now - start)) as libc::DWORD; - libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0 - }; - if timed_out { - return Err(sys_common::timeout("connect timed out")) - } - } - - // An example I found on Microsoft's website used 20 - // seconds, libuv uses 30 seconds, hence we make the - // obvious choice of waiting for 25 seconds. - None => { - if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 { - return Err(super::last_error()) - } - } - } - } - } - - fn handle(&self) -> libc::HANDLE { self.inner.handle } - - fn read_closed(&self) -> bool { - self.inner.read_closed.load(atomic::SeqCst) - } - - fn write_closed(&self) -> bool { - self.inner.write_closed.load(atomic::SeqCst) - } - - fn cancel_io(&self) -> IoResult<()> { - match unsafe { c::CancelIoEx(self.handle(), ptr::null_mut()) } { - 0 if os::errno() == libc::ERROR_NOT_FOUND as uint => { - Ok(()) - } - 0 => Err(super::last_error()), - _ => Ok(()) - } - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - if self.read.is_none() { - self.read = Some(try!(Event::new(true, false))); - } - - let mut bytes_read = 0; - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.read.as_ref().unwrap().handle(); - - // Pre-flight check to see if the reading half has been closed. This - // must be done before issuing the ReadFile request, but after we - // acquire the lock. - // - // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; - if self.read_closed() { - return Err(eof()) - } - - // Issue a nonblocking requests, succeeding quickly if it happened to - // succeed. - let ret = unsafe { - libc::ReadFile(self.handle(), - buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, - &mut bytes_read, - &mut overlapped) - }; - if ret != 0 { return Ok(bytes_read as uint) } - - // If our errno doesn't say that the I/O is pending, then we hit some - // legitimate error and return immediately. - if os::errno() != libc::ERROR_IO_PENDING as uint { - return Err(super::last_error()) - } - - // Now that we've issued a successful nonblocking request, we need to - // wait for it to finish. This can all be done outside the lock because - // we'll see any invocation of CancelIoEx. We also call this in a loop - // because we're woken up if the writing half is closed, we just need to - // realize that the reading half wasn't closed and we go right back to - // sleep. - drop(guard); - loop { - // Process a timeout if one is pending - let wait_succeeded = await(self.handle(), self.read_deadline, - &[overlapped.hEvent]); - - let ret = unsafe { - libc::GetOverlappedResult(self.handle(), - &mut overlapped, - &mut bytes_read, - libc::TRUE) - }; - // If we succeeded, or we failed for some reason other than - // CancelIoEx, return immediately - if ret != 0 { return Ok(bytes_read as uint) } - if os::errno() != libc::ERROR_OPERATION_ABORTED as uint { - return Err(super::last_error()) - } - - // If the reading half is now closed, then we're done. If we woke up - // because the writing half was closed, keep trying. - if wait_succeeded.is_err() { - return Err(sys_common::timeout("read timed out")) - } - if self.read_closed() { - return Err(eof()) - } - } - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - if self.write.is_none() { - self.write = Some(try!(Event::new(true, false))); - } - - let mut offset = 0; - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.write.as_ref().unwrap().handle(); - - while offset < buf.len() { - let mut bytes_written = 0; - - // This sequence below is quite similar to the one found in read(). - // Some careful looping is done to ensure that if close_write() is - // invoked we bail out early, and if close_read() is invoked we keep - // going after we woke up. - // - // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; - if self.write_closed() { - return Err(epipe()) - } - let ret = unsafe { - libc::WriteFile(self.handle(), - buf[offset..].as_ptr() as libc::LPVOID, - (buf.len() - offset) as libc::DWORD, - &mut bytes_written, - &mut overlapped) - }; - let err = os::errno(); - drop(guard); - - if ret == 0 { - if err != libc::ERROR_IO_PENDING as uint { - return Err(decode_error_detailed(err as i32)) - } - // Process a timeout if one is pending - let wait_succeeded = await(self.handle(), self.write_deadline, - &[overlapped.hEvent]); - let ret = unsafe { - libc::GetOverlappedResult(self.handle(), - &mut overlapped, - &mut bytes_written, - libc::TRUE) - }; - // If we weren't aborted, this was a legit error, if we were - // aborted, then check to see if the write half was actually - // closed or whether we woke up from the read half closing. - if ret == 0 { - if os::errno() != libc::ERROR_OPERATION_ABORTED as uint { - return Err(super::last_error()) - } - if !wait_succeeded.is_ok() { - let amt = offset + bytes_written as uint; - return if amt > 0 { - Err(IoError { - kind: io::ShortWrite(amt), - desc: "short write during write", - detail: None, - }) - } else { - Err(sys_common::timeout("write timed out")) - } - } - if self.write_closed() { - return Err(epipe()) - } - continue // retry - } - } - offset += bytes_written as uint; - } - Ok(()) - } - - pub fn close_read(&mut self) -> IoResult<()> { - // On windows, there's no actual shutdown() method for pipes, so we're - // forced to emulate the behavior manually at the application level. To - // do this, we need to both cancel any pending requests, as well as - // prevent all future requests from succeeding. These two operations are - // not atomic with respect to one another, so we must use a lock to do - // so. - // - // The read() code looks like: - // - // 1. Make sure the pipe is still open - // 2. Submit a read request - // 3. Wait for the read request to finish - // - // The race this lock is preventing is if another thread invokes - // close_read() between steps 1 and 2. By atomically executing steps 1 - // and 2 with a lock with respect to close_read(), we're guaranteed that - // no thread will erroneously sit in a read forever. - let _guard = unsafe { self.inner.lock.lock() }; - self.inner.read_closed.store(true, atomic::SeqCst); - self.cancel_io() - } - - pub fn close_write(&mut self) -> IoResult<()> { - // see comments in close_read() for why this lock is necessary - let _guard = unsafe { self.inner.lock.lock() }; - self.inner.write_closed.store(true, atomic::SeqCst); - self.cancel_io() - } - - pub fn set_timeout(&mut self, timeout: Option) { - let deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - self.read_deadline = deadline; - self.write_deadline = deadline; - } - pub fn set_read_timeout(&mut self, timeout: Option) { - self.read_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - pub fn set_write_timeout(&mut self, timeout: Option) { - self.write_deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } -} - -impl Clone for UnixStream { - fn clone(&self) -> UnixStream { - UnixStream { - inner: self.inner.clone(), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Unix Listener -//////////////////////////////////////////////////////////////////////////////// - -pub struct UnixListener { - handle: libc::HANDLE, - name: CString, -} - -impl UnixListener { - pub fn bind(addr: &CString) -> IoResult { - // Although we technically don't need the pipe until much later, we - // create the initial handle up front to test the validity of the name - // and such. - let addr_v = try!(to_utf16(addr.as_str())); - let ret = unsafe { pipe(addr_v.as_ptr(), true) }; - if ret == libc::INVALID_HANDLE_VALUE { - Err(super::last_error()) - } else { - Ok(UnixListener { handle: ret, name: addr.clone() }) - } - } - - pub fn listen(self) -> IoResult { - Ok(UnixAcceptor { - listener: self, - event: try!(Event::new(true, false)), - deadline: 0, - inner: Arc::new(AcceptorState { - abort: try!(Event::new(true, false)), - closed: atomic::AtomicBool::new(false), - }), - }) - } -} - -impl Drop for UnixListener { - fn drop(&mut self) { - unsafe { let _ = libc::CloseHandle(self.handle); } - } -} - -pub struct UnixAcceptor { - inner: Arc, - listener: UnixListener, - event: Event, - deadline: u64, -} - -struct AcceptorState { - abort: Event, - closed: atomic::AtomicBool, -} - -impl UnixAcceptor { - pub fn accept(&mut self) -> IoResult { - // This function has some funky implementation details when working with - // unix pipes. On windows, each server named pipe handle can be - // connected to a one or zero clients. To the best of my knowledge, a - // named server is considered active and present if there exists at - // least one server named pipe for it. - // - // The model of this function is to take the current known server - // handle, connect a client to it, and then transfer ownership to the - // UnixStream instance. The next time accept() is invoked, it'll need a - // different server handle to connect a client to. - // - // Note that there is a possible race here. Once our server pipe is - // handed off to a `UnixStream` object, the stream could be closed, - // meaning that there would be no active server pipes, hence even though - // we have a valid `UnixAcceptor`, no one can connect to it. For this - // reason, we generate the next accept call's server pipe at the end of - // this function call. - // - // This provides us an invariant that we always have at least one server - // connection open at a time, meaning that all connects to this acceptor - // should succeed while this is active. - // - // The actual implementation of doing this is a little tricky. Once a - // server pipe is created, a client can connect to it at any time. I - // assume that which server a client connects to is nondeterministic, so - // we also need to guarantee that the only server able to be connected - // to is the one that we're calling ConnectNamedPipe on. This means that - // we have to create the second server pipe *after* we've already - // accepted a connection. In order to at least somewhat gracefully - // handle errors, this means that if the second server pipe creation - // fails that we disconnect the connected client and then just keep - // using the original server pipe. - let handle = self.listener.handle; - - // If we've had an artificial call to close_accept, be sure to never - // proceed in accepting new clients in the future - if self.inner.closed.load(atomic::SeqCst) { return Err(eof()) } - - let name = try!(to_utf16(self.listener.name.as_str())); - - // Once we've got a "server handle", we need to wait for a client to - // connect. The ConnectNamedPipe function will block this thread until - // someone on the other end connects. This function can "fail" if a - // client connects after we created the pipe but before we got down - // here. Thanks windows. - let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlapped.hEvent = self.event.handle(); - if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } { - let mut err = unsafe { libc::GetLastError() }; - - if err == libc::ERROR_IO_PENDING as libc::DWORD { - // Process a timeout if one is pending - let wait_succeeded = await(handle, self.deadline, - &[self.inner.abort.handle(), - overlapped.hEvent]); - - // This will block until the overlapped I/O is completed. The - // timeout was previously handled, so this will either block in - // the normal case or succeed very quickly in the timeout case. - let ret = unsafe { - let mut transfer = 0; - libc::GetOverlappedResult(handle, - &mut overlapped, - &mut transfer, - libc::TRUE) - }; - if ret == 0 { - if wait_succeeded.is_ok() { - err = unsafe { libc::GetLastError() }; - } else { - return Err(sys_common::timeout("accept timed out")) - } - } else { - // we succeeded, bypass the check below - err = libc::ERROR_PIPE_CONNECTED as libc::DWORD; - } - } - if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD { - return Err(super::last_error()) - } - } - - // Now that we've got a connected client to our handle, we need to - // create a second server pipe. If this fails, we disconnect the - // connected client and return an error (see comments above). - let new_handle = unsafe { pipe(name.as_ptr(), false) }; - if new_handle == libc::INVALID_HANDLE_VALUE { - let ret = Err(super::last_error()); - // If our disconnection fails, then there's not really a whole lot - // that we can do, so panic - let err = unsafe { libc::DisconnectNamedPipe(handle) }; - assert!(err != 0); - return ret; - } else { - self.listener.handle = new_handle; - } - - // Transfer ownership of our handle into this stream - Ok(UnixStream { - inner: Arc::new(Inner::new(handle)), - read: None, - write: None, - read_deadline: 0, - write_deadline: 0, - }) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|i| i + timer::now()).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, atomic::SeqCst); - let ret = unsafe { - c::SetEvent(self.inner.abort.handle()) - }; - if ret == 0 { - Err(super::last_error()) - } else { - Ok(()) - } - } -} - -impl Clone for UnixAcceptor { - fn clone(&self) -> UnixAcceptor { - let name = to_utf16(self.listener.name.as_str()).ok().unwrap(); - UnixAcceptor { - inner: self.inner.clone(), - event: Event::new(true, false).ok().unwrap(), - deadline: 0, - listener: UnixListener { - name: self.listener.name.clone(), - handle: unsafe { - let p = pipe(name.as_ptr(), false) ; - assert!(p != libc::INVALID_HANDLE_VALUE as libc::HANDLE); - p - }, - }, - } - } -} diff --git a/src/libst2/sys/windows/process.rs b/src/libst2/sys/windows/process.rs deleted file mode 100644 index 3fb5ee34356fe..0000000000000 --- a/src/libst2/sys/windows/process.rs +++ /dev/null @@ -1,511 +0,0 @@ -// 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. - -use libc::{pid_t, c_void, c_int}; -use libc; -use c_str::CString; -use io; -use mem; -use os; -use ptr; -use prelude::*; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use collections; -use path::BytesContainer; -use hash::Hash; -use io::{IoResult, IoError}; - -use sys::fs; -use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use sys_common::{AsFileDesc, mkerr_libc, timeout}; - -use io::fs::PathExtensions; -use string::String; - -pub use sys_common::ProcessConfig; - -/** - * A value representing a child process. - * - * The lifetime of this value is linked to the lifetime of the actual - * process - the Process destructor calls self.finish() which waits - * for the process to terminate. - */ -pub struct Process { - /// The unique id of the process (this should never be negative). - pid: pid_t, - - /// A HANDLE to the process, which will prevent the pid being - /// re-used until the handle is closed. - handle: *mut (), -} - -impl Drop for Process { - fn drop(&mut self) { - free_handle(self.handle); - } -} - -impl Process { - pub fn id(&self) -> pid_t { - self.pid - } - - pub unsafe fn kill(&self, signal: int) -> IoResult<()> { - Process::killpid(self.pid, signal) - } - - pub unsafe fn killpid(pid: pid_t, signal: int) -> IoResult<()> { - let handle = libc::OpenProcess(libc::PROCESS_TERMINATE | - libc::PROCESS_QUERY_INFORMATION, - libc::FALSE, pid as libc::DWORD); - if handle.is_null() { - return Err(super::last_error()) - } - let ret = match signal { - // test for existence on signal 0 - 0 => { - let mut status = 0; - let ret = libc::GetExitCodeProcess(handle, &mut status); - if ret == 0 { - Err(super::last_error()) - } else if status != libc::STILL_ACTIVE { - Err(IoError { - kind: io::InvalidInput, - desc: "no process to kill", - detail: None, - }) - } else { - Ok(()) - } - } - 15 | 9 => { // sigterm or sigkill - let ret = libc::TerminateProcess(handle, 1); - super::mkerr_winbool(ret) - } - _ => Err(IoError { - kind: io::IoUnavailable, - desc: "unsupported signal on windows", - detail: None, - }) - }; - let _ = libc::CloseHandle(handle); - return ret; - } - - pub fn spawn(cfg: &C, in_fd: Option

, - out_fd: Option

, err_fd: Option

) - -> IoResult - where C: ProcessConfig, P: AsFileDesc, - K: BytesContainer + Eq + Hash, V: BytesContainer - { - use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; - use libc::consts::os::extra::{ - TRUE, FALSE, - STARTF_USESTDHANDLES, - INVALID_HANDLE_VALUE, - DUPLICATE_SAME_ACCESS - }; - use libc::funcs::extra::kernel32::{ - GetCurrentProcess, - DuplicateHandle, - CloseHandle, - CreateProcessW - }; - use libc::funcs::extra::msvcrt::get_osfhandle; - - use mem; - use iter::Iterator; - use str::StrPrelude; - - if cfg.gid().is_some() || cfg.uid().is_some() { - return Err(IoError { - kind: io::IoUnavailable, - desc: "unsupported gid/uid requested on windows", - detail: None, - }) - } - - // To have the spawning semantics of unix/windows stay the same, we need to - // read the *child's* PATH if one is provided. See #15149 for more details. - let program = cfg.env().and_then(|env| { - for (key, v) in env.iter() { - if b"PATH" != key.container_as_bytes() { continue } - - // Split the value and test each path to see if the - // program exists. - for path in os::split_paths(v.container_as_bytes()).into_iter() { - let path = path.join(cfg.program().as_bytes_no_nul()) - .with_extension(os::consts::EXE_EXTENSION); - if path.exists() { - return Some(path.to_c_str()) - } - } - break - } - None - }); - - unsafe { - let mut si = zeroed_startupinfo(); - si.cb = mem::size_of::() as DWORD; - si.dwFlags = STARTF_USESTDHANDLES; - - let cur_proc = GetCurrentProcess(); - - // Similarly to unix, we don't actually leave holes for the stdio file - // descriptors, but rather open up /dev/null equivalents. These - // equivalents are drawn from libuv's windows process spawning. - let set_fd = |fd: &Option

, slot: &mut HANDLE, - is_stdin: bool| { - match *fd { - None => { - let access = if is_stdin { - libc::FILE_GENERIC_READ - } else { - libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES - }; - let size = mem::size_of::(); - let mut sa = libc::SECURITY_ATTRIBUTES { - nLength: size as libc::DWORD, - lpSecurityDescriptor: ptr::null_mut(), - bInheritHandle: 1, - }; - let mut filename: Vec = "NUL".utf16_units().collect(); - filename.push(0); - *slot = libc::CreateFileW(filename.as_ptr(), - access, - libc::FILE_SHARE_READ | - libc::FILE_SHARE_WRITE, - &mut sa, - libc::OPEN_EXISTING, - 0, - ptr::null_mut()); - if *slot == INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - } - Some(ref fd) => { - let orig = get_osfhandle(fd.as_fd().fd()) as HANDLE; - if orig == INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - if DuplicateHandle(cur_proc, orig, cur_proc, slot, - 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { - return Err(super::last_error()) - } - } - } - Ok(()) - }; - - try!(set_fd(&in_fd, &mut si.hStdInput, true)); - try!(set_fd(&out_fd, &mut si.hStdOutput, false)); - try!(set_fd(&err_fd, &mut si.hStdError, false)); - - let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()), - cfg.args()); - let mut pi = zeroed_process_information(); - let mut create_err = None; - - // stolen from the libuv code. - let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; - if cfg.detach() { - flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; - } - - with_envp(cfg.env(), |envp| { - with_dirp(cfg.cwd(), |dirp| { - let mut cmd_str: Vec = cmd_str.as_slice().utf16_units().collect(); - cmd_str.push(0); - let created = CreateProcessW(ptr::null(), - cmd_str.as_mut_ptr(), - ptr::null_mut(), - ptr::null_mut(), - TRUE, - flags, envp, dirp, - &mut si, &mut pi); - if created == FALSE { - create_err = Some(super::last_error()); - } - }) - }); - - assert!(CloseHandle(si.hStdInput) != 0); - assert!(CloseHandle(si.hStdOutput) != 0); - assert!(CloseHandle(si.hStdError) != 0); - - match create_err { - Some(err) => return Err(err), - None => {} - } - - // We close the thread handle because we don't care about keeping the - // thread id valid, and we aren't keeping the thread handle around to be - // able to close it later. We don't close the process handle however - // because std::we want the process id to stay valid at least until the - // calling code closes the process handle. - assert!(CloseHandle(pi.hThread) != 0); - - Ok(Process { - pid: pi.dwProcessId as pid_t, - handle: pi.hProcess as *mut () - }) - } - } - - /** - * Waits for a process to exit and returns the exit code, failing - * if there is no process with the specified id. - * - * Note that this is private to avoid race conditions on unix where if - * a user calls waitpid(some_process.get_id()) then some_process.finish() - * and some_process.destroy() and some_process.finalize() will then either - * operate on a none-existent process or, even worse, on a newer process - * with the same id. - */ - pub fn wait(&self, deadline: u64) -> IoResult { - use libc::types::os::arch::extra::DWORD; - use libc::consts::os::extra::{ - SYNCHRONIZE, - PROCESS_QUERY_INFORMATION, - FALSE, - STILL_ACTIVE, - INFINITE, - WAIT_TIMEOUT, - WAIT_OBJECT_0, - }; - use libc::funcs::extra::kernel32::{ - OpenProcess, - GetExitCodeProcess, - CloseHandle, - WaitForSingleObject, - }; - - unsafe { - let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, - FALSE, - self.pid as DWORD); - if process.is_null() { - return Err(super::last_error()) - } - - loop { - let mut status = 0; - if GetExitCodeProcess(process, &mut status) == FALSE { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err; - } - if status != STILL_ACTIVE { - assert!(CloseHandle(process) != 0); - return Ok(ExitStatus(status as int)); - } - let interval = if deadline == 0 { - INFINITE - } else { - let now = timer::now(); - if deadline < now {0} else {(deadline - now) as u32} - }; - match WaitForSingleObject(process, interval) { - WAIT_OBJECT_0 => {} - WAIT_TIMEOUT => { - assert!(CloseHandle(process) != 0); - return Err(timeout("process wait timed out")) - } - _ => { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err - } - } - } - } - } -} - -fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { - libc::types::os::arch::extra::STARTUPINFO { - cb: 0, - lpReserved: ptr::null_mut(), - lpDesktop: ptr::null_mut(), - lpTitle: ptr::null_mut(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::null_mut(), - hStdInput: libc::INVALID_HANDLE_VALUE, - hStdOutput: libc::INVALID_HANDLE_VALUE, - hStdError: libc::INVALID_HANDLE_VALUE, - } -} - -fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { - libc::types::os::arch::extra::PROCESS_INFORMATION { - hProcess: ptr::null_mut(), - hThread: ptr::null_mut(), - dwProcessId: 0, - dwThreadId: 0 - } -} - -fn make_command_line(prog: &CString, args: &[CString]) -> String { - let mut cmd = String::new(); - append_arg(&mut cmd, prog.as_str() - .expect("expected program name to be utf-8 encoded")); - for arg in args.iter() { - cmd.push(' '); - append_arg(&mut cmd, arg.as_str() - .expect("expected argument to be utf-8 encoded")); - } - return cmd; - - fn append_arg(cmd: &mut String, arg: &str) { - // If an argument has 0 characters then we need to quote it to ensure - // that it actually gets passed through on the command line or otherwise - // it will be dropped entirely when parsed on the other end. - let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0; - if quote { - cmd.push('"'); - } - let argvec: Vec = arg.chars().collect(); - for i in range(0u, argvec.len()) { - append_char_at(cmd, argvec.as_slice(), i); - } - if quote { - cmd.push('"'); - } - } - - fn append_char_at(cmd: &mut String, arg: &[char], i: uint) { - match arg[i] { - '"' => { - // Escape quotes. - cmd.push_str("\\\""); - } - '\\' => { - if backslash_run_ends_in_quote(arg, i) { - // Double all backslashes that are in runs before quotes. - cmd.push_str("\\\\"); - } else { - // Pass other backslashes through unescaped. - cmd.push('\\'); - } - } - c => { - cmd.push(c); - } - } - } - - fn backslash_run_ends_in_quote(s: &[char], mut i: uint) -> bool { - while i < s.len() && s[i] == '\\' { - i += 1; - } - return i < s.len() && s[i] == '"'; - } -} - -fn with_envp(env: Option<&collections::HashMap>, - cb: |*mut c_void| -> T) -> T - where K: BytesContainer + Eq + Hash, V: BytesContainer -{ - // On Windows we pass an "environment block" which is not a char**, but - // rather a concatenation of null-terminated k=v\0 sequences, with a final - // \0 to terminate. - match env { - Some(env) => { - let mut blk = Vec::new(); - - for pair in env.iter() { - let kv = format!("{}={}", - pair.ref0().container_as_str().unwrap(), - pair.ref1().container_as_str().unwrap()); - blk.extend(kv.as_slice().utf16_units()); - blk.push(0); - } - - blk.push(0); - - cb(blk.as_mut_ptr() as *mut c_void) - } - _ => cb(ptr::null_mut()) - } -} - -fn with_dirp(d: Option<&CString>, cb: |*const u16| -> T) -> T { - match d { - Some(dir) => { - let dir_str = dir.as_str() - .expect("expected workingdirectory to be utf-8 encoded"); - let mut dir_str: Vec = dir_str.utf16_units().collect(); - dir_str.push(0); - cb(dir_str.as_ptr()) - }, - None => cb(ptr::null()) - } -} - -fn free_handle(handle: *mut ()) { - assert!(unsafe { - libc::CloseHandle(mem::transmute(handle)) != 0 - }) -} - -#[cfg(test)] -mod tests { - - #[test] - fn test_make_command_line() { - use prelude::*; - use str; - use c_str::CString; - use super::make_command_line; - - fn test_wrapper(prog: &str, args: &[&str]) -> String { - make_command_line(&prog.to_c_str(), - args.iter() - .map(|a| a.to_c_str()) - .collect::>() - .as_slice()) - } - - assert_eq!( - test_wrapper("prog", &["aaa", "bbb", "ccc"]), - "prog aaa bbb ccc".to_string() - ); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa".to_string() - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb".to_string() - ); - assert_eq!( - test_wrapper("echo", &["a b c"]), - "echo \"a b c\"".to_string() - ); - assert_eq!( - test_wrapper("\u03c0\u042f\u97f3\u00e6\u221e", &[]), - "\u03c0\u042f\u97f3\u00e6\u221e".to_string() - ); - } -} diff --git a/src/libst2/sys/windows/tcp.rs b/src/libst2/sys/windows/tcp.rs deleted file mode 100644 index 3baf2be08d238..0000000000000 --- a/src/libst2/sys/windows/tcp.rs +++ /dev/null @@ -1,219 +0,0 @@ -// 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. - -use io::net::ip; -use io::IoResult; -use libc; -use mem; -use ptr; -use prelude::*; -use super::{last_error, last_net_error, retry, sock_t}; -use sync::{Arc, atomic}; -use sys::fs::FileDesc; -use sys::{mod, c, set_nonblocking, wouldblock, timer}; -use sys_common::{mod, timeout, eof}; -use sys_common::net::*; - -pub use sys_common::net::TcpStream; - -pub struct Event(c::WSAEVENT); - -impl Event { - pub fn new() -> IoResult { - let event = unsafe { c::WSACreateEvent() }; - if event == c::WSA_INVALID_EVENT { - Err(super::last_error()) - } else { - Ok(Event(event)) - } - } - - pub fn handle(&self) -> c::WSAEVENT { let Event(handle) = *self; handle } -} - -impl Drop for Event { - fn drop(&mut self) { - unsafe { let _ = c::WSACloseEvent(self.handle()); } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// TCP listeners -//////////////////////////////////////////////////////////////////////////////// - -pub struct TcpListener { - inner: FileDesc, -} - -impl TcpListener { - pub fn bind(addr: ip::SocketAddr) -> IoResult { - sys::init_net(); - - let fd = try!(socket(addr, libc::SOCK_STREAM)); - let ret = TcpListener { inner: FileDesc::new(fd as libc::c_int, true) }; - - let mut storage = unsafe { mem::zeroed() }; - let len = addr_to_sockaddr(addr, &mut storage); - let addrp = &storage as *const _ as *const libc::sockaddr; - - match unsafe { libc::bind(fd, addrp, len) } { - -1 => Err(last_net_error()), - _ => Ok(ret), - } - } - - pub fn fd(&self) -> sock_t { self.inner.fd as sock_t } - - pub fn listen(self, backlog: int) -> IoResult { - match unsafe { libc::listen(self.fd(), backlog as libc::c_int) } { - -1 => Err(last_net_error()), - - _ => { - let accept = try!(Event::new()); - let ret = unsafe { - c::WSAEventSelect(self.fd(), accept.handle(), c::FD_ACCEPT) - }; - if ret != 0 { - return Err(last_net_error()) - } - Ok(TcpAcceptor { - inner: Arc::new(AcceptorInner { - listener: self, - abort: try!(Event::new()), - accept: accept, - closed: atomic::AtomicBool::new(false), - }), - deadline: 0, - }) - } - } - } - - pub fn socket_name(&mut self) -> IoResult { - sockname(self.fd(), libc::getsockname) - } -} - -pub struct TcpAcceptor { - inner: Arc, - deadline: u64, -} - -struct AcceptorInner { - listener: TcpListener, - abort: Event, - accept: Event, - closed: atomic::AtomicBool, -} - -impl TcpAcceptor { - pub fn fd(&self) -> sock_t { self.inner.listener.fd() } - - pub fn accept(&mut self) -> IoResult { - // Unlink unix, windows cannot invoke `select` on arbitrary file - // descriptors like pipes, only sockets. Consequently, windows cannot - // use the same implementation as unix for accept() when close_accept() - // is considered. - // - // In order to implement close_accept() and timeouts, windows uses - // event handles. An acceptor-specific abort event is created which - // will only get set in close_accept(), and it will never be un-set. - // Additionally, another acceptor-specific event is associated with the - // FD_ACCEPT network event. - // - // These two events are then passed to WaitForMultipleEvents to see - // which one triggers first, and the timeout passed to this function is - // the local timeout for the acceptor. - // - // If the wait times out, then the accept timed out. If the wait - // succeeds with the abort event, then we were closed, and if the wait - // succeeds otherwise, then we do a nonblocking poll via `accept` to - // see if we can accept a connection. The connection is candidate to be - // stolen, so we do all of this in a loop as well. - let events = [self.inner.abort.handle(), self.inner.accept.handle()]; - - while !self.inner.closed.load(atomic::SeqCst) { - let ms = if self.deadline == 0 { - c::WSA_INFINITE as u64 - } else { - let now = timer::now(); - if self.deadline < now {0} else {self.deadline - now} - }; - let ret = unsafe { - c::WSAWaitForMultipleEvents(2, events.as_ptr(), libc::FALSE, - ms as libc::DWORD, libc::FALSE) - }; - match ret { - c::WSA_WAIT_TIMEOUT => { - return Err(timeout("accept timed out")) - } - c::WSA_WAIT_FAILED => return Err(last_net_error()), - c::WSA_WAIT_EVENT_0 => break, - n => assert_eq!(n, c::WSA_WAIT_EVENT_0 + 1), - } - - let mut wsaevents: c::WSANETWORKEVENTS = unsafe { mem::zeroed() }; - let ret = unsafe { - c::WSAEnumNetworkEvents(self.fd(), events[1], &mut wsaevents) - }; - if ret != 0 { return Err(last_net_error()) } - - if wsaevents.lNetworkEvents & c::FD_ACCEPT == 0 { continue } - match unsafe { - libc::accept(self.fd(), ptr::null_mut(), ptr::null_mut()) - } { - -1 if wouldblock() => {} - -1 => return Err(last_net_error()), - - // Accepted sockets inherit the same properties as the caller, - // so we need to deregister our event and switch the socket back - // to blocking mode - fd => { - let stream = TcpStream::new(fd); - let ret = unsafe { - c::WSAEventSelect(fd, events[1], 0) - }; - if ret != 0 { return Err(last_net_error()) } - try!(set_nonblocking(fd, false)); - return Ok(stream) - } - } - } - - Err(eof()) - } - - pub fn socket_name(&mut self) -> IoResult { - sockname(self.fd(), libc::getsockname) - } - - pub fn set_timeout(&mut self, timeout: Option) { - self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); - } - - pub fn close_accept(&mut self) -> IoResult<()> { - self.inner.closed.store(true, atomic::SeqCst); - let ret = unsafe { c::WSASetEvent(self.inner.abort.handle()) }; - if ret == libc::TRUE { - Ok(()) - } else { - Err(last_net_error()) - } - } -} - -impl Clone for TcpAcceptor { - fn clone(&self) -> TcpAcceptor { - TcpAcceptor { - inner: self.inner.clone(), - deadline: 0, - } - } -} diff --git a/src/libst2/sys/windows/thread_local.rs b/src/libst2/sys/windows/thread_local.rs deleted file mode 100644 index b841f6d3a2b2f..0000000000000 --- a/src/libst2/sys/windows/thread_local.rs +++ /dev/null @@ -1,238 +0,0 @@ -// 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. - -use prelude::*; - -use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; - -use mem; -use rustrt; -use rustrt::exclusive::Exclusive; -use sync::{ONCE_INIT, Once}; - -pub type Key = DWORD; -pub type Dtor = unsafe extern fn(*mut u8); - -// Turns out, like pretty much everything, Windows is pretty close the -// functionality that Unix provides, but slightly different! In the case of -// TLS, Windows does not provide an API to provide a destructor for a TLS -// variable. This ends up being pretty crucial to this implementation, so we -// need a way around this. -// -// The solution here ended up being a little obscure, but fear not, the -// internet has informed me [1][2] that this solution is not unique (no way -// I could have thought of it as well!). The key idea is to insert some hook -// somewhere to run arbitrary code on thread termination. With this in place -// we'll be able to run anything we like, including all TLS destructors! -// -// To accomplish this feat, we perform a number of tasks, all contained -// within this module: -// -// * All TLS destructors are tracked by *us*, not the windows runtime. This -// means that we have a global list of destructors for each TLS key that -// we know about. -// * When a TLS key is destroyed, we're sure to remove it from the dtor list -// if it's in there. -// * When a thread exits, we run over the entire list and run dtors for all -// non-null keys. This attempts to match Unix semantics in this regard. -// -// This ends up having the overhead of using a global list, having some -// locks here and there, and in general just adding some more code bloat. We -// attempt to optimize runtime by forgetting keys that don't have -// destructors, but this only gets us so far. -// -// For more details and nitty-gritty, see the code sections below! -// -// [1]: http://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way -// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base -// /threading/thread_local_storage_win.cc#L42 - -static INIT_DTORS: Once = ONCE_INIT; -static mut DTORS: *mut Exclusive> = 0 as *mut _; - -// ------------------------------------------------------------------------- -// Native bindings -// -// This section is just raw bindings to the native functions that Windows -// provides, There's a few extra calls to deal with destructors. - -#[inline] -pub unsafe fn create(dtor: Option) -> Key { - const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - let key = TlsAlloc(); - assert!(key != TLS_OUT_OF_INDEXES); - match dtor { - Some(f) => register_dtor(key, f), - None => {} - } - return key; -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = TlsSetValue(key, value as LPVOID); - debug_assert!(r != 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - TlsGetValue(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(key: Key) { - if unregister_dtor(key) { - // FIXME: Currently if a key has a destructor associated with it we - // can't actually ever unregister it. If we were to - // unregister it, then any key destruction would have to be - // serialized with respect to actually running destructors. - // - // We want to avoid a race where right before run_dtors runs - // some destructors TlsFree is called. Allowing the call to - // TlsFree would imply that the caller understands that *all - // known threads* are not exiting, which is quite a difficult - // thing to know! - // - // For now we just leak all keys with dtors to "fix" this. - // Note that source [2] above shows precedent for this sort - // of strategy. - } else { - let r = TlsFree(key); - debug_assert!(r != 0); - } -} - -extern "system" { - fn TlsAlloc() -> DWORD; - fn TlsFree(dwTlsIndex: DWORD) -> BOOL; - fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; - fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; -} - -// ------------------------------------------------------------------------- -// Dtor registration -// -// These functions are associated with registering and unregistering -// destructors. They're pretty simple, they just push onto a vector and scan -// a vector currently. -// -// FIXME: This could probably be at least a little faster with a BTree. - -fn init_dtors() { - let dtors = box Exclusive::new(Vec::<(Key, Dtor)>::new()); - unsafe { - DTORS = mem::transmute(dtors); - } - - rustrt::at_exit(proc() unsafe { - mem::transmute::<_, Box>>>(DTORS); - DTORS = 0 as *mut _; - }); -} - -unsafe fn register_dtor(key: Key, dtor: Dtor) { - INIT_DTORS.doit(init_dtors); - let mut dtors = (*DTORS).lock(); - dtors.push((key, dtor)); -} - -unsafe fn unregister_dtor(key: Key) -> bool { - if DTORS.is_null() { return false } - let mut dtors = (*DTORS).lock(); - let before = dtors.len(); - dtors.retain(|&(k, _)| k != key); - dtors.len() != before -} - -// ------------------------------------------------------------------------- -// Where the Magic (TM) Happens -// -// If you're looking at this code, and wondering "what is this doing?", -// you're not alone! I'll try to break this down step by step: -// -// # What's up with CRT$XLB? -// -// For anything about TLS destructors to work on Windows, we have to be able -// to run *something* when a thread exits. To do so, we place a very special -// static in a very special location. If this is encoded in just the right -// way, the kernel's loader is apparently nice enough to run some function -// of ours whenever a thread exits! How nice of the kernel! -// -// Lots of detailed information can be found in source [1] above, but the -// gist of it is that this is leveraging a feature of Microsoft's PE format -// (executable format) which is not actually used by any compilers today. -// This apparently translates to any callbacks in the ".CRT$XLB" section -// being run on certain events. -// -// So after all that, we use the compiler's #[link_section] feature to place -// a callback pointer into the magic section so it ends up being called. -// -// # What's up with this callback? -// -// The callback specified receives a number of parameters from... someone! -// (the kernel? the runtime? I'm not qute sure!) There are a few events that -// this gets invoked for, but we're currentl only interested on when a -// thread or a process "detaches" (exits). The process part happens for the -// last thread and the thread part happens for any normal thread. -// -// # Ok, what's up with running all these destructors? -// -// This will likely need to be improved over time, but this function -// attempts a "poor man's" destructor callback system. To do this we clone a -// local copy of the dtor list to start out with. This is our fudgy attempt -// to not hold the lock while destructors run and not worry about the list -// changing while we're looking at it. -// -// Once we've got a list of what to run, we iterate over all keys, check -// their values, and then run destructors if the values turn out to be non -// null (setting them to null just beforehand). We do this a few times in a -// loop to basically match Unix semantics. If we don't reach a fixed point -// after a short while then we just inevitably leak something most likely. -// -// # The article mentions crazy stuff about "/INCLUDE"? -// -// It sure does! This seems to work for now, so maybe we'll just run into -// that if we start linking with msvc? - -#[link_section = ".CRT$XLB"] -#[linkage = "external"] -#[allow(warnings)] -pub static p_thread_callback: unsafe extern "system" fn(LPVOID, DWORD, - LPVOID) = - on_tls_callback; - -#[allow(warnings)] -unsafe extern "system" fn on_tls_callback(h: LPVOID, - dwReason: DWORD, - pv: LPVOID) { - const DLL_THREAD_DETACH: DWORD = 3; - const DLL_PROCESS_DETACH: DWORD = 0; - if dwReason == DLL_THREAD_DETACH || dwReason == DLL_PROCESS_DETACH { - run_dtors(); - } -} - -unsafe fn run_dtors() { - if DTORS.is_null() { return } - let mut any_run = true; - for _ in range(0, 5i) { - if !any_run { break } - any_run = false; - let dtors = (*DTORS).lock().iter().map(|p| *p).collect::>(); - for &(key, dtor) in dtors.iter() { - let ptr = TlsGetValue(key); - if !ptr.is_null() { - TlsSetValue(key, 0 as *mut _); - dtor(ptr as *mut _); - any_run = true; - } - } - } -} diff --git a/src/libst2/sys/windows/timer.rs b/src/libst2/sys/windows/timer.rs deleted file mode 100644 index 9af3a7c8b6e01..0000000000000 --- a/src/libst2/sys/windows/timer.rs +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright 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. - -//! Timers based on Windows WaitableTimers -//! -//! This implementation is meant to be used solely on windows. As with other -//! implementations, there is a worker thread which is doing all the waiting on -//! a large number of timers for all active timers in the system. This worker -//! thread uses the select() equivalent, WaitForMultipleObjects. One of the -//! objects being waited on is a signal into the worker thread to notify that -//! the incoming channel should be looked at. -//! -//! Other than that, the implementation is pretty straightforward in terms of -//! the other two implementations of timers with nothing *that* new showing up. - -pub use self::Req::*; - -use libc; -use ptr; -use comm; - -use sys::c; -use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use prelude::*; -use io::IoResult; - -helper_init!(static HELPER: Helper) - -pub trait Callback { - fn call(&mut self); -} - -pub struct Timer { - obj: libc::HANDLE, - on_worker: bool, -} - -pub enum Req { - NewTimer(libc::HANDLE, Box, bool), - RemoveTimer(libc::HANDLE, Sender<()>), -} - -fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { - let mut objs = vec![input]; - let mut chans = vec![]; - - 'outer: loop { - let idx = unsafe { - imp::WaitForMultipleObjects(objs.len() as libc::DWORD, - objs.as_ptr(), - 0 as libc::BOOL, - libc::INFINITE) - }; - - if idx == 0 { - loop { - match messages.try_recv() { - Ok(NewTimer(obj, c, one)) => { - objs.push(obj); - chans.push((c, one)); - } - Ok(RemoveTimer(obj, c)) => { - c.send(()); - match objs.iter().position(|&o| o == obj) { - Some(i) => { - drop(objs.remove(i)); - drop(chans.remove(i - 1)); - } - None => {} - } - } - Err(comm::Disconnected) => { - assert_eq!(objs.len(), 1); - assert_eq!(chans.len(), 0); - break 'outer; - } - Err(..) => break - } - } - } else { - let remove = { - match &mut chans[idx as uint - 1] { - &(ref mut c, oneshot) => { c.call(); oneshot } - } - }; - if remove { - drop(objs.remove(idx as uint)); - drop(chans.remove(idx as uint - 1)); - } - } - } -} - -// returns the current time (in milliseconds) -pub fn now() -> u64 { - let mut ticks_per_s = 0; - assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1); - let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s}; - let mut ticks = 0; - assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1); - - return (ticks as u64 * 1000) / (ticks_per_s as u64); -} - -impl Timer { - pub fn new() -> IoResult { - HELPER.boot(|| {}, helper); - - let obj = unsafe { - imp::CreateWaitableTimerA(ptr::null_mut(), 0, ptr::null()) - }; - if obj.is_null() { - Err(super::last_error()) - } else { - Ok(Timer { obj: obj, on_worker: false, }) - } - } - - fn remove(&mut self) { - if !self.on_worker { return } - - let (tx, rx) = channel(); - HELPER.send(RemoveTimer(self.obj, tx)); - rx.recv(); - - self.on_worker = false; - } - - pub fn sleep(&mut self, msecs: u64) { - self.remove(); - - // there are 10^6 nanoseconds in a millisecond, and the parameter is in - // 100ns intervals, so we multiply by 10^4. - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), - ptr::null_mut(), 0) - }, 1); - - let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) }; - } - - pub fn oneshot(&mut self, msecs: u64, cb: Box) { - self.remove(); - - // see above for the calculation - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, 0, ptr::null_mut(), - ptr::null_mut(), 0) - }, 1); - - HELPER.send(NewTimer(self.obj, cb, true)); - self.on_worker = true; - } - - pub fn period(&mut self, msecs: u64, cb: Box) { - self.remove(); - - // see above for the calculation - let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER; - assert_eq!(unsafe { - imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG, - ptr::null_mut(), ptr::null_mut(), 0) - }, 1); - - HELPER.send(NewTimer(self.obj, cb, false)); - self.on_worker = true; - } -} - -impl Drop for Timer { - fn drop(&mut self) { - self.remove(); - assert!(unsafe { libc::CloseHandle(self.obj) != 0 }); - } -} - -mod imp { - use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER, - LONG, LPVOID, DWORD, c_void}; - - pub type PTIMERAPCROUTINE = *mut c_void; - - extern "system" { - pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES, - bManualReset: BOOL, - lpTimerName: LPCSTR) -> HANDLE; - pub fn SetWaitableTimer(hTimer: HANDLE, - pDueTime: *const LARGE_INTEGER, - lPeriod: LONG, - pfnCompletionRoutine: PTIMERAPCROUTINE, - lpArgToCompletionRoutine: LPVOID, - fResume: BOOL) -> BOOL; - pub fn WaitForMultipleObjects(nCount: DWORD, - lpHandles: *const HANDLE, - bWaitAll: BOOL, - dwMilliseconds: DWORD) -> DWORD; - pub fn WaitForSingleObject(hHandle: HANDLE, - dwMilliseconds: DWORD) -> DWORD; - } -} diff --git a/src/libst2/sys/windows/tty.rs b/src/libst2/sys/windows/tty.rs deleted file mode 100644 index 0e7b06cbb9478..0000000000000 --- a/src/libst2/sys/windows/tty.rs +++ /dev/null @@ -1,166 +0,0 @@ -// 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. - -// ignore-lexer-test FIXME #15877 - -//! Windows specific console TTY implementation -//! -//! This module contains the implementation of a Windows specific console TTY. -//! Also converts between UTF-16 and UTF-8. Windows has very poor support for -//! UTF-8 and some functions will panic. In particular ReadFile and ReadConsole -//! will panic when the codepage is set to UTF-8 and a Unicode character is -//! entered. -//! -//! FIXME -//! This implementation does not account for codepoints that are split across -//! multiple reads and writes. Also, this implementation does not expose a way -//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer -//! wrapper that performs encoding/decoding, this implementation should switch -//! to working in raw UTF-16, with such a wrapper around it. - -use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; -use super::c::{ERROR_ILLEGAL_CHARACTER}; -use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS}; -use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT}; -use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; -use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID}; -use libc::{get_osfhandle, CloseHandle}; -use libc::types::os::arch::extra::LPCVOID; -use io::{mod, IoError, IoResult, MemReader}; -use prelude::*; -use ptr; -use str::from_utf8; - -fn invalid_encoding() -> IoError { - IoError { - kind: io::InvalidInput, - desc: "text was not valid unicode", - detail: None, - } -} - -pub fn is_tty(fd: c_int) -> bool { - let mut out: DWORD = 0; - // If this function doesn't panic then fd is a TTY - match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE, - &mut out as LPDWORD) } { - 0 => false, - _ => true, - } -} - -pub struct TTY { - closeme: bool, - handle: HANDLE, - utf8: MemReader, -} - -impl TTY { - pub fn new(fd: c_int) -> IoResult { - if is_tty(fd) { - // If the file descriptor is one of stdin, stderr, or stdout - // then it should not be closed by us - let closeme = match fd { - 0...2 => false, - _ => true, - }; - let handle = unsafe { get_osfhandle(fd) as HANDLE }; - Ok(TTY { - handle: handle, - utf8: MemReader::new(Vec::new()), - closeme: closeme, - }) - } else { - Err(IoError { - kind: io::MismatchedFileTypeForOperation, - desc: "invalid handle provided to function", - detail: None, - }) - } - } - - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { - // Read more if the buffer is empty - if self.utf8.eof() { - let mut utf16 = Vec::from_elem(0x1000, 0u16); - let mut num: DWORD = 0; - match unsafe { ReadConsoleW(self.handle, - utf16.as_mut_ptr() as LPVOID, - utf16.len() as u32, - &mut num as LPDWORD, - ptr::null_mut()) } { - 0 => return Err(super::last_error()), - _ => (), - }; - utf16.truncate(num as uint); - let utf8 = match String::from_utf16(utf16.as_slice()) { - Some(utf8) => utf8.into_bytes(), - None => return Err(invalid_encoding()), - }; - self.utf8 = MemReader::new(utf8); - } - // MemReader shouldn't error here since we just filled it - Ok(self.utf8.read(buf).unwrap()) - } - - pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let utf16 = match from_utf8(buf) { - Some(utf8) => { - utf8.as_slice().utf16_units().collect::>() - } - None => return Err(invalid_encoding()), - }; - let mut num: DWORD = 0; - match unsafe { WriteConsoleW(self.handle, - utf16.as_ptr() as LPCVOID, - utf16.len() as u32, - &mut num as LPDWORD, - ptr::null_mut()) } { - 0 => Err(super::last_error()), - _ => Ok(()), - } - } - - pub fn set_raw(&mut self, raw: bool) -> IoResult<()> { - // FIXME - // Somebody needs to decide on which of these flags we want - match unsafe { SetConsoleMode(self.handle, - match raw { - true => 0, - false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS | - ENABLE_INSERT_MODE | ENABLE_LINE_INPUT | - ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE, - }) } { - 0 => Err(super::last_error()), - _ => Ok(()), - } - } - - pub fn get_winsize(&mut self) -> IoResult<(int, int)> { - // FIXME - // Get console buffer via CreateFile with CONOUT$ - // Make a CONSOLE_SCREEN_BUFFER_INFO - // Call GetConsoleScreenBufferInfo - // Maybe call GetLargestConsoleWindowSize instead? - Err(super::unimpl()) - } - - // Let us magically declare this as a TTY - pub fn isatty(&self) -> bool { true } -} - -impl Drop for TTY { - fn drop(&mut self) { - if self.closeme { - // Nobody cares about the return value - let _ = unsafe { CloseHandle(self.handle) }; - } - } -} diff --git a/src/libst2/sys/windows/udp.rs b/src/libst2/sys/windows/udp.rs deleted file mode 100644 index 50f8fb828ad32..0000000000000 --- a/src/libst2/sys/windows/udp.rs +++ /dev/null @@ -1,11 +0,0 @@ -// 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. - -pub use sys_common::net::UdpSocket; diff --git a/src/libst2/task.rs b/src/libst2/task.rs deleted file mode 100644 index 296a9f936413d..0000000000000 --- a/src/libst2/task.rs +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Task creation -//! -//! An executing Rust program consists of a collection of tasks, each -//! with their own stack and local state. -//! -//! Tasks generally have their memory *isolated* from each other by -//! virtue of Rust's owned types (which of course may only be owned by -//! a single task at a time). Communication between tasks is primarily -//! done through [channels](../../std/comm/index.html), Rust's -//! message-passing types, though [other forms of task -//! synchronization](../../std/sync/index.html) are often employed to -//! achieve particular performance goals. In particular, types that -//! are guaranteed to be threadsafe are easily shared between threads -//! using the atomically-reference-counted container, -//! [`Arc`](../../std/sync/struct.Arc.html). -//! -//! Fatal logic errors in Rust cause *task panic*, during which -//! a task will unwind the stack, running destructors and freeing -//! owned resources. Task panic is unrecoverable from within -//! the panicking task (i.e. there is no 'try/catch' in Rust), but -//! panic may optionally be detected from a different task. If -//! the main task panics the application will exit with a non-zero -//! exit code. -//! -//! ## Example -//! -//! ```rust -//! spawn(proc() { -//! println!("Hello, World!"); -//! }) -//! ``` - -#![unstable = "The task spawning model will be changed as part of runtime reform, and the module \ - will likely be renamed from `task` to `thread`."] - -use any::Any; -use comm::channel; -use io::{Writer, stdio}; -use kinds::{Send, marker}; -use option::{None, Some, Option}; -use boxed::Box; -use result::Result; -use rustrt::local::Local; -use rustrt::task; -use rustrt::task::Task; -use str::{Str, SendStr, IntoMaybeOwned}; -use string::{String, ToString}; -use sync::Future; - -/// The task builder type. -/// -/// Provides detailed control over the properties and behavior of new tasks. - -// NB: Builders are designed to be single-use because they do stateful -// things that get weird when reusing - e.g. if you create a result future -// it only applies to a single task, so then you have to maintain Some -// potentially tricky state to ensure that everything behaves correctly -// when you try to reuse the builder to spawn a new task. We'll just -// sidestep that whole issue by making builders uncopyable and making -// the run function move them in. -pub struct TaskBuilder { - // A name for the task-to-be, for identification in panic messages - name: Option, - // The size of the stack for the spawned task - stack_size: Option, - // Task-local stdout - stdout: Option>, - // Task-local stderr - stderr: Option>, - // Optionally wrap the eventual task body - gen_body: Option proc():Send>, - nocopy: marker::NoCopy, -} - -impl TaskBuilder { - /// Generate the base configuration for spawning a task, off of which more - /// configuration methods can be chained. - pub fn new() -> TaskBuilder { unimplemented!() } -} - -impl TaskBuilder { - /// Name the task-to-be. Currently the name is used for identification - /// only in panic messages. - #[unstable = "IntoMaybeOwned will probably change."] - pub fn named>(mut self, name: T) -> TaskBuilder { unimplemented!() } - - /// Set the size of the stack for the new task. - pub fn stack_size(mut self, size: uint) -> TaskBuilder { unimplemented!() } - - /// Redirect task-local stdout. - #[experimental = "May not want to make stdio overridable here."] - pub fn stdout(mut self, stdout: Box) -> TaskBuilder { unimplemented!() } - - /// Redirect task-local stderr. - #[experimental = "May not want to make stdio overridable here."] - pub fn stderr(mut self, stderr: Box) -> TaskBuilder { unimplemented!() } - - // Where spawning actually happens (whether yielding a future or not) - fn spawn_internal(self, f: proc():Send, - on_exit: Option>):Send>) { unimplemented!() } - - /// Creates and executes a new child task. - /// - /// Sets up a new task with its own call stack and schedules it to run - /// the provided proc. The task has the properties and behavior - /// specified by the `TaskBuilder`. - pub fn spawn(self, f: proc():Send) { unimplemented!() } - - /// Execute a proc in a newly-spawned task and return a future representing - /// the task's result. The task has the properties and behavior - /// specified by the `TaskBuilder`. - /// - /// Taking the value of the future will block until the child task - /// terminates. - /// - /// # Return value - /// - /// If the child task executes successfully (without panicking) then the - /// future returns `result::Ok` containing the value returned by the - /// function. If the child task panics then the future returns `result::Err` - /// containing the argument to `panic!(...)` as an `Any` trait object. - #[experimental = "Futures are experimental."] - pub fn try_future(self, f: proc():Send -> T) - -> Future>> { unimplemented!() } - - /// Execute a function in a newly-spawnedtask and block until the task - /// completes or panics. Equivalent to `.try_future(f).unwrap()`. - #[unstable = "Error type may change."] - pub fn try(self, f: proc():Send -> T) -> Result> { unimplemented!() } -} - -/* Convenience functions */ - -/// Creates and executes a new child task -/// -/// Sets up a new task with its own call stack and schedules it to run -/// the provided unique closure. -/// -/// This function is equivalent to `TaskBuilder::new().spawn(f)`. -pub fn spawn(f: proc(): Send) { unimplemented!() } - -/// Execute a function in a newly-spawned task and return either the return -/// value of the function or an error if the task panicked. -/// -/// This is equivalent to `TaskBuilder::new().try`. -#[unstable = "Error type may change."] -pub fn try(f: proc(): Send -> T) -> Result> { unimplemented!() } - -/// Execute a function in another task and return a future representing the -/// task's result. -/// -/// This is equivalent to `TaskBuilder::new().try_future`. -#[experimental = "Futures are experimental."] -pub fn try_future(f: proc():Send -> T) -> Future>> { unimplemented!() } - - -/* Lifecycle functions */ - -/// Read the name of the current task. -#[stable] -pub fn name() -> Option { unimplemented!() } - -/// Yield control to the task scheduler. -#[unstable = "Name will change."] -pub fn deschedule() { unimplemented!() } - -/// True if the running task is currently panicking (e.g. will return `true` inside a -/// destructor that is run while unwinding the stack after a call to `panic!()`). -#[unstable = "May move to a different module."] -pub fn failing() -> bool { unimplemented!() } - -#[test] -fn task_abort_no_kill_runtime() { unimplemented!() } diff --git a/src/libst2/thread_local/mod.rs b/src/libst2/thread_local/mod.rs deleted file mode 100644 index 1927aaf9da25b..0000000000000 --- a/src/libst2/thread_local/mod.rs +++ /dev/null @@ -1,313 +0,0 @@ -// 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. - -//! Thread local storage -//! -//! This module provides an implementation of thread local storage for Rust -//! programs. Thread local storage is a method of storing data into a global -//! variable which each thread in the program will have its own copy of. -//! Threads do not share this data, so accesses do not need to be synchronized. -//! -//! At a high level, this module provides two variants of storage: -//! -//! * Owning thread local storage. This is a type of thread local key which -//! owns the value that it contains, and will destroy the value when the -//! thread exits. This variant is created with the `thread_local!` macro and -//! can contain any value which is `'static` (no borrowed pointers. -//! -//! * Scoped thread local storage. This type of key is used to store a reference -//! to a value into local storage temporarily for the scope of a function -//! call. There are no restrictions on what types of values can be placed -//! into this key. -//! -//! Both forms of thread local storage provide an accessor function, `with`, -//! which will yield a shared reference to the value to the specified -//! closure. Thread local keys only allow shared access to values as there is no -//! way to guarantee uniqueness if a mutable borrow was allowed. Most values -//! will want to make use of some form of **interior mutability** through the -//! `Cell` or `RefCell` types. - -#![macro_escape] -#![experimental] - -use prelude::*; - -use cell::UnsafeCell; - -// Sure wish we had macro hygiene, no? -#[doc(hidden)] pub use self::imp::Key as KeyInner; -#[doc(hidden)] pub use self::imp::destroy_value; -#[doc(hidden)] pub use sys_common::thread_local::INIT_INNER as OS_INIT_INNER; -#[doc(hidden)] pub use sys_common::thread_local::StaticKey as OsStaticKey; - -pub mod scoped; - -/// A thread local storage key which owns its contents. -/// -/// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the `thread_local!` macro and the -/// primary method is the `with` method. -/// -/// The `with` method yields a reference to the contained value which cannot be -/// sent across tasks or escape the given closure. -/// -/// # Initialization and Destruction -/// -/// Initialization is dynamically performed on the first call to `with()` -/// within a thread, and values support destructors which will be run when a -/// thread exits. -/// -/// # Example -/// -/// ``` -/// use std::cell::RefCell; -/// -/// thread_local!(static FOO: RefCell = RefCell::new(1)); -/// -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 2; -/// }); -/// -/// // each thread starts out with the initial value of 1 -/// spawn(proc() { -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 1); -/// *f.borrow_mut() = 3; -/// }); -/// }); -/// -/// // we retain our original value of 2 despite the child thread -/// FOO.with(|f| { -/// assert_eq!(*f.borrow(), 2); -/// }); -/// ``` -pub struct Key { - // The key itself may be tagged with #[thread_local], and this `Key` is - // stored as a `static`, and it's not valid for a static to reference the - // address of another thread_local static. For this reason we kinda wonkily - // work around this by generating a shim function which will give us the - // address of the inner TLS key at runtime. - // - // This is trivially devirtualizable by LLVM because we never store anything - // to this field and rustc can declare the `static` as constant as well. - #[doc(hidden)] - pub inner: fn() -> &'static KeyInner>>, - - // initialization routine to invoke to create a value - #[doc(hidden)] - pub init: fn() -> T, -} - -/// Declare a new thread local storage key of type `std::thread_local::Key`. -#[macro_export] -#[doc(hidden)] -macro_rules! thread_local( - (static $name:ident: $t:ty = $init:expr) => ( - static $name: ::std::thread_local::Key<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread_local::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }) - fn __init() -> $t { unimplemented!() } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { unimplemented!() } - ::std::thread_local::Key { inner: __getit, init: __init } - }; - ); - (pub static $name:ident: $t:ty = $init:expr) => ( - pub static $name: ::std::thread_local::Key<$t> = { - use std::cell::UnsafeCell as __UnsafeCell; - use std::thread_local::KeyInner as __KeyInner; - use std::option::Option as __Option; - use std::option::None as __None; - - __thread_local_inner!(static __KEY: __UnsafeCell<__Option<$t>> = { - __UnsafeCell { value: __None } - }) - fn __init() -> $t { unimplemented!() } - fn __getit() -> &'static __KeyInner<__UnsafeCell<__Option<$t>>> { unimplemented!() } - ::std::thread_local::Key { inner: __getit, init: __init } - }; - ); -) - -// Macro pain #4586: -// -// When cross compiling, rustc will load plugins and macros from the *host* -// platform before search for macros from the target platform. This is primarily -// done to detect, for example, plugins. Ideally the macro below would be -// defined once per module below, but unfortunately this means we have the -// following situation: -// -// 1. We compile libstd for x86_64-unknown-linux-gnu, this thread_local!() macro -// will inject #[thread_local] statics. -// 2. We then try to compile a program for arm-linux-androideabi -// 3. The compiler has a host of linux and a target of android, so it loads -// macros from the *linux* libstd. -// 4. The macro generates a #[thread_local] field, but the android libstd does -// not use #[thread_local] -// 5. Compile error about structs with wrong fields. -// -// To get around this, we're forced to inject the #[cfg] logic into the macro -// itself. Woohoo. - -#[macro_export] -macro_rules! __thread_local_inner( - (static $name:ident: $t:ty = $init:expr) => ( - #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)] - static $name: ::std::thread_local::KeyInner<$t> = - __thread_local_inner!($init, $t); - ); - (pub static $name:ident: $t:ty = $init:expr) => ( - #[cfg_attr(any(target_os = "macos", target_os = "linux"), thread_local)] - pub static $name: ::std::thread_local::KeyInner<$t> = - __thread_local_inner!($init, $t); - ); - ($init:expr, $t:ty) => ({ - #[cfg(any(target_os = "macos", target_os = "linux"))] - const INIT: ::std::thread_local::KeyInner<$t> = { - ::std::thread_local::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - dtor_registered: ::std::cell::UnsafeCell { value: false }, - dtor_running: ::std::cell::UnsafeCell { value: false }, - marker: ::std::kinds::marker::NoCopy, - } - }; - - #[cfg(not(any(target_os = "macos", target_os = "linux")))] - const INIT: ::std::thread_local::KeyInner<$t> = { - unsafe extern fn __destroy(ptr: *mut u8) { unimplemented!() } - ::std::thread_local::KeyInner { - inner: ::std::cell::UnsafeCell { value: $init }, - os: ::std::thread_local::OsStaticKey { - inner: ::std::thread_local::OS_INIT_INNER, - dtor: ::std::option::Some(__destroy), - }, - } - }; - - INIT - }); -) - -impl Key { - /// Acquire a reference to the value in this TLS key. - /// - /// This will lazily initialize the value if this thread has not referenced - /// this key yet. - /// - /// # Panics - /// - /// This function will `panic!()` if the key currently has its - /// destructor running, and it **may** panic if the destructor has - /// previously been run for this thread. - pub fn with(&'static self, f: |&T| -> R) -> R { unimplemented!() } - - /// Test this TLS key to determine whether its value has been destroyed for - /// the current thread or not. - /// - /// This will not initialize the key if it is not already initialized. - pub fn destroyed(&'static self) -> bool { unimplemented!() } -} - -#[cfg(any(target_os = "macos", target_os = "linux"))] -mod imp { - use prelude::*; - - use cell::UnsafeCell; - use intrinsics; - use kinds::marker; - use ptr; - - #[doc(hidden)] - pub struct Key { - // Place the inner bits in an `UnsafeCell` to currently get around the - // "only Sync statics" restriction. This allows any type to be placed in - // the cell. - // - // Note that all access requires `T: 'static` so it can't be a type with - // any borrowed pointers still. - pub inner: UnsafeCell, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - pub dtor_registered: UnsafeCell, // should be Cell - pub dtor_running: UnsafeCell, // should be Cell - - // These shouldn't be copied around. - pub marker: marker::NoCopy, - } - - #[doc(hidden)] - impl Key { - pub unsafe fn get(&'static self) -> Option<&'static T> { unimplemented!() } - - unsafe fn register_dtor(&self) { unimplemented!() } - } - - // Since what appears to be glibc 2.18 this symbol has been shipped which - // GCC and clang both use to invoke destructors in thread_local globals, so - // let's do the same! - // - // Note, however, that we run on lots older linuxes, as well as cross - // compiling from a newer linux to an older linux, so we also have a - // fallback implementation to use as well. - // - // Due to rust-lang/rust#18804, make sure this is not generic! - #[cfg(target_os = "linux")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { unimplemented!() } - - // OSX's analog of the above linux function is this _tlv_atexit function. - // The disassembly of thread_local globals in C++ (at least produced by - // clang) will have this show up in the output. - #[cfg(target_os = "macos")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { unimplemented!() } - - #[doc(hidden)] - pub unsafe extern fn destroy_value(ptr: *mut u8) { unimplemented!() } -} - -#[cfg(not(any(target_os = "macos", target_os = "linux")))] -mod imp { - use prelude::*; - - use cell::UnsafeCell; - use mem; - use sys_common::thread_local::StaticKey as OsStaticKey; - - #[doc(hidden)] - pub struct Key { - // Statically allocated initialization expression, using an `UnsafeCell` - // for the same reasons as above. - pub inner: UnsafeCell, - - // OS-TLS key that we'll use to key off. - pub os: OsStaticKey, - } - - struct Value { - key: &'static Key, - value: T, - } - - #[doc(hidden)] - impl Key { - pub unsafe fn get(&'static self) -> Option<&'static T> { unimplemented!() } - - unsafe fn ptr(&'static self) -> Option<*mut T> { unimplemented!() } - } - - #[doc(hidden)] - pub unsafe extern fn destroy_value(ptr: *mut u8) { unimplemented!() } -} diff --git a/src/libst2/thread_local/scoped.rs b/src/libst2/thread_local/scoped.rs deleted file mode 100644 index 1368adf65609d..0000000000000 --- a/src/libst2/thread_local/scoped.rs +++ /dev/null @@ -1,199 +0,0 @@ -// 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. - -//! Scoped thread-local storage -//! -//! This module provides the ability to generate *scoped* thread-local -//! variables. In this sense, scoped indicates that thread local storage -//! actually stores a reference to a value, and this reference is only placed -//! in storage for a scoped amount of time. -//! -//! There are no restrictions on what types can be placed into a scoped -//! variable, but all scoped variables are initialized to the equivalent of -//! null. Scoped thread local stor is useful when a value is present for a known -//! period of time and it is not required to relinquish ownership of the -//! contents. -//! -//! # Example -//! -//! ``` -//! scoped_thread_local!(static FOO: uint) -//! -//! // Initially each scoped slot is empty. -//! assert!(!FOO.is_set()); -//! -//! // When inserting a value, the value is only in place for the duration -//! // of the closure specified. -//! FOO.set(&1, || { -//! FOO.with(|slot| { -//! assert_eq!(*slot, 1); -//! }); -//! }); -//! ``` - -#![macro_escape] - -use prelude::*; - -// macro hygiene sure would be nice, wouldn't it? -#[doc(hidden)] pub use self::imp::KeyInner; -#[doc(hidden)] pub use sys_common::thread_local::INIT as OS_INIT; - -/// Type representing a thread local storage key corresponding to a reference -/// to the type parameter `T`. -/// -/// Keys are statically allocated and can contain a reference to an instance of -/// type `T` scoped to a particular lifetime. Keys provides two methods, `set` -/// and `with`, both of which currently use closures to control the scope of -/// their contents. -pub struct Key { #[doc(hidden)] pub inner: KeyInner } - -/// Declare a new scoped thread local storage key. -/// -/// This macro declares a `static` item on which methods are used to get and -/// set the value stored within. -#[macro_export] -macro_rules! scoped_thread_local( - (static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(static $name: $t) - ); - (pub static $name:ident: $t:ty) => ( - __scoped_thread_local_inner!(pub static $name: $t) - ); -) - -#[macro_export] -#[doc(hidden)] -macro_rules! __scoped_thread_local_inner( - (static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios")), - thread_local)] - static $name: ::std::thread_local::scoped::Key<$t> = - __scoped_thread_local_inner!($t); - ); - (pub static $name:ident: $t:ty) => ( - #[cfg_attr(not(any(windows, target_os = "android", target_os = "ios")), - thread_local)] - pub static $name: ::std::thread_local::scoped::Key<$t> = - __scoped_thread_local_inner!($t); - ); - ($t:ty) => ({ - use std::thread_local::scoped::Key as __Key; - - #[cfg(not(any(windows, target_os = "android", target_os = "ios")))] - const INIT: __Key<$t> = __Key { - inner: ::std::thread_local::scoped::KeyInner { - inner: ::std::cell::UnsafeCell { value: 0 as *mut _ }, - } - }; - - #[cfg(any(windows, target_os = "android", target_os = "ios"))] - const INIT: __Key<$t> = __Key { - inner: ::std::thread_local::scoped::KeyInner { - inner: ::std::thread_local::scoped::OS_INIT, - marker: ::std::kinds::marker::InvariantType, - } - }; - - INIT - }) -) - -impl Key { - /// Insert a value into this scoped thread local storage slot for a - /// duration of a closure. - /// - /// While `cb` is running, the value `t` will be returned by `get` unless - /// this function is called recursively inside of `cb`. - /// - /// Upon return, this function will restore the previous value, if any - /// was available. - /// - /// # Example - /// - /// ``` - /// scoped_thread_local!(static FOO: uint) - /// - /// FOO.set(&100, || { - /// let val = FOO.with(|v| *v); - /// assert_eq!(val, 100); - /// - /// // set can be called recursively - /// FOO.set(&101, || { - /// // ... - /// }); - /// - /// // Recursive calls restore the previous value. - /// let val = FOO.with(|v| *v); - /// assert_eq!(val, 100); - /// }); - /// ``` - pub fn set(&'static self, t: &T, cb: || -> R) -> R { unimplemented!() } - - /// Get a value out of this scoped variable. - /// - /// This function takes a closure which receives the value of this - /// variable. - /// - /// # Panics - /// - /// This function will panic if `set` has not previously been called. - /// - /// # Example - /// - /// ```no_run - /// scoped_thread_local!(static FOO: uint) - /// - /// FOO.with(|slot| { - /// // work with `slot` - /// }); - /// ``` - pub fn with(&'static self, cb: |&T| -> R) -> R { unimplemented!() } - - /// Test whether this TLS key has been `set` for the current thread. - pub fn is_set(&'static self) -> bool { unimplemented!() } -} - -#[cfg(not(any(windows, target_os = "android", target_os = "ios")))] -mod imp { - use std::cell::UnsafeCell; - - // FIXME: Should be a `Cell`, but that's not `Sync` - #[doc(hidden)] - pub struct KeyInner { pub inner: UnsafeCell<*mut T> } - - #[doc(hidden)] - impl KeyInner { - #[doc(hidden)] - pub unsafe fn set(&self, ptr: *mut T) { unimplemented!() } - #[doc(hidden)] - pub unsafe fn get(&self) -> *mut T { unimplemented!() } - } -} - -#[cfg(any(windows, target_os = "android", target_os = "ios"))] -mod imp { - use kinds::marker; - use sys_common::thread_local::StaticKey as OsStaticKey; - - #[doc(hidden)] - pub struct KeyInner { - pub inner: OsStaticKey, - pub marker: marker::InvariantType, - } - - #[doc(hidden)] - impl KeyInner { - #[doc(hidden)] - pub unsafe fn set(&self, ptr: *mut T) { unimplemented!() } - #[doc(hidden)] - pub unsafe fn get(&self) -> *mut T { unimplemented!() } - } -} diff --git a/src/libst2/time/duration.rs b/src/libst2/time/duration.rs deleted file mode 100644 index ec2d62ff85cb1..0000000000000 --- a/src/libst2/time/duration.rs +++ /dev/null @@ -1,557 +0,0 @@ -// 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. - -//! Temporal quantification - -#![experimental] - -use {fmt, i64}; -use ops::{Add, Sub, Mul, Div, Neg}; -use option::{Option, Some, None}; -use num::Int; -use result::{Result, Ok, Err}; - -/// The number of nanoseconds in a microsecond. -const NANOS_PER_MICRO: i32 = 1000; -/// The number of nanoseconds in a millisecond. -const NANOS_PER_MILLI: i32 = 1000_000; -/// The number of nanoseconds in seconds. -const NANOS_PER_SEC: i32 = 1_000_000_000; -/// The number of microseconds per second. -const MICROS_PER_SEC: i64 = 1000_000; -/// The number of milliseconds per second. -const MILLIS_PER_SEC: i64 = 1000; -/// The number of seconds in a minute. -const SECS_PER_MINUTE: i64 = 60; -/// The number of seconds in an hour. -const SECS_PER_HOUR: i64 = 3600; -/// The number of (non-leap) seconds in days. -const SECS_PER_DAY: i64 = 86400; -/// The number of (non-leap) seconds in a week. -const SECS_PER_WEEK: i64 = 604800; - -macro_rules! try_opt( - ($e:expr) => (match $e { Some(v) => v, None => return None }) -) - - -/// ISO 8601 time duration with nanosecond precision. -/// This also allows for the negative duration; see individual methods for details. -#[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Duration { - secs: i64, - nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC -} - -/// The minimum possible `Duration`: `i64::MIN` milliseconds. -pub const MIN: Duration = Duration { - secs: i64::MIN / MILLIS_PER_SEC - 1, - nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI -}; - -/// The maximum possible `Duration`: `i64::MAX` milliseconds. -pub const MAX: Duration = Duration { - secs: i64::MAX / MILLIS_PER_SEC, - nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI -}; - -impl Duration { - /// Makes a new `Duration` with given number of weeks. - /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn weeks(weeks: i64) -> Duration { - let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of days. - /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn days(days: i64) -> Duration { - let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of hours. - /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn hours(hours: i64) -> Duration { - let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of minutes. - /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks. - /// Panics when the duration is out of bounds. - #[inline] - pub fn minutes(minutes: i64) -> Duration { - let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds"); - Duration::seconds(secs) - } - - /// Makes a new `Duration` with given number of seconds. - /// Panics when the duration is more than `i64::MAX` milliseconds - /// or less than `i64::MIN` milliseconds. - #[inline] - pub fn seconds(seconds: i64) -> Duration { - let d = Duration { secs: seconds, nanos: 0 }; - if d < MIN || d > MAX { - panic!("Duration::seconds out of bounds"); - } - d - } - - /// Makes a new `Duration` with given number of milliseconds. - #[inline] - pub fn milliseconds(milliseconds: i64) -> Duration { - let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC); - let nanos = millis as i32 * NANOS_PER_MILLI; - Duration { secs: secs, nanos: nanos } - } - - /// Makes a new `Duration` with given number of microseconds. - #[inline] - pub fn microseconds(microseconds: i64) -> Duration { - let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC); - let nanos = micros as i32 * NANOS_PER_MICRO; - Duration { secs: secs, nanos: nanos } - } - - /// Makes a new `Duration` with given number of nanoseconds. - #[inline] - pub fn nanoseconds(nanos: i64) -> Duration { - let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64); - Duration { secs: secs, nanos: nanos as i32 } - } - - /// Runs a closure, returning the duration of time it took to run the - /// closure. - pub fn span(f: ||) -> Duration { - let before = super::precise_time_ns(); - f(); - Duration::nanoseconds((super::precise_time_ns() - before) as i64) - } - - /// Returns the total number of whole weeks in the duration. - #[inline] - pub fn num_weeks(&self) -> i64 { - self.num_days() / 7 - } - - /// Returns the total number of whole days in the duration. - pub fn num_days(&self) -> i64 { - self.num_seconds() / SECS_PER_DAY - } - - /// Returns the total number of whole hours in the duration. - #[inline] - pub fn num_hours(&self) -> i64 { - self.num_seconds() / SECS_PER_HOUR - } - - /// Returns the total number of whole minutes in the duration. - #[inline] - pub fn num_minutes(&self) -> i64 { - self.num_seconds() / SECS_PER_MINUTE - } - - /// Returns the total number of whole seconds in the duration. - pub fn num_seconds(&self) -> i64 { - // If secs is negative, nanos should be subtracted from the duration. - if self.secs < 0 && self.nanos > 0 { - self.secs + 1 - } else { - self.secs - } - } - - /// Returns the number of nanoseconds such that - /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of - /// nanoseconds in the duration. - fn nanos_mod_sec(&self) -> i32 { - if self.secs < 0 && self.nanos > 0 { - self.nanos - NANOS_PER_SEC - } else { - self.nanos - } - } - - /// Returns the total number of whole milliseconds in the duration, - pub fn num_milliseconds(&self) -> i64 { - // A proper Duration will not overflow, because MIN and MAX are defined - // such that the range is exactly i64 milliseconds. - let secs_part = self.num_seconds() * MILLIS_PER_SEC; - let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI; - secs_part + nanos_part as i64 - } - - /// Returns the total number of whole microseconds in the duration, - /// or `None` on overflow (exceeding 2^63 microseconds in either direction). - pub fn num_microseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC)); - let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO; - secs_part.checked_add(nanos_part as i64) - } - - /// Returns the total number of whole nanoseconds in the duration, - /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction). - pub fn num_nanoseconds(&self) -> Option { - let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64)); - let nanos_part = self.nanos_mod_sec(); - secs_part.checked_add(nanos_part as i64) - } - - /// Add two durations, returning `None` if overflow occured. - pub fn checked_add(&self, rhs: &Duration) -> Option { - let mut secs = try_opt!(self.secs.checked_add(rhs.secs)); - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs = try_opt!(secs.checked_add(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { None } else { Some(d) } - } - - /// Subtract two durations, returning `None` if overflow occured. - pub fn checked_sub(&self, rhs: &Duration) -> Option { - let mut secs = try_opt!(self.secs.checked_sub(rhs.secs)); - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs = try_opt!(secs.checked_sub(1)); - } - let d = Duration { secs: secs, nanos: nanos }; - // Even if d is within the bounds of i64 seconds, - // it might still overflow i64 milliseconds. - if d < MIN || d > MAX { None } else { Some(d) } - } - - /// The minimum possible `Duration`: `i64::MIN` milliseconds. - #[inline] - pub fn min_value() -> Duration { MIN } - - /// The maximum possible `Duration`: `i64::MAX` milliseconds. - #[inline] - pub fn max_value() -> Duration { MAX } - - /// A duration where the stored seconds and nanoseconds are equal to zero. - #[inline] - pub fn zero() -> Duration { - Duration { secs: 0, nanos: 0 } - } - - /// Returns `true` if the duration equals `Duration::zero()`. - #[inline] - pub fn is_zero(&self) -> bool { - self.secs == 0 && self.nanos == 0 - } -} - -impl Neg for Duration { - #[inline] - fn neg(&self) -> Duration { - if self.nanos == 0 { - Duration { secs: -self.secs, nanos: 0 } - } else { - Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos } - } - } -} - -impl Add for Duration { - fn add(&self, rhs: &Duration) -> Duration { - let mut secs = self.secs + rhs.secs; - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs += 1; - } - Duration { secs: secs, nanos: nanos } - } -} - -impl Sub for Duration { - fn sub(&self, rhs: &Duration) -> Duration { - let mut secs = self.secs - rhs.secs; - let mut nanos = self.nanos - rhs.nanos; - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - Duration { secs: secs, nanos: nanos } - } -} - -impl Mul for Duration { - fn mul(&self, rhs: &i32) -> Duration { - // Multiply nanoseconds as i64, because it cannot overflow that way. - let total_nanos = self.nanos as i64 * *rhs as i64; - let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64); - let secs = self.secs * *rhs as i64 + extra_secs; - Duration { secs: secs, nanos: nanos as i32 } - } -} - -impl Div for Duration { - fn div(&self, rhs: &i32) -> Duration { - let mut secs = self.secs / *rhs as i64; - let carry = self.secs - secs * *rhs as i64; - let extra_nanos = carry * NANOS_PER_SEC as i64 / *rhs as i64; - let mut nanos = self.nanos / *rhs + extra_nanos as i32; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs += 1; - } - if nanos < 0 { - nanos += NANOS_PER_SEC; - secs -= 1; - } - Duration { secs: secs, nanos: nanos } - } -} - -impl fmt::Show for Duration { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // technically speaking, negative duration is not valid ISO 8601, - // but we need to print it anyway. - let (abs, sign) = if self.secs < 0 { (-*self, "-") } else { (*self, "") }; - - let days = abs.secs / SECS_PER_DAY; - let secs = abs.secs - days * SECS_PER_DAY; - let hasdate = days != 0; - let hastime = (secs != 0 || abs.nanos != 0) || !hasdate; - - try!(write!(f, "{}P", sign)); - - if hasdate { - try!(write!(f, "{}D", days)); - } - if hastime { - if abs.nanos == 0 { - try!(write!(f, "T{}S", secs)); - } else if abs.nanos % NANOS_PER_MILLI == 0 { - try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI)); - } else if abs.nanos % NANOS_PER_MICRO == 0 { - try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO)); - } else { - try!(write!(f, "T{}.{:09}S", secs, abs.nanos)); - } - } - Ok(()) - } -} - -// Copied from libnum -#[inline] -fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) { - (div_floor_64(this, other), mod_floor_64(this, other)) -} - -#[inline] -fn div_floor_64(this: i64, other: i64) -> i64 { - match div_rem_64(this, other) { - (d, r) if (r > 0 && other < 0) - || (r < 0 && other > 0) => d - 1, - (d, _) => d, - } -} - -#[inline] -fn mod_floor_64(this: i64, other: i64) -> i64 { - match this % other { - r if (r > 0 && other < 0) - || (r < 0 && other > 0) => r + other, - r => r, - } -} - -#[inline] -fn div_rem_64(this: i64, other: i64) -> (i64, i64) { - (this / other, this % other) -} - -#[cfg(test)] -mod tests { - use super::{Duration, MIN, MAX}; - use {i32, i64}; - use option::{Some, None}; - use string::ToString; - - #[test] - fn test_duration() { - assert!(Duration::seconds(1) != Duration::zero()); - assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3)); - assert_eq!(Duration::seconds(86399) + Duration::seconds(4), - Duration::days(1) + Duration::seconds(3)); - assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000)); - assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000)); - assert_eq!(Duration::days(2) + Duration::seconds(86399) + - Duration::nanoseconds(1234567890), - Duration::days(3) + Duration::nanoseconds(234567890)); - assert_eq!(-Duration::days(3), Duration::days(-3)); - assert_eq!(-(Duration::days(3) + Duration::seconds(70)), - Duration::days(-4) + Duration::seconds(86400-70)); - } - - #[test] - fn test_duration_num_days() { - assert_eq!(Duration::zero().num_days(), 0); - assert_eq!(Duration::days(1).num_days(), 1); - assert_eq!(Duration::days(-1).num_days(), -1); - assert_eq!(Duration::seconds(86399).num_days(), 0); - assert_eq!(Duration::seconds(86401).num_days(), 1); - assert_eq!(Duration::seconds(-86399).num_days(), 0); - assert_eq!(Duration::seconds(-86401).num_days(), -1); - assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64); - assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64); - } - - #[test] - fn test_duration_num_seconds() { - assert_eq!(Duration::zero().num_seconds(), 0); - assert_eq!(Duration::seconds(1).num_seconds(), 1); - assert_eq!(Duration::seconds(-1).num_seconds(), -1); - assert_eq!(Duration::milliseconds(999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(1001).num_seconds(), 1); - assert_eq!(Duration::milliseconds(-999).num_seconds(), 0); - assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1); - } - - #[test] - fn test_duration_num_milliseconds() { - assert_eq!(Duration::zero().num_milliseconds(), 0); - assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1); - assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1); - assert_eq!(Duration::microseconds(999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1); - assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0); - assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1); - assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX); - assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN); - assert_eq!(MAX.num_milliseconds(), i64::MAX); - assert_eq!(MIN.num_milliseconds(), i64::MIN); - } - - #[test] - fn test_duration_num_microseconds() { - assert_eq!(Duration::zero().num_microseconds(), Some(0)); - assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1)); - assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1)); - assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1)); - assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX)); - assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_microseconds(), None); - assert_eq!(MIN.num_microseconds(), None); - - // overflow checks - const MICROS_PER_DAY: i64 = 86400_000_000; - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(), - Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY)); - assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(), - Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY)); - assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None); - assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None); - } - - #[test] - fn test_duration_num_nanoseconds() { - assert_eq!(Duration::zero().num_nanoseconds(), Some(0)); - assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1)); - assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1)); - assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX)); - assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN)); - assert_eq!(MAX.num_nanoseconds(), None); - assert_eq!(MIN.num_nanoseconds(), None); - - // overflow checks - const NANOS_PER_DAY: i64 = 86400_000_000_000; - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY)); - assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(), - Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY)); - assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None); - assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None); - } - - #[test] - fn test_duration_checked_ops() { - assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)), - Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999))); - assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000)) - .is_none()); - - assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)), - Some(Duration::milliseconds(i64::MIN))); - assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1)) - .is_none()); - } - - #[test] - fn test_duration_mul() { - assert_eq!(Duration::zero() * i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() * i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 0, Duration::zero()); - assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1)); - assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1)); - assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1)); - assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1)); - assert_eq!(Duration::nanoseconds(30) * 333_333_333, - Duration::seconds(10) - Duration::nanoseconds(10)); - assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3, - Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3)); - assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3)); - assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3)); - } - - #[test] - fn test_duration_div() { - assert_eq!(Duration::zero() / i32::MAX, Duration::zero()); - assert_eq!(Duration::zero() / i32::MIN, Duration::zero()); - assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789)); - assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789)); - assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333)); - assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333)); - assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500)); - assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500)); - assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333)); - assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333)); - } - - #[test] - fn test_duration_fmt() { - assert_eq!(Duration::zero().to_string(), "PT0S".to_string()); - assert_eq!(Duration::days(42).to_string(), "P42D".to_string()); - assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string()); - assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string()); - assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string()); - assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string()); - assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string()); - assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(), - "P7DT6.543S".to_string()); - assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S".to_string()); - assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S".to_string()); - - // the format specifier should have no effect on `Duration` - assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)), - "P1DT2.345S".to_string()); - } -} diff --git a/src/libst2/time/mod.rs b/src/libst2/time/mod.rs deleted file mode 100644 index c920dbdc56623..0000000000000 --- a/src/libst2/time/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -// 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. - -//! Temporal quantification. - -use libc; - -pub use self::duration::Duration; - -pub mod duration; - -/// Returns the current value of a high-resolution performance counter -/// in nanoseconds since an unspecified epoch. -// NB: this is intentionally not public, this is not ready to stabilize its api. -fn precise_time_ns() -> u64 { unimplemented!() } - -#[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios")))] -mod imp { - use libc::{c_int, timespec}; - - // Apparently android provides this in some other library? - #[cfg(not(target_os = "android"))] - #[link(name = "rt")] - extern {} - - extern { - pub fn clock_gettime(clk_id: c_int, tp: *mut timespec) -> c_int; - } - -} -#[cfg(any(target_os = "macos", target_os = "ios"))] -mod imp { - use libc::{c_int, mach_timebase_info}; - - extern { - pub fn mach_absolute_time() -> u64; - pub fn mach_timebase_info(info: *mut mach_timebase_info) -> c_int; - } -} From e3921696b1f71d632ef850da164a873e56bc41c7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 13:26:29 +0100 Subject: [PATCH 63/65] a new regression test discovered during bootstrapping. --- .../trait-object-with-lifetime-bound.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/test/run-pass/trait-object-with-lifetime-bound.rs diff --git a/src/test/run-pass/trait-object-with-lifetime-bound.rs b/src/test/run-pass/trait-object-with-lifetime-bound.rs new file mode 100644 index 0000000000000..71f307387c768 --- /dev/null +++ b/src/test/run-pass/trait-object-with-lifetime-bound.rs @@ -0,0 +1,42 @@ +// 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. + +// Uncovered during work on new scoping rules for safe destructors +// as an important use case to support properly. + +pub struct E<'a> { + pub f: &'a uint, +} +impl<'b> E<'b> { + pub fn m(&self) -> &'b uint { self.f } +} + +pub struct P<'c> { + pub g: &'c uint, +} +pub trait M { + fn n(&self) -> uint; +} +impl<'d> M for P<'d> { + fn n(&self) -> uint { *self.g } +} + +fn extension<'e>(x: &'e E<'e>) -> Box { + loop { + let p = P { g: x.m() }; + return box p as Box; + } +} + +fn main() { + let w = E { f: &10u }; + let o = extension(&w); + assert_eq!(o.n(), 10u); +} From 5f07c00d16c26eea11cbd30224c00fee796e229e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 13:27:21 +0100 Subject: [PATCH 64/65] more regression tests extracted while bootstrapping. --- src/test/run-pass/regions-refcell.rs | 36 +++++++++++++++++ src/test/run-pass/regions-trait-object-1.rs | 43 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/test/run-pass/regions-refcell.rs create mode 100644 src/test/run-pass/regions-trait-object-1.rs diff --git a/src/test/run-pass/regions-refcell.rs b/src/test/run-pass/regions-refcell.rs new file mode 100644 index 0000000000000..9122d2865e061 --- /dev/null +++ b/src/test/run-pass/regions-refcell.rs @@ -0,0 +1,36 @@ +// 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. + +// This is a regression test for something that only came up while +// attempting to bootstrap librustc with new destructor lifetime +// semantics. + +use std::collections::HashMap; +use std::cell::RefCell; + +fn foo(map: RefCell>) { + // assert_eq!(map.borrow().get("one"), Some(&1u)); + let map = map.borrow(); + for (i, &x) in map.get("one").unwrap().iter().enumerate() { + assert_eq!((i, x), (0u, 1u)); + } +} + +fn main() { + let zer = [0u]; + let one = [1u]; + let two = [2u]; + let mut map = HashMap::new(); + map.insert("zero", zer.as_slice()); + map.insert("one", one.as_slice()); + map.insert("two", two.as_slice()); + let map = RefCell::new(map); + foo(map); +} diff --git a/src/test/run-pass/regions-trait-object-1.rs b/src/test/run-pass/regions-trait-object-1.rs new file mode 100644 index 0000000000000..858a0d250d6e6 --- /dev/null +++ b/src/test/run-pass/regions-trait-object-1.rs @@ -0,0 +1,43 @@ +// 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. + +// This is a regression test for something that only came up while +// attempting to bootstrap libsyntax; it is adapted from +// `syntax::ext::tt::generic_extension`. + +pub struct E<'a> { + pub f: &'a uint, +} +impl<'b> E<'b> { + pub fn m(&self) -> &'b uint { self.f } +} + +pub struct P<'c> { + pub g: &'c uint, +} +pub trait M { + fn n(&self) -> uint; +} +impl<'d> M for P<'d> { + fn n(&self) -> uint { *self.g } +} + +fn extension<'e>(x: &'e E<'e>) -> Box { + loop { + let p = P { g: x.m() }; + return box p as Box; + } +} + +fn main() { + let w = E { f: &10u }; + let o = extension(&w); + assert_eq!(o.n(), 10u); +} From 50c318ac66ffd2e3b72bd2c6cfab283680bc7ad8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 Jan 2015 13:33:13 +0100 Subject: [PATCH 65/65] placate `make tidy` --- src/librustc/middle/mem_categorization.rs | 4 +++- src/librustc/middle/typeck/check/dropck.rs | 13 ++++++++++++- src/librustc/util/ppaux.rs | 2 +- src/librustc_trans/trans/adt.rs | 13 +++++++++---- src/librustc_trans/trans/base.rs | 4 +++- src/librustc_trans/trans/common.rs | 3 ++- src/librustc_trans/trans/glue.rs | 5 +++-- 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6602c8cc95bf3..9ddc8ff0fac30 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1560,7 +1560,9 @@ fn element_kind(t: Ty) -> ElementKind { /// Returns the maximal region scope for the which the lvalue `cmt` is /// guaranteed to be valid without any rooting etc, and presuming `cmt` /// is not mutated. See the `SCOPE(LV)` function in `borrowck/doc.rs`. -pub fn scope<'tcx>(tcx: &ty::ctxt<'tcx>, cmt: &cmt<'tcx>, extent: region::CodeExtent) -> ty::Region { +pub fn scope<'tcx>(tcx: &ty::ctxt<'tcx>, + cmt: &cmt<'tcx>, + extent: region::CodeExtent) -> ty::Region { let ret = match cmt.cat { cat_rvalue(temp_scope) => temp_scope, cat_upvar(..) => ty::ReScope(extent), diff --git a/src/librustc/middle/typeck/check/dropck.rs b/src/librustc/middle/typeck/check/dropck.rs index d5d8cad320a6e..e5bba98318796 100644 --- a/src/librustc/middle/typeck/check/dropck.rs +++ b/src/librustc/middle/typeck/check/dropck.rs @@ -1,3 +1,13 @@ +// 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. + use middle::region; use middle::subst; use middle::ty; @@ -54,7 +64,8 @@ fn constrain_region_for_destructor_safety(rcx: &mut Rcx, Some(parent_inner_scope) => ty::ReScope(parent_inner_scope), }; - debug!("constrain_region_for_destructor_safety region: {} :> parent_inner_region: {} (from inner_scope: {}){}", + debug!("constrain_region_for_destructor_safety region: {} :> \ + parent_inner_region: {} (from inner_scope: {}){}", region, parent_inner_region, inner_scope, if could_have_been_re_function { " could_have_been_re_function" } else { "" }); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 31e45741f5673..b9420361cb383 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -152,7 +152,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) explain_span(cx, place, Span { lo: stmt_span.hi, ..blk.span }) } _ => { - cx.sess.bug("failed to find block for BlockRemainder") + cx.sess.bug("failed to find block for BlockRemainder") } } } diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index d3e8bfd820716..1a9a1445b8722 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -863,8 +863,11 @@ pub fn trans_field_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr< } } -pub fn struct_field_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, st: &Struct<'tcx>, val: ValueRef, - ix: uint, needs_cast: bool) -> ValueRef { +pub fn struct_field_ptr<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + st: &Struct<'tcx>, + val: ValueRef, + ix: uint, + needs_cast: bool) -> ValueRef { let val = if needs_cast { let ccx = bcx.ccx(); let fields = st.fields.iter().map(|&ty| type_of::type_of(ccx, ty)).collect::>(); @@ -918,8 +921,10 @@ pub fn fold_variants<'fcx, 'blk, 'tcx>( } /// Access the struct drop flag, if present. -pub fn trans_drop_flag_ptr<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef) - -> datum::DatumBlock<'fcx, 'blk, 'tcx, datum::Expr> { +pub fn trans_drop_flag_ptr<'fcx, 'blk, 'tcx>(mut bcx: Block<'fcx, 'blk, 'tcx>, + r: &Repr<'tcx>, + val: ValueRef) + -> datum::DatumBlock<'fcx, 'blk, 'tcx, datum::Expr> { let ptr_ty = ty::mk_imm_ptr(bcx.tcx(), ty::mk_bool()); match *r { Univariant(ref st, true) => { diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index fc28cb8b25968..1b4d148e19680 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1213,7 +1213,9 @@ fn memzero<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>) { b.call(llintrinsicfn, &[llptr, llzeroval, size, align, volatile], None); } -pub fn alloc_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef { +pub fn alloc_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + t: Ty<'tcx>, + name: &str) -> ValueRef { let _icx = push_ctxt("alloc_ty"); let ccx = bcx.ccx(); let ty = type_of::type_of(ccx, t); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index b7cffe2dc945e..5d3042df2b906 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -776,7 +776,8 @@ pub fn expr_ty<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ex: &ast::Expr) - node_id_type(bcx, ex.id) } -pub fn expr_ty_adjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, ex: &ast::Expr) -> Ty<'tcx> { +pub fn expr_ty_adjusted<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + ex: &ast::Expr) -> Ty<'tcx> { monomorphize_type(bcx, ty::expr_ty_adjusted(bcx.tcx(), ex)) } diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index cb7f90b1206f2..e3fb2529a4ee9 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -298,8 +298,9 @@ fn trans_struct_drop<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, }) } -fn size_and_align_of_dst<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef) - -> (ValueRef, ValueRef) { +fn size_and_align_of_dst<'fcx, 'blk, 'tcx>(bcx: Block<'fcx, 'blk, 'tcx>, + t: Ty<'tcx>, + info: ValueRef) -> (ValueRef, ValueRef) { debug!("calculate size of DST: {}; with lost info: {}", bcx.ty_to_string(t), bcx.val_to_string(info)); if ty::type_is_sized(bcx.tcx(), t) {